MySQL 8.0性能下降主因是旧配置失效、新默认值不匹配及优化器误判,需优先检查persisted_variables、optimizer_switch变更、统计信息失真,并针对性调优sort_buffer_size与innodb_buffer_pool_size。

性能下降不是MySQL 8.0变慢了,而是旧配置失效、新默认值不匹配、优化器重新评估时“看走了眼”——直接调sort_buffer_size或innodb_buffer_pool_size往往治标不治本,得先确认谁在真正生效、哪些开关被悄悄关掉了、统计信息有没有失真。
查清persisted_variables是否锁死了你的配置
MySQL 8.0 的SET PERSIST会把变量写进mysqld-auto.cnf,该文件优先级高于my.cnf。你改了配置文件却没生效?大概率是它在覆盖。
- 查当前持久化变量:
SELECT * FROM performance_schema.persisted_variables; - 看加载来源和顺序:
SELECT VARIABLE_NAME, VARIABLE_SOURCE, VARIABLE_PATH FROM performance_schema.variables_info WHERE VARIABLE_SOURCE IN ('PERSISTED', 'CONFIG'); - 测试环境可临时清空:
RESET PERSIST;,再重启验证配置是否回归预期 - 重点盯紧:
sort_buffer_size、innodb_buffer_pool_size、optimizer_switch——这三个最常被PERSIST意外锁死
对比optimizer_switch默认值变化,避免执行计划跳变
MySQL 8.0 至少有 12 项optimizer_switch子开关默认值变了,比如mrr=off(5.7 是on)、index_merge=on(可能拼凑单列索引,绕过你建好的复合索引)。
- 升级前务必存档 baseline:
SELECT @@optimizer_switch; - 升级后比对,重点关注带
=off的项:mrr、use_index_extensions、derived_merge - 临时验证执行路径:
SET SESSION optimizer_switch='mrr=on,use_index_extensions=on';,再跑EXPLAIN - 如果
Extra出现Using intersect()或Using union(),说明index_merge在干扰,可先关掉:SET SESSION optimizer_switch='index_merge=off';
用ANALYZE TABLE刷新统计信息,防止优化器“瞎猜”行数
5.7 升 8.0 后,INNODB_TABLESTATS里的last_update时间仍停留在升级前。优化器以为某张表有 10 万行,实际才 100 行——于是放弃索引,走type: ALL。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 查失真程度:
SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESTATS WHERE TABLE_NAME = 'your_table';,再对比SHOW INDEX FROM your_table中的Cardinality与SELECT COUNT(DISTINCT your_col) FROM your_table - 立刻修复:
ANALYZE TABLE your_table;(对所有慢查询涉及的表都执行) - 长期建议开启自动更新:
SET GLOBAL information_schema_stats_expiry = 3600;(单位秒),但注意这会让元数据缓存更久,变更后需手动ANALYZE才能立即生效
重估sort_buffer_size和innodb_buffer_pool_size的实际占用
8.0 彻底废弃max_length_for_sort_data,排序策略改为全字段内存排序;同时数据字典、角色权限等元数据全存 InnoDB,会悄悄吃掉 buffer pool 空间。
-
sort_buffer_size是 per-connection 分配的:设成 8M 且并发 200 连接,光排序缓冲就吃掉 1.6GB 内存;更稳妥做法是先建复合索引覆盖ORDER BY,再把该值设为 2M~4M 区间观察 -
innodb_buffer_pool_size在 8.0 中实际可用率更低:查真实使用率:SELECT (SELECT COUNT(*) FROM information_schema.INNODB_BUFFER_PAGE WHERE PAGE_TYPE = 'INDEX') / (SELECT COUNT(*) FROM information_schema.INNODB_BUFFER_PAGE) AS index_ratio;,若低于 70%,说明元数据或其它开销占用了太多空间 - 不要盲目调大 buffer pool:先确认是否因
information_schema_stats_expiry未关闭导致统计缓存常驻,或是否有大量未使用的系统表索引在占用
最容易被忽略的是:很多“性能下降”其实发生在连接建立后第一轮查询——因为information_schema元数据访问变慢、mysql.func缺失触发兼容层兜底、甚至caching_sha2_password认证插件让客户端反复重试。这些问题不会出现在EXPLAIN里,但会拖垮整体响应。排查时别只盯着 SQL 本身,得从连接器、解析器、预处理一路往下捋。










