MySQL在SSD上变慢主因是I/O调度器未关闭、innodb_io_capacity设置不当、buffer_pool_size过大或日志参数不合理;需关调度器、按实测IOPS设io_capacity、按可用内存70%设buffer_pool_size、log_file_size设为pool_size的25%、保持sync_binlog=1和flush_log_at_trx_commit=1。

MySQL在SSD上为什么还慢?I/O调度器没关
SSD不走机械磁盘那一套,cfq或deadline调度器反而会拖后腿。Linux默认可能仍启用,导致额外延迟和随机IO放大。
- 检查当前调度器:
cat /sys/block/nvme0n1/queue/scheduler(把nvme0n1换成你的SSD设备名) - 临时切换为
none(NVMe)或noop(SATA SSD):echo none > /sys/block/nvme0n1/queue/scheduler - 永久生效需改
/etc/default/grub,在GRUB_CMDLINE_LINUX里加elevator=none,再update-grub && reboot - 注意:容器环境或云主机可能无法直接改内核参数,得看宿主机配置
innodb_io_capacity设多少才不浪费SSD带宽
innodb_io_capacity不是“越大越好”,它控制InnoDB后台刷脏页、合并插入缓冲等IO强度的上限。设太高会导致IO打满、影响查询响应;设太低又压不住脏页堆积,最终照样卡。
- 查SSD实测随机写IOPS(用
fio跑--name=randwrite --ioengine=libaio --bs=16k --iodepth=64 --runtime=60) - 生产建议值 = 实测IOPS × 0.7~0.8(留余量),例如实测120K IOPS → 设
innodb_io_capacity = 90000 -
innodb_io_capacity_max建议设为innodb_io_capacity × 2,应对突发负载 - 别照搬HDD时代的
200或1000,SSD下这个值差一个数量级,性能表现就天壤之别
innodb_buffer_pool_size调太大反而OOM?
SSD降低了IO等待,但内存压力没变。Buffer Pool占太多,系统缓存、连接线程、其他进程就容易被OOM killer干掉,尤其在小内存服务器上。
- 确认可用内存:用
free -h看available列,不是total - used - 安全上限 ≈ 可用内存 × 0.7,例如
available是30G →innodb_buffer_pool_size = 21G - 如果启用了
innodb_buffer_pool_instances > 1,记得让buffer_pool_size能被整除,否则多余内存会被丢弃 - 观察
Innodb_buffer_pool_wait_free状态变量,持续非零说明Buffer Pool太小或并发写入太猛
log_file_size和sync_binlog要不要跟着SSD改
SSD的fsync延迟低,但不代表可以无脑调大日志文件或关同步——它们影响的是崩溃恢复时间与数据安全性边界。
-
innodb_log_file_size建议总和(所有log file)设为innodb_buffer_pool_size × 0.25左右,比如Buffer Pool 21G → 总log大小≈5G(两个文件各2.5G) -
sync_binlog = 1必须保持,SSD让每次sync代价变小,但设成0意味着主从不一致风险陡增,且crash后binlog可能比redo log少一段 -
innodb_flush_log_at_trx_commit = 1也别动,除非你明确接受部分事务丢失;SSD只是让1模式更可行,不是让它失效 - 注意:调整
innodb_log_file_size需停库、删旧log、重启,不能在线改
SSD迁移后最常被忽略的,其实是buffer pool预热和redo log循环覆盖节奏的变化——冷启动后前几分钟的慢查询,往往不是配置问题,而是没等热点页载入内存,或者redo log刚切到新文件时的瞬时写放大。盯着SHOW ENGINE INNODB STATUS里的LOG和BUFFER POOL AND MEMORY段,比盲目调参有用得多。



















