10bet网址
MySQL 8.0参考手册
相关的文档10bet官方网站 下载本手册 本手册节选

8.2.1.4哈希连接优化

从MySQL 8.0.18开始,MySQL对任何查询都使用了哈希连接,其中每个连接都有一个等连接条件,并且没有索引可以应用到任何连接条件,比如下面这个:

SELECT * FROM t1 JOIN t2 ON t1.c1=t2.c1;

当有一个或多个索引可用于单表谓词时,也可以使用散列连接。

哈希连接通常比块嵌套循环算法更快,并且在这种情况下使用哈希连接的目的是代替块嵌套循环算法(参见块嵌套循环连接算法)用于以前版本的MySQL。从MySQL 8.0.20开始,删除了对块嵌套循环的支持,服务器在以前使用块嵌套循环的地方使用了哈希连接。

在刚才展示的示例和本节其余示例中,我们假设这三个表t1t2,t3已使用以下语句创建:

创建表t1 (c1 INT, c2 INT);创建表t2 (c1 INT, c2 INT);创建表t3 (c1 INT, c2 INT);

您可以通过使用看到正在使用哈希连接解释,像这样:

mysql> EXPLAIN -> SELECT * FROM t1 -> JOIN t2 ON t1.c1=t2。c \G ***************************行  *************************** id: 1 select_type:简单的表:t1分区:空类型:所有possible_keys:零键:空key_len:零参考:空行:1过滤:100.00额外:零  *************************** 2。row *************************** id: 1 select_type: SIMPLE table: t2 partitions: NULL type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1 filtered: 100.00 Extra: Using where;使用连接缓冲区(散列连接)

(在MySQL 8.0.20之前,必须包含格式=树选项,查看是否将哈希连接用于给定的连接。)

解释分析还显示所使用的哈希连接的信息。

哈希连接也用于涉及多个连接的查询,只要每对表至少有一个连接条件是等价连接,就像下面所示的查询:

SELECT * FROM t1 JOIN t2C1 = t2。c1和t1。c2 < t2.c2) JOIN t3 ON (t2. c2)C1 = t3.c1);

在类似刚刚展示的使用内部连接的情况下,任何非等连接的额外条件都在连接执行后作为过滤器应用。(对于外部连接,如左连接、半连接和反连接,它们被打印为连接的一部分。)的输出中可以看到解释

mysql> EXPLAIN FORMAT=TREE -> SELECT * -> FROM t1 -> JOIN t2 -> ON (t1。C1 = t2。c1和t1。c2 < t2.c2) -> JOIN t3 -> ON (t2. c2)c1 = t3.c1)\G ***************************行  *************************** 解释:- >内部散列连接(t3。c1 = t1.c1) (cost=1.05 rows=1) -> t3上的表扫描(cost=0.35 rows=1) -> Hash -> Filter:(t1.c1)c2 < t2.c2) (cost=0.70 rows=1) ->内部哈希连接(t2. c2)c1 = t1.c1) (cost=0.70 rows=1) -> t2上的表扫描(cost=0.35 rows=1) -> Hash -> t1上的表扫描(cost=0.35 rows=1)

从刚刚显示的输出也可以看出,多个散列连接可以(并且正在)用于具有多个等连接条件的连接。

在MySQL 8.0.20之前,如果任何一对连接表没有至少一个等连接条件,则不能使用哈希连接,并且使用较慢的块嵌套循环算法。在MySQL 8.0.20及以后的版本中,在这种情况下使用哈希连接,如下所示:

mysql> EXPLAIN FORMAT=TREE -> SELECT * FROM t1 -> JOIN t2 ON (t1.)c1 = t2.c1) -> JOIN t3 ON (t2. c1 = t2.c1)c1 < t3.c1)\G ***************************行  *************************** 解释:- >过滤器:(t1。c1 < t3.c1) (cost=1.05 rows=1) ->内部哈希连接(no condition) (cost=1.05 rows=1) -> t3上的表扫描(cost=0.35 rows=1) -> hash ->内部哈希连接(t2. c1 =1.05 rows=1) -c1 = t1.c1) (cost=0.70 rows=1) -> t2上的表扫描(cost=0.35 rows=1) -> Hash -> t1上的表扫描(cost=0.35 rows=1)

(本节稍后将提供其他示例。)

哈希连接也应用于笛卡尔积——也就是说,当没有指定连接条件时,如下所示:

mysql> EXPLAIN FORMAT=TREE -> SELECT * -> FROM t1 -> JOIN t2 -> WHERE t1。c2 > 50\G ***************************行  *************************** 解释:- >内部散列连接(成本= 0.70 = 1行)- >表扫描t2(成本= 0.35 = 1行)- >哈希- >过滤器:(t1。(cost=0.35 rows=1)表扫描t1 (cost=0.35 rows=1)

在MySQL 8.0.20及以后版本中,为了使用散列连接,连接不再需要包含至少一个等连接条件。这意味着可以使用哈希连接优化的查询类型包括以下列表中的查询(带示例):

  • 内部non-equi-join

    mysql> EXPLAIN FORMAT=TREE SELECT * FROM t1 JOIN t2 ON t1。C1 < t2。c \G ***************************行  *************************** 解释:- >过滤器:(t1。C1 < t2。c1) (cost=4.70 rows=12) -> Inner hash join (no condition) (cost=4.70 rows=12) -> Table scan on t2 (cost=0.08 rows=6) -> Hash -> Table scan on t1 (cost=0.85 rows=6)
  • Semijoin

    mysql> EXPLAIN FORMAT=TREE SELECT * FROM t1 -> WHERE t1。c1 IN (SELECT t2;c2 FROM t2)\G ***************************;行  *************************** 解释:- >嵌套循环内连接- >过滤器:(t1。c1不是null) (cost=0.85 rows=6) -> t1上的表扫描(cost=0.85 rows=6)-> Single-row index lookup on  using  (c2=t1.c1) -> Materialize with deduplication -> Filter: (t2.c2 is not null) (cost=0.85 rows=6) -> Table scan on t2 (cost=0.85 rows=6)
  • Antijoin

    mysql> EXPLAIN FORMAT=TREE SELECT * FROM t2 -> WHERE NOT EXISTS (SELECT * FROM t1 WHERE t1.)col1 = t2.col1)\G ***************************->嵌套循环反连接-> t2上的表扫描(cost=0.85 rows=6) -> 上的单行索引查找使用 (c1=t2.c1) ->使用重复数据删除物化->过滤器:(t1. 1)c1不是null) (cost=0.85 rows=6) -> t1上的表扫描(cost=0.85 rows=6)
  • 左外连接

    mysql> EXPLAIN FORMAT=TREE SELECT * FROM t1 LEFT JOIN t2 ON t1。C1 = t2。c \G ***************************行  *************************** 解释:- >左散列连接(t2。c1 = t1.c1) (cost=3.99 rows=36) -> t1上的表扫描(cost=0.85 rows=6) -> Hash -> t2上的表扫描(cost=0.14 rows=6)
  • 右外连接(注意MySQL将所有右外连接重写为左外连接):

    mysql> EXPLAIN FORMAT=TREE SELECT * FROM t1 RIGHT JOIN t2 ON t1。C1 = t2。c \G ***************************行  *************************** 解释:- >左散列连接(t1。C1 = t2。c1) (cost=3.99 rows=36) -> Table scan on t2 (cost=0.85 rows=6) -> Hash -> Table scan on t1 (cost=0.14 rows=6)

默认情况下,MySQL 8.0.18及以后版本尽可能使用散列连接。属性之一可以控制是否使用散列连接BNL而且NO_BNL优化器提示。

(MySQL 8.0.18支持hash_join =对hash_join =了作为设置的一部分optimizer_switch服务器系统变量以及优化器提示HASH_JOINNO_HASH_JOIN.在MySQL 8.0.19及以后版本中,这些不再有任何影响。)

属性控制散列连接的内存使用情况join_buffer_size系统变量;哈希连接使用的内存不能超过这个数量。当一个哈希连接所需的内存超过可用的数量时,MySQL通过使用磁盘上的文件来处理这个问题。如果发生这种情况,您应该意识到,如果哈希连接无法装入内存,并且它创建的文件多于设置的文件,那么连接可能不会成功open_files_limit.为避免此类问题,请进行以下更改之一:

  • 增加join_buffer_size这样哈希连接就不会溢出到磁盘。

  • 增加open_files_limit

从MySQL 8.0.18开始,哈希连接的连接缓冲区是增量分配的;因此,您可以设置join_buffer_size如果没有小的查询分配大量的RAM,则会占用更高的内存,但是外部连接分配整个缓冲区。在MySQL 8.0.20及以后版本中,哈希连接也用于外部连接(包括反连接和半连接),因此这不再是一个问题。