从库延迟导致JOIN执行计划漂移,主从统计信息不同步使优化器误判表大小、选错驱动表;join_buffer_size过小加剧I/O放大;索引元数据未同步或统计陈旧致全表扫描;LEFT JOIN易触发磁盘临时表。

从库延迟导致JOIN执行计划漂移
主库和从库的统计信息不同步,会让MySQL优化器在从库上误判表大小,从而选错驱动表。比如主库中orders是小表、customers是大表,优化器自然选orders当驱动表;但从库因复制延迟,customers的行数统计可能还是旧值(比如显示只有1000行),优化器就可能反向选择它当驱动表——结果就是用大表去循环匹配小表,触发Block Nested Loop Join算法,耗时飙升。
验证方法:在从库上执行EXPLAIN,对比rows估算值和key实际使用的索引,再跟主库的EXPLAIN结果逐项比对。特别注意type列是否从ref退化成ALL或index。
只读副本的join_buffer_size默认更小
很多DBA会给从库配置更低的内存参数以节省资源,但join_buffer_size直接影响Nested Loop Join的效率。当该值太小时,驱动表每批能缓存的行数减少,被驱动表就要被反复扫描更多轮次,I/O放大明显。
- 查当前值:
SELECT @@join_buffer_size - 临时调大测试:
SET SESSION join_buffer_size = 4194304(4MB) - 若效果显著,需在从库
my.cnf中持久化配置,但注意不要超过max_heap_table_size
从库索引未及时生效或统计信息陈旧
即使你在主库加了索引,从库不会自动同步索引元数据变更的时间点——如果加索引后没做ANALYZE TABLE,从库的统计信息仍基于旧数据,优化器无法感知新索引的存在,依然走全表扫描。
常见表现:主库EXPLAIN显示type=ref且key列有值,从库却显示type=ALL,key=NULL。
解决步骤:
- 确认索引已存在:
SHOW INDEX FROM customer_balances - 强制更新统计:
ANALYZE TABLE customer_balances - 如仍无效,可尝试
OPTIMIZE TABLE customer_balances(会锁表,慎用)
LEFT JOIN在从库上更容易触发磁盘临时表
从库通常禁用query_cache,且tmp_table_size和max_heap_table_size常设得比主库保守。当LEFT JOIN结果集过大(比如左表10万行 × 右表平均2行匹配),内存不够存下中间结果,就会落盘生成MyISAM临时表,性能断崖式下跌。
检查方式:SHOW STATUS LIKE 'Created_tmp_disk_tables',执行一次查询后看该值是否+1。
临时缓解:
- 增大内存临时表上限:
SET SESSION tmp_table_size = 67108864(64MB) - 确保
max_heap_table_size≥tmp_table_size - 终极办法:在
WHERE里尽早过滤左表,比如把WHERE name = 'xxx'写在LEFT JOIN前,而不是放在最后

















