云数据库MySQL 8.0升级后性能反降?这四个隐形坑位在偷你的并发
先扯个真实场景。前阵子帮一个客户处理线上问题,业务量没涨,配置没动,就是从MySQL 5.7升到8.0后,原本跑得挺稳的库开始周期性抖动,慢查询日志里全是些本该走索引的小查询。查了一圈,不是锁问题,不是慢SQL本身的问题,而是8.0版本偷偷改了好几个默认行为,误导了新手甚至不少老手的调优方向。如果你是刚把业务迁到云数据库MySQL 8.0上,下面这几个坑位务必对照检查。
坑位一:TempTable引擎的磁盘溢出比你想的更早
5.7时代,临时表默认用MEMORY引擎,超过`tmp_table_size`就落盘。8.0换了默认引擎TempTable,内存上限由`temptable_max_ram`控制,默认**1GB**。看起来很美好对吧?但TempTable有一个坑:数据量超过内存上限后,**后续所有临时表操作都会直接落盘**,且落盘路径不是`/tmp`,而是`innodb_temp_tablespaces_dir`指向的InnoDB临时表空间。这意味着临时表空间文件会持续膨胀,且跟你的数据文件抢IO。 更隐蔽的是——如果你的实例内存只有4GB或8GB,而`temptable_max_ram`仍是默认的1GB,那么一个稍大的`ORDER BY`或者`GROUP BY`就可能提前触发磁盘临时表,把IO延迟瞬间拉高。在云数据库这种共享底层存储的环境下,IO抖动是致命的。 排查命令: ```sql -- 查看当前临时表内存上限 SHOW VARIABLES LIKE 'temptable_max_ram'; -- 查看临时表落盘情况 SHOW STATUS LIKE 'Temp_tables%'; -- 查看临时表空间文件大小(Linux shell执行) ls -lh /var/lib/mysql/#innodb_temp/ ``` 如果`Created_tmp_disk_tables`增长明显,建议下调`temptable_max_ram`到512MB或256MB,强制更早判断是否需要改写SQL,而不是让一个大查询慢慢吃掉内存。配合`tmp_table_size`=64MB(8.0中仅对MEMORY引擎生效)一起调,能有效减少磁盘临时表产生。# 直接生效 SET GLOBAL temptable_max_ram = 536870912; # 持久化(注意版本差异,8.0.30+支持ALTER INSTANCE方式) SET PERSIST temptable_max_ram = 536870912;
坑位二:redo log容量缩水,高写入必炸
5.7时代调`innodb_log_file_size`是常规操作,8.0.30之后这个参数被废弃,取而代之的是`innodb_redo_log_capacity`,默认**100MB**。看清楚了,是100MB,不是1GB。在SSD出现之前,redo log设太大的确恢复慢,但现在的云盘IO能力完全不是瓶颈。100MB的redo log意味着什么?就是你的InnoDB几乎每秒钟都要做一次checkpoint,把脏页刷到磁盘。刷盘一多,磁盘IO开销成倍增长。 更坑的是,这个默认值对不同IO能力的实例是“一刀切”。你在低配VPS上跑小业务也许没感觉,但在高IOPS云数据库实例上,业务一波动,`log_wait_for_flush`事件会直接飙升。碰到这个情况,新手第一反应是加大`innodb_buffer_pool_size`,其实是本末倒置——刷脏页的压力源头在redo log容量太短。 排查: ```sql SELECT @@innodb_redo_log_capacity; SHOW ENGINE INNODB STATUS\G -- 查看Log sequence number与Log flushed up to的差值 ``` 调整方式(8.0.30+):SET PERSIST innodb_redo_log_capacity = 1073741824; -- 1GB注意:如果实例已经在IO抖动中,直接`SET PERSIST`会触发一次checkpoint,可能导致短暂hang住。建议低峰期操作。这个坑在云数据库MySQL 8.0上尤其常见。我自己之前用的一款云服务就因为没关注这个参数,高峰期写放大严重,后来在轻云互联的云数据库实例上对比测试,才意识到是redo log容量设置导致的差异,调整后吞吐明显稳定了。