mysql 5.7升8.0后性能下降主因是默认行为更严格、持久化配置优先级高于my.cnf、sort_buffer_size易溢出触发磁盘filesort、innodb_buffer_pool_size被元数据额外占用,需检查persisted_variables、重估排序缓冲、补全复合索引并调优缓冲池。

MySQL 5.7 升级到 8.0 后性能下降,**大概率不是“变慢了”,而是“暴露了旧配置失效 + 新默认值不匹配”**。很多所谓“降级回 5.7 就恢复”的案例,本质是 8.0 的默认行为更严格、更真实,把原来靠隐式容忍撑住的查询打回原形。
检查 persisted_variables 是否被意外覆盖
MySQL 8.0 引入 PERSIST 机制,SET PERSIST 写入的变量会存进 mysqld-auto.cnf,重启后自动加载——但这个文件**优先级高于 my.cnf**。如果升级前有人执行过 SET PERSIST sort_buffer_size = 64K,而你升级后只改了 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 和 read_rnd_buffer_size
MySQL 8.0.20+ 彻底废弃 max_length_for_sort_data,排序策略改为全字段内存排序(rowid 排序路径被移除)。这意味着:只要 sort_buffer_size 不够装下所有排序字段总长度 × 行数,就必然触发磁盘 filesort。而 5.7 默认 sort_buffer_size = 256K,8.0 默认仍是 256K —— 但 8.0 的排序开销模型变了,同样值更容易溢出。
- 检查当前值:
SHOW VARIABLES LIKE 'sort_buffer_size'; - 估算需求数值:假设
ORDER BY a,b,c,三字段加起来平均 200 字节,要排 10 万行 → 至少需要 20MB;256K 显然不够 - 不要盲目调大:该变量是 per-connection 分配的,设成 8M 且并发 200 连接,光排序缓冲就吃掉 1.6GB 内存
- 更稳妥做法:先建复合索引覆盖排序,再把
sort_buffer_size设为 2M~4M 区间观察
innodb_buffer_pool_size 在 8.0 中的实际占用更高
8.0 的数据字典、角色权限、原子 DDL 日志等元数据全存 InnoDB,information_schema_stats_expiry 默认开启(3600 秒),导致统计信息缓存常驻 buffer pool。如果你沿用 5.7 的 innodb_buffer_pool_size = 1G,在 8.0 下可能有 15%~20% 被元数据悄悄占掉,留给业务数据的反而更少。
- 查真实使用率:
SELECT (SELECT COUNT(*) FROM information_schema.INNODB_BUFFER_PAGE) * 16384 / @@innodb_buffer_pool_size AS used_ratio; - 查元数据缓存占比:
SELECT * FROM performance_schema.memory_summary_global_by_event_name WHERE event_name LIKE 'memory%dictionary%'; - 若发现 buffer pool 命中率骤降(
Innodb_buffer_pool_hit_rateinnodb_buffer_pool_size
真正容易被忽略的点是:**8.0 的“默认值”不是静态快照,而是动态适配结果**。比如 innodb_log_file_size 在首次初始化时由 innodb_buffer_pool_size 自动推导,但升级过程不会重算——你拿到的可能是 5.7 时代遗留的小日志文件,却跑在 8.0 更激进的刷脏逻辑上,间接拖慢提交吞吐。这类问题不会报错,只会让 innodb_os_log_written 持续偏高、innodb_log_waits 缓慢爬升。











