出现“using join buffer (block nested loop)”表示mysql正使用块嵌套循环连接,说明join未走索引,依赖内存缓冲区匹配;需优先建索引而非盲目调大join_buffer_size。

看执行计划里有没有 Using join buffer (Block Nested Loop)
这是最直接的信号:只要 EXPLAIN 输出的 Extra 列出现这个提示,就说明 MySQL 正在用 join_buffer_size 做块嵌套循环连接。它不表示一定慢,但意味着当前 JOIN 没走索引驱动,而是靠内存缓冲区“硬扛”匹配逻辑。
常见错误现象包括:
- 两表
type都是ALL或range,且没走任何key - 即使加了
WHERE条件,rows显示扫描行数巨大(比如百万级) -
filtered值极低(如1.00或10.00),说明过滤效率差,大量中间行被缓存又丢弃
确认是否真需要调大 join_buffer_size
不是所有带 Using join buffer 的场景都该调大这个值。关键要看 JOIN 类型和驱动表选择:
- 只对
Block Nested Loop Join有效;如果是Index Nested Loop Join(type是ref/eq_ref),调它完全没用 - 仅对外层表(驱动表)小、内层表无索引的场景有意义;如果内层表已有高效索引,增大缓冲区反而浪费内存
- 多个 JOIN 表会各自分配一个 buffer,
join_buffer_size是 per-connection 的,高并发下总内存消耗 = 连接数 × 缓冲区大小
例如你有 2000 个活跃连接,设成 16M,光这部分就吃掉 32GB 内存,还没算 innodb_buffer_pool_size 和其他缓存。
怎么安全地测试合适值
别一上来就改全局配置。先定位到具体慢 SQL,再按会话级别临时调整并对比效果:
- 用
EXPLAIN FORMAT=JSON查看query_cost,记下原始值 - 执行
SET SESSION join_buffer_size = 4194304;(即 4MB),再跑EXPLAIN看rows和filtered是否改善 - 逐步试 8M、16M,观察
Rows_examined是否明显下降;一旦不再降,说明已够用 - 注意:调太大可能触发磁盘临时表(
Using temporary; Using filesort变多),反而更慢
示例中某三表 JOIN 在 join_buffer_size = 2M 时 Rows_examined = 7200w,提到 8M 后降到 1800w,再提就无效了——说明 8M 是临界点。
为什么不能只看 join_buffer_size 就动手
它只是“兜底方案”,不是性能根因。真正该优先做的永远是:
- 确保
ON列和WHERE条件列都有索引(尤其复合索引要覆盖 JOIN + 过滤) - 检查驱动表是否合理:用
STRAIGHT_JOIN强制顺序,或加/*+ JOIN_ORDER(t1,t2) */提示 - 避免
SELECT *,减少 join buffer 存储的数据量(它只存关联字段,不是整行) - 确认是否真需要 RIGHT/LEFT JOIN —— 很多 LEFT JOIN 场景其实能转成 INNER JOIN + 子查询,彻底绕过 buffer
buffer 调得再大,也救不了缺失索引的全表扫描。它解决的是“已经没索引可用了,怎么少扫几次”的问题,而不是“怎么让扫描变快”。










