MySQL 8.0查询变慢主因是优化器“重新认识数据”时踩坑:统计信息陈旧(last_update滞后)、optimizer_switch默认启用index_merge/hash_join等新特性误判、cost_model对排序更敏感致filesort;需立即ANALYZE TABLE并建联合索引。

查询变慢不是 MySQL 8.0 更慢,而是优化器在“重新认识数据”时踩了坑——统计信息陈旧、optimizer_switch 默认值变了、sort_buffer_size 在新排序模型下更容易溢出,三者叠加导致执行计划劣化。
EXPLAIN 显示 rows 暴涨或 type 从 ref 变成 ALL 怎么办
这是最直接的信号:优化器误判了索引选择性,根源是 INNODB_TABLESTATS.last_update 还卡在升级前。
- 查表统计更新时间:
SELECT last_update FROM INFORMATION_SCHEMA.INNODB_TABLESTATS WHERE TABLE_NAME = 'your_table',若早于升级时间,必须手动刷新 - 别等
innodb_stats_auto_recalc=ON——它只对单次变更超 10% 行数的表触发,冷表/配置表永远不动 - 执行
ANALYZE TABLE your_table WITH SYNC(加WITH SYNC避免后台异步延迟) - 验证基数是否失真:
SHOW INDEX FROM your_table中的Cardinality值,对比SELECT COUNT(DISTINCT your_col) FROM your_table,差 10 倍以上就确认失效
ORDER BY 突然变慢且 EXPLAIN 出现 Using filesort
MySQL 8.0 废弃了 max_length_for_sort_data,改用全字段内存排序模型,sort_buffer_size 不够就立刻写磁盘临时文件。
- 检查是否真正走索引排序:
EXPLAIN输出中Extra列不含Using filesort才算有效 - 临时修复:给
WHERE + ORDER BY字段建复合索引,例如WHERE a=1 ORDER BY b,c就建INDEX(a,b,c) - 避免
SELECT *加剧恶化——字段越多,filesort 内存压力越大;先试SELECT a,b,c看是否恢复毫秒级 -
sort_buffer_size是 per-connection 分配的,设太大易引发内存爆炸;建议从 512K 起调,结合EXPLAIN ANALYZE观察实际排序内存使用
FORCE INDEX 失效且出现 using_index_merge
MySQL 8.0.19+ 默认开启 index_merge=on,优化器会无视你的 FORCE INDEX,转而合并多个单列索引。
- 确认是否触发:
EXPLAIN FORMAT=TREE或EXPLAIN ANALYZE输出里搜using_index_merge - 临时绕过:
IGNORE INDEX (idx_a, idx_b)把它想合并的单列索引全禁掉 - 根本解法:删掉冗余单列索引——比如已有
(a,b)复合索引,就别留(a)或(b)单列索引,减少优化器的“错误联想” - 检查当前开关:
SELECT @@optimizer_switch\G,针对性关闭测试:SET SESSION optimizer_switch='index_merge=off'
慢查询日志“变少”或解析失败
这不是性能变好,而是日志行为变了:8.0 默认只记录已提交事务的慢语句,且时间戳精度升到微秒,老工具直接无感。
- 确认是否漏记未提交事务:
SELECT @@global.log_slow_replica_statements(旧名log_slow_slave_statements),默认OFF,长事务场景建议开 - 用
pt-query-digest前先测试解析:pt-query-digest --print --no-report /var/lib/mysql/slow.log | head -20,若Time异常或Query_time为 0,说明工具版本太低(需 ≥3.5.0) - 临时兼容:启动时加
--log-slow-verbosity=standard(仅 8.0.26+ 支持),禁用微秒输出 - 别只看平均响应时间——查 p95/p99 延迟,单位是皮秒,要除以
10^12;很多问题藏在长尾里
真正容易被忽略的是:persisted_variables 优先级高于 my.cnf,如果升级前有人执行过 SET PERSIST sort_buffer_size = 64K,你改了配置文件也白搭;还有 information_schema 查询变慢往往不是 SQL 本身的问题,而是遗留的 MyISAM 表被内核“冷处理”,得转成 InnoDB 才能根治。


















