如何强制SQL走性能更优的hash join

如何,强制,sql,性能,更优,hash,join · 浏览次数 : 12

小编点评

**华为云 SQL 优化问题:hashjoin 和 nestloop join 的选择** **问题:** 在某些情况下,使用 hashjoin 进行数据库连接时,可能无法获得执行性能更优的结果。 **分析:** * Hashjoin 的复杂度为 O(N),而 Nestloop join 的复杂度为 O(N^2)。 * 在 SQL 脚本中使用 hashjoin 时,通常需要关闭 Nestloop 模式,这会导致性能下降。 **解决方案:** * 在 SQL 中使用 /*+ hashjoin(a b) */ 方式来强制使用 hashjoin。 * 在会话级关闭 Nestloop 模式。 **选择最佳方案:** 在选择 hashjoin 或 Nestloop join 方式时,应考虑以下因素: * 数据类型兼容性:两种数据类型是否相互兼容? * 数据规模:大型数据集可能更适合使用 hashjoin。 * 连接性能:如果性能是关键,则可以选择使用 hashjoin。 **其他建议:** * 避免在 hashjoin 或 Nestloop join 中使用与连接条件相同的列。 * 使用索引来优化 hashjoin 或 Nestloop join。 * 在使用 hashjoin 或 Nestloop join 时,考虑使用分区或行级聚合。

正文

本文分享自华为云社区《【SQL优化】为什么有时候无法走执行性能更优的hashjoin》,作者: leapdb。

1. hash join通常优于nestloop join

通常nestloop join的复杂度是O(N方),hash join时间复杂度是O(N),所以我们一般倾向于使用hash join。
 
在SQL脚本调优过程中通常有两种方式,强制走hash join方式:

1. 在session级关闭nestloop方式,set enable_nestloop to off;

2. 在SQL中通过 /*+ hashjoin(a b) */ 方式,让a和b表走hash join;
 
CREATE DATABASE test_td WITH DBCOMPATIBILITY='td';

create table dim_day(day_code char(8));
create table dwr_rpo as select current_date - 1 as day_code; --返回了date类型

test_td=# \d+ dwr_rpo
                       Table "public.dwr_rpo"
  Column  | Type | Modifiers | Storage | Stats target | Description 
----------+------+-----------+---------+--------------+-------------
 day_code | date |           | plain   |              | 
Has OIDs: no
Distribute By: ROUND ROBIN
Location Nodes: ALL DATANODES
Options: orientation=row, compression=no

explain select *
from dwr_rpo a
left join dim_day c
on c.day_code = a.day_code;

id |                  operation                   | E-rows  | E-distinct | E-memory | E-width |   E-costs    
---+----------------------------------------------+---------+------------+----------+---------+--------------
 1 | ->  Streaming (type: GATHER)                 | 1310148 |            |          |    1694 | 279235196.70 
 2 |    ->  Nested Loop Left Join (3, 4)          | 1310148 |            | 1MB      |    1694 | 279229682.93 
 3 |       ->  Seq Scan on dwr_rpo a              | 1310148 |            | 1MB      |    1676 | 46589.16     
 4 |       ->  Materialize                        |  109575 |            | 16MB     |      22 | 3747.76      
 5 |          ->  Streaming(type: BROADCAST)      |  109575 |            | 2MB      |      22 | 3565.14      
 6 |             ->  Seq Scan on dim_day c        |   36525 |            | 1MB      |      22 | 272.75       

               Predicate Information (identified by plan id)                
-----------------------------------------------------------------------------
  2 --Nested Loop Left Join (3, 4)
        Join Filter: ((c.day_code)::timestamp without time zone = a.day_code)

mermaid-diagram-2023-09-06-114052.png

可是,以上SQL无论用哪种方式都走不上hash join。我们需要看一下,join两端的数据类型是否支持hash比较。
 
1. 为什么有时候无法走执行性能更优的hashjoin

不同数据类型计算hash函数不同,互不兼容的数据类型无法进行hash比较。

2. 为什么hashjoin秒级,nestloop需要两个小时

nestloop复杂度:131w * 10w = 1310亿

hashjoin复杂度:131w

所以两种方式性能差距很大。
 
3. 为什么有类型转换,还不能hash join

看似类型相近,但由于两端的精度,格式,有无时区等不一样,无法认为直接相等。

4. 都哪些数据类型间的join不支持hash?
select oprname,oprkind,oprcanhash,
  (select typname from pg_type where oid=oprleft) oprleft,
  (select typname from pg_type where oid=oprright) oprright 
from pg_operator 
where oprname='=' and oprcanhash='f';

 oprname | oprkind | oprcanhash |    oprleft    |   oprright    
---------+---------+------------+---------------+---------------
 =       | b       | f          | xid           | int8
 =       | b       | f          | xid32         | int4
 =       | b       | f          | tid           | tid
 =       | b       | f          | box           | box
 =       | b       | f          | path          | path
 =       | b       | f          | tinterval     | tinterval
 =       | b       | f          | money         | money
 =       | b       | f          | circle        | circle
 =       | b       | f          | lseg          | lseg
 =       | b       | f          | line          | line
 =       | b       | f          | bit           | bit
 =       | b       | f          | varbit        | varbit
 =       | b       | f          | date          | timestamp
 =       | b       | f          | date          | timestamptz
 =       | b       | f          | timestamp     | date
 =       | b       | f          | timestamptz   | date
 =       | b       | f          | timestamp     | timestamptz
 =       | b       | f          | timestamptz   | timestamp
 =       | b       | f          | tsvector      | tsvector
 =       | b       | f          | tsquery       | tsquery
 =       | b       | f          | record        | record
 =       | b       | f          | hll           | hll
 =       | b       | f          | hll_hashval   | hll_hashval
 =       | b       | f          | roaringbitmap | roaringbitmap
(24 rows)
 
主要是timestamp, timestamptz, date间互相join是无法走hash。其它数据类型不常见。
 
开发建议:join两端的数据类型尽量一致或互相兼容。
 
5. 为什么 oracle 兼容模式没有问题,td兼容模式有问题?

current_date 在TD兼容模式下为date类型;

current_date 在Oracle兼容模式下为timestamp类型;

点击关注,第一时间了解华为云新鲜技术~

 

与如何强制SQL走性能更优的hash join相似的内容:

如何强制SQL走性能更优的hash join

通常nestloop join的复杂度是O(N方),hash join时间复杂度是O(N),所以我们一般倾向于使用hash join。

一款利用人工智能将自然语言查询转换为 SQL 代码的互译工具 - SQL Translator

前言 对于后端程序员来说,编写SQL代码是日常工作中不可或缺的一部分。然而,随着数据复杂性的增加,如何高效、准确地编写SQL查询成为了新的挑战。幸运的是,SQL Translator的出现为后端程序员提供了一个强大的工具,将自然语言查询转换为精确的SQL代码,极大地提高了工作效率。 SQL Tran

一文掌握MyBatis的动态SQL使用与原理

摘要:使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。 本文分享自华为云社区《MyBatis详解 - 动态SQL使用与原理》,作者:龙哥手记 。 动态 SQL 是 MyBatis 的强大特性之一。如果你使用

小知识:SQL Monitor Report的使用

在上一篇 优化利器In-Memory开启和效果 中,提到的两个SQL对比,使用的是传统的dbms_xplan.display_cursor方式来查看执行计划,好处是文本输出的通用性强,基本信息也都有。 但如果大家参加过我们的RWP培训,就会发现O原厂强烈推荐大家使用的一个工具是 SQL Monito

MySQL的索引优化

哪些场景下MySQL会使用索引查询数据,哪些场景下MySQL不会使用索引查询数据,以及如何使用索引提示来告知查询优化器使用索引、忽略索引和强制索引索引。

驱动开发:内核解锁与强删文件

在某些时候我们的系统中会出现一些无法被正常删除的文件,如果想要强制删除则需要在驱动层面对其进行解锁后才可删掉,而所谓的解锁其实就是释放掉文件描述符(句柄表)占用,文件解锁的核心原理是通过调用`ObSetHandleAttributes`函数将特定句柄设置为可关闭状态,然后在调用`ZwClose`将其文件关闭,强制删除则是通过`ObReferenceObjectByHandle`在对象上提供相应的权

Tarjan强连通分量详解

1、简介: 在阅读下列内容之前,请务必了解 图论相关概念 中的基础部分。 强连通的定义是:有向图 G 强连通是指,G 中任意两个结点连通。 强连通分量(Strongly Connected Components,SCC)的定义是:极大的强连通子图。 这里要介绍的是如何来求强连通分量。 2、引入: 在

红袖添香,绝代妖娆,Ruby语言基础入门教程之Ruby3基础数据类型(data types)EP02

Ruby是强类型动态语言,即Ruby中一旦某一个对象被定义类型,如果不通过强制转换操作,那么它永远就是该数据类型,并且只有在Ruby解释器运行时才会检测对象数据类型,它的一切皆为对象(包括 nil 值对象),可以通过调用内置class属性来获取该对象的具体数据类型。对于 Ruby 而言,所有类型都继

编程语言常识

看图区别编程语言 什么是强类型、弱类型语言?哪种更好? 强类型语言 强类型语言是一种强制类型定义的语言,即一旦某一个变量被定义类型,如果不经强制转换,那么它永远就是该数据类型。 在强类型语言中,变量的数据类型是严格定义的,编译器或解释器会强制确保变量只能存储与其数据类型相匹配的值。 类型转换通常需要

如何使用Java + React计算个人所得税?

**前言** 在报表数据处理中,Excel公式拥有强大而多样的功能,广泛应用于各个业务领域。无论是投资收益计算、财务报表编制还是保险收益估算,Excel公式都扮演着不可或缺的角色。传统的做法是直接依赖Excel来实现复杂的业务逻辑,并生成相应的Excel文件。因此只需在预设位置输入相应参数,Exce