join_buffer_size仅在被驱动表无法走索引(type=ALL或index)且EXPLAIN显示“Using join buffer (Block Nested Loop)”时生效;若ON字段有有效索引,则走Index Nested-Loop Join,调大该参数无效。

join_buffer_size 不是“调大就快”的开关,它只在特定条件下生效——而且多数慢 JOIN 的根因根本不在这里。
确认是否真用了 Join Buffer(Using join buffer (Block Nested Loop))
不看 EXPLAIN 就调参数,等于蒙眼换轮胎。
- 必须执行
EXPLAIN FORMAT=TRADITIONAL your_sql,检查被驱动表的type列是否为ALL或index,且Extra中明确出现Using join buffer (Block Nested Loop) - 如果
key列非NULL,说明走了索引,join_buffer_size完全不参与,调它没用 -
Handler_read_next暴增(通过SHOW STATUS LIKE 'Handler_read_next'查)+Extra含该提示,才是典型 BNL 场景
为什么加了索引,join_buffer_size 还是没被用上?
不是“有 JOIN 就用”,而是“被驱动表彻底没法走索引”才退化到 BNL。
- ON 条件用了函数:比如
ON UPPER(a.name) = UPPER(b.name)→ 索引失效 → BNL 启用 - 复合索引未覆盖最左前缀:索引是
(status, category_id),但写成ON b.category_id = a.id→ 无法命中 → BNL - 字段类型不一致:a.id 是
INT,b.user_id 是VARCHAR→ 隐式转换 → 索引失效 → BNL - 统计信息过期:
ANALYZE TABLE b后优化器重估,可能改走 NLJ,join_buffer_size自然闲置
怎么设 join_buffer_size 才有效?
它是线程级变量,不是全局性能杠杆;设错比不设更危险。
- 默认值
256K在多数中等 JOIN 场景下偏低,建议单连接内设为2M–8M - 超过
32M几乎无收益,反而易触发内存分配失败或 swap,尤其在高并发下 - 绝对不要在
my.cnf全局设高——每个连接都吃几 MB,OOM 风险远大于提速 - 配合被驱动表主键递增插入(避免 MRR 失效),否则缓冲区越大,随机 IO 越密集
真正卡 JOIN 性能的,从来不是缓冲区大小
三个点没对齐,其他全是障眼法:
- 被驱动表 JOIN 字段有没有索引(且是独立索引,别指望联合索引靠后列)
- 驱动表结果集有没有被
WHERE压到合理规模(rows在EXPLAIN里不能动辄百万) - 两表 JOIN 字段类型、长度、NULL 属性是否严格一致(
SHOW CREATE TABLE对着看)
这些不动,join_buffer_size 再大也只是把全表扫描从磁盘搬到内存里多跑几趟而已。


















