提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
官网介绍:Hash join in MySQL 8
mysql8.0 开始引入 Hash join



下面我们使用一个例子来进行说明。
SELECT
given_name, country_name
FROM
persons JOIN countries ON persons.country_id = countries.country_id;
HashJoin一般包括两个过程,hash 表构建过程 和 基于hash 表的探测比较部分。
mysql> EXPLAIN FORMAT=tree
-> SELECT
-> given_name, country_name
-> FROM
-> persons JOIN countries ON persons.country_id = countries.country_id;
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Inner hash join (countries.country_id = persons.country_id) (cost=0.70 rows=1)
-> Table scan on countries (cost=0.35 rows=1)
-> Hash
-> Table scan on persons (cost=0.35 rows=1)
|
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
通常情况下,如果join 使用了 等值条件 (一个或多个)、并且,没有 索引可用,就会使用hash join 。(也就是说,如果存在索引,则mysql 还是会优先使用 所有查询)
我们也可以使用通过命令来关闭 hash join :
mysql> SET optimizer_switch="hash_join=off";
Query OK, 0 rows affected (0.00 sec)
mysql> EXPLAIN FORMAT=tree
-> SELECT
-> given_name, country_name
-> FROM
-> persons JOIN countries ON persons.country_id = countries.country_id;
+----------------------------------------+
| EXPLAIN |
+----------------------------------------+
|
|
+----------------------------------------+
1 row in set (0.00 sec)
选择数据量较小的表 来构建hash 表


如果作为join 的数据表数据量 都很大,无法完成缓存,则要对小表也要进行数据拆分

例如,country 表数据量很大,只能将 以A - D 开头的国家写入到 内存 hash 表中。另外,将 剩下的国家数据 写入到磁盘文件块中。
如果国家 HXX 写入到 hash 表块 HA 中。在扫描Person 表时,如果某一个人员的国家也是HXX ,则同理,会将 该调数据写入到 探测表HXX 块号中。

在这里,有两个地方需要说明: