mysql升级后sql变慢主因是优化器统计信息失效,需执行analyze table更新统计信息,并检查optimizer_switch、sort_buffer_size等配置变更。

不是所有 SQL 都变慢,但变慢的几乎都和优化器“重新认识数据”有关——统计信息没更新、optimizer_switch 默认值变了、cost_model 开始较真了。
EXPLAIN 显示 rows 暴涨、type 从 ref 变成 ALL 怎么办
这是最典型的信号:优化器误判了索引选择性。5.7 升级到 8.0 后,INNODB_TABLESTATS 和 INNODB_INDEXSTATS 中的 last_update 时间仍停留在升级前,导致估算严重偏离真实值。
- 查
last_update:执行SELECT last_update FROM INFORMATION_SCHEMA.INNODB_TABLESTATS WHERE TABLE_NAME = 'your_table',若早于升级时间,就是它 - 比
Cardinality:用SHOW INDEX FROM your_table查值,再对比SELECT COUNT(DISTINCT your_col) FROM your_table;差 10 倍以上基本确认失真 - 别等
innodb_stats_auto_recalc=ON自动触发——它只对单次变更超 10% 行数的表生效,冷表、配置表永远不动 - 立刻执行
ANALYZE TABLE your_table(大表加WITH SYNC强制同步)
ORDER BY 突然变慢,且 EXPLAIN 出现 Using filesort
8.0 废弃了 max_length_for_sort_data,排序策略改为全字段内存排序。只要 sort_buffer_size 不够装下所有排序字段总长度 × 行数,就必然触发磁盘 filesort。
- 检查是否命中索引排序:EXPLAIN 输出中
Extra列不含Using filesort才算真正走索引有序扫描 - 临时修复:给排序字段补全复合索引,例如
WHERE a=1 ORDER BY b,c就建INDEX(a,b,c) - 避免
SELECT *加剧恶化——字段越多,filesort内存压力越大;可先试SELECT a,b,c看是否恢复毫秒级 - 别盲目调大
sort_buffer_size:它是 per-connection 分配的,设成 8M + 并发 200 连接,光排序缓冲就吃掉 1.6GB 内存
FORCE INDEX 失效,执行计划里冒出 using_index_merge
8.0.19+ 默认开启 index_merge=on,优化器会主动把多个单列索引“合并使用”,哪怕你写了 FORCE INDEX (idx_composite),它也可能无视并改走 idx_a,idx_b 合并路径。
- 在
EXPLAIN FORMAT=TREE或EXPLAIN ANALYZE输出里搜using_index_merge即可确认 - 临时绕过:加
IGNORE INDEX (idx_a, idx_b)把它想合并的单列索引全禁掉 - 根本解法:删掉冗余单列索引——比如已有
(a,b)复合索引,就别留(a)或(b)单列索引,减少优化器的“错误联想” - 注意:如果系统里有大量监控 SQL(如查
sys.innodb_lock_waits),它们在 8.0 下可能因视图底层变更而变重,间接拖慢业务查询
慢查询日志突然“变少”或解析失败
这不是性能变好,而是日志行为变了:8.0 默认只记录已提交事务的慢语句,且时间戳精度升到微秒,老版分析工具(如 mysqldumpslow)直接无法解析。
- 检查是否漏记未提交事务:执行
SELECT @@global.log_slow_replica_statements,默认为OFF,建议显式开启 - 验证日志格式兼容性:用
pt-query-digest --print --no-report /path/to/slow.log | head -20观察时间字段是否正常;若报错Cannot parse time,需升级 Percona Toolkit 至 3.5.0+ - 临时降级兼容:启动 MySQL 时加参数
--log-slow-verbosity=standard(仅 8.0.26+ 支持),可禁用微秒输出 - 真正容易被忽略的是:
persisted_variables优先级高于my.cnf,如果有人之前执行过SET PERSIST sort_buffer_size = 64K,那你在配置文件里改的值根本没生效











