0

0

mysql如何选择合适的JOIN算法(Nested Loop、Hash Join等)

P粉602998670

P粉602998670

发布时间:2026-01-10 01:01:11

|

680人浏览过

|

来源于php中文网

原创

MySQL 8.0.18+ 默认对无索引等值连接使用 Hash Join,但需满足类型兼容、优化器估算更优等条件;有索引时仍首选 NLJ。

mysql如何选择合适的join算法(nested loop、hash join等)

MySQL 8.0.18+ 默认用哪种 JOIN 算法?

MySQL 8.0.18 起,Hash Join 成为非索引连接场景的默认算法,但前提是:被驱动表(右表)没有可用索引、且连接字段类型兼容、连接条件是等值(=),并且优化器估算其比 Block Nested-Loop Join(BNL)更优。

注意:Nested-Loop Join(NLJ)仍是索引存在时的首选——只要驱动表的每行能通过索引快速定位被驱动表匹配行,优化器几乎总选 NLJ,因为它 IO 少、延迟低。

  • Hash Join 只在 EXPLAINExtra 列中显示为 Using join buffer (hash join)
  • 若看到 Using where; Using join buffer (Block Nested Loop),说明走的是 BNL(一种带缓冲的 NLJ 变种)
  • Using join buffer(无括号说明)通常表示 BNL;而 Using index conditionUsing index 出现时,基本可判定是 NLJ

为什么有时候强制用 Hash Join 反而变慢?

Hash Join 需把被驱动表(或其连接字段 + 主键)整个加载进内存构建哈希表。一旦该表太大(比如 > 数百 MB)、或内存不足(join_buffer_size 不够),就会退化成多次磁盘分片处理,性能断崖式下跌。

典型踩坑场景:

  • 被驱动表含 TEXT/BLOB 字段,即使只 select 主键,也可能因 MySQL 内部物化逻辑导致哈希表膨胀
  • join_buffer_size 设置过小(默认仅 256KB),而实际需要数 MB —— 此时应调大,但注意它是 per-connection 的,别盲目设到 1GB+
  • 连接字段有隐式类型转换(如 INT vs VARCHAR),哈希计算前需统一类型,开销增大且可能失准
  • 非等值连接(, BETWEEN)完全不支持 Hash Join,优化器会直接忽略

如何干预 JOIN 算法选择?

MySQL 不提供 USE HASH JOIN 这类 HINT,但可通过以下方式间接引导:

FashionLabs
FashionLabs

AI服装模特、商品图,可商用,低价提升销量神器

下载
  • 删掉被驱动表上“干扰性”索引:有时一个低效的索引会让优化器误判 NLJ 成本更低,删除后反而触发 Hash Join
  • STRAIGHT_JOIN 固定驱动表顺序,再配合 FORCE INDEXIGNORE INDEX 控制是否走索引,从而影响算法路径
  • 调大 join_buffer_size(会话级即可):例如 SET SESSION join_buffer_size = 4194304;(4MB),对中等规模被驱动表提升明显
  • 检查 EXPLAIN FORMAT=TREE 输出,它会明确写出 -> Hash join-> Nested loop join,比传统 EXPLAIN 更直观

BNL 和 Simple Nested Loop 的区别在哪?

老版本 MySQL 常见的 Block Nested-Loop Join(BNL)本质是把驱动表数据分块读入 join_buffer,再批量去被驱动表做匹配,减少被驱动表扫描次数;而 Simple Nested Loop(未启用 BNL 时)是驱动表每行都单独扫一遍被驱动表,IO 放大严重。

关键控制开关是 optimizer_switch 中的 block_nested_loop 标志(默认 ON)。禁用它:

SET optimizer_switch='block_nested_loop=off';
会强制退回到 Simple Nested Loop —— 仅用于调试对比,生产环境绝不建议。

真正要关注的是:当 join_buffer_size 太小,BNL 的“块”太小,反而导致更多次被驱动表扫描;此时不如让驱动表走索引,切回 NLJ。

哈希表构建和 NLJ 的索引查找,本质上是内存换 IO 和 IO 换 CPU 的权衡,没有银弹——得看你的数据分布、内存余量、以及最痛的是延迟还是吞吐。

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

658

2023.06.20

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

244

2023.06.21

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

280

2023.07.18

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

514

2023.07.19

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

253

2023.07.25

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

386

2023.08.08

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

528

2023.08.11

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

597

2023.08.14

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

3

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MySQL 教程
MySQL 教程

共48课时 | 1.7万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 785人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号