MySQL

MySQL 8.0.18 的 hash join,救的是没索引的 JOIN

JOIN 本质上是嵌套循环:外层的驱动表每拿一行,就去被驱动表里找匹配。

  • 被驱动表的连接列有索引:每次是一次索引查找,本来就不慢。
  • 没索引:8.0.18 之前只能走 BNL,把一批驱动表的行放进 join buffer,再扫被驱动表两两比较,约 M × N 次。

hash join 分两步:

  1. 构建:把小表按连接列建一张内存哈希表。
  2. 探测:扫一遍大表,每行算哈希去表里找。

两张表各扫一遍,约 M + N。内存放不下时按哈希分片落盘,再一片片处理。

sql
EXPLAIN FORMAT=TREE SELECT * FROM o JOIN m ON m.code = o.member_code;
-- -> Inner hash join (o.member_code = m.code)
--     -> Table scan on o
--     -> Hash
--         -> Table scan on m

版本:8.0.18 只支持内连接等值,8.0.20 起外连接、半连接也用它,BNL 被删掉。只适合等值连接。

顺带一个常被误解的点:「小表驱动大表」比的是过滤后参与连接的行数,不是表的总行数。

esc