主从EXPLAIN结果不同源于优化器决策依据差异:统计信息陈旧、optimizer_switch不一致、read_only不限制临时表、binlog_format非ROW等导致执行计划漂移。
为什么主从上
结果不一样?
主从同步本身不保证执行计划一致——MySQL 优化器基于统计信息、索引分布、配置参数和实际数据分布做决策,而这些在主从间天然可能不同。最常见诱因是:从库没开
,或
关闭后统计信息长期未更新,导致从库用的是过期直方图或采样估算。
实操建议:
主从都设
,并确认
(5.6.6+ 默认开启,但升级或手动配置时容易漏)
检查
和
表的
字段,对比主从是否严重滞后
若业务允许,可在从库执行
强制刷新(注意:会加表级读锁,大表慎用)
下为何还卡在单线程回放?
即使开了并行复制,只要事务之间存在逻辑依赖(比如同一张表的写操作被分到不同事务但有锁等待),从库仍会退化为串行回放。更隐蔽的问题是:主库 binlog_format 不是
,或用了
模式混写,导致 GTID event 分组失效,
失去判断依据。
实操建议:
确认主库
,且所有写入(包括应用层、中间件、定时任务)都不绕过该设置
查从库状态:
中看
是否频繁出现
临时启用
(8.0.13+)可缓解乱序提交引发的阻塞,但会轻微增加延迟
从库
但还是能写进临时表?
默认不限制
表创建,也不阻止
或
这类隐式临时表操作。这类行为不会写入 binlog,但会污染从库的查询缓存、影响
的“真实”执行路径(比如优化器误判临时表大小),进而导致主从执行计划偏差。
MySQL(Linux)
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
下载
实操建议:
严格设置
(需先开
),它才真正禁止所有写操作,包括临时表
监控从库是否频繁出现
增长(用
),异常高说明有应用在从库跑分析类 SQL
应用层避免在从库执行
、
等带写副作用的语句
主从
不一致引发计划漂移
哪怕 MySQL 版本相同,
默认值也可能因编译选项或补丁版本微调而不同。比如
在主库生效、从库关闭,就可能导致主走索引合并、从走全表扫描;又或者
导致从库低估连接结果集大小,选错驱动表。
实操建议:
主从都显式设置统一值:
(8.0.22+ 支持
,否则改
并重启)
用
对比主从输出,逐项核对,尤其关注
、
、
这些影响较大的开关
上线前在从库执行
(8.0.16+)对比主库输出,比传统
更直观暴露优化器决策差异
执行计划不一致从来不是孤立现象,它背后往往是统计信息陈旧、配置项错位、或写操作逃逸了只读约束。最容易被忽略的,是那些“看起来不影响同步”的配置——比如
主从不一致,会让同样一条
在从库被迫落磁盘,触发不同的排序算法选择,最终改变执行路径。
EXPLAINinnodb_stats_persistentinnodb_stats_auto_recalcinnodb_stats_persistent = ONinnodb_stats_auto_recalc = ONinformation_schema.INNODB_TABLESTATSINNODB_INDEXSTATSlast_updateANALYZE TABLEslave_parallel_type = LOGICAL_CLOCKROWSTATEMENTLOGICAL_CLOCKbinlog_format = ROWSHOW SLAVE STATUS\GSlave_SQL_Running_StateWaiting for preceding transaction to commitslave_preserve_commit_order = ONread_only = ONread_onlyTEMPORARYCREATE TEMPORARY TABLEINSERT INTO ... SELECTEXPLAINsuper_read_only = ONread_onlyCreated_tmp_tablesSHOW GLOBAL STATUS LIKE 'Created_tmp%'SELECT ... INTO OUTFILESELECT ... INTO DUMPFILEoptimizer_switchoptimizer_switchindex_merge=oncondition_fanout_filter=offSET PERSIST optimizer_switch = 'index_merge=on,index_merge_union=on,...';PERSISTmy.cnfSELECT @@optimizer_switch;materializationsemijoinloosescanEXPLAIN FORMAT=TREEEXPLAINtmp_table_sizeGROUP BY