mysql磁盘i/o优化核心是减少磁盘访问,关键措施包括:合理设置innodb_buffer_pool_size(60%–80%物理内存且为instances整数倍)、调整日志刷盘策略(如innodb_flush_log_at_trx_commit=2+sync_binlog=1000)、避免慢查询引发随机i/o(通过索引、覆盖索引、调大tmp_table_size)、选用raid 10与xfs文件系统,并借助iostat和innodb status定位真实瓶颈。

磁盘 I/O 是 MySQL 最常见的性能瓶颈,尤其在高并发或数据量大的场景下。优化的核心不是“让磁盘更快”,而是“让 MySQL 少碰磁盘”——通过内存缓存、日志策略调整、SQL 与表结构优化,把随机读写压到最低。
innodb_buffer_pool_size 设置不合理导致频繁刷盘
这是生产环境里最常被忽略的 I/O 根源:缓冲池太小,热数据留不住,每次查询都得去磁盘捞。
-
innodb_buffer_pool_size应设为物理内存的 60%–80%,但必须是innodb_buffer_pool_instances的整数倍(例如设了 8 个实例,就不能设 12.5G,得是 8G、16G 这样的值) - 监控命中率:
Innodb_buffer_pool_read_requests / (Innodb_buffer_pool_read_requests + Innodb_buffer_pool_reads),低于 99% 就说明缓存不够用 - 启用预加载能缓解重启后的 I/O 高峰:
innodb_buffer_pool_dump_at_shutdown = ON+innodb_buffer_pool_load_at_startup = ON - 动态调大需 MySQL 5.7+,且不能跨实例边界,比如当前是 8 实例 × 1G,就不能直接 SET 到 12G
innodb_flush_log_at_trx_commit 和 sync_binlog 组合引发写放大
默认的 innodb_flush_log_at_trx_commit = 1 + sync_binlog = 1 每次事务都要两次 fsync,对 SSD 是可承受的,但对机械盘或云盘 IOPS 限制严的环境,会直接卡住写入吞吐。
- 允许最多丢失 1 秒事务时,设为
innodb_flush_log_at_trx_commit = 2(log 写 OS cache,每秒刷盘) +sync_binlog = 1000(每千次事务刷一次 binlog) - 若使用带 BBU/FBWC 的 RAID 卡或 NVMe SSD + UPS,可考虑
innodb_flush_method = O_DIRECT,绕过 OS page cache,避免双重缓存和 swap 风险 -
innodb_log_file_size建议设为 1–2GB,太小会导致检查点过于频繁,脏页刷盘压力陡增;调整前必须停库并删除旧日志文件
慢查询触发大量随机 I/O
没索引的 WHERE、ORDER BY 或 JOIN 不是只慢一点,它会让 MySQL 把整张表拖进内存排序或建磁盘临时表,一次查询就能打满 I/O。
- 用
EXPLAIN看执行计划,重点关注type是否为ALL、是否出现Using filesort或Using temporary - 监控
Created_tmp_disk_tables,如果占Created_tmp_tables比例 >5%,说明tmp_table_size或max_heap_table_size太小,排序/聚合被迫落盘 - 覆盖索引能彻底避免回表:比如
SELECT user_id, name FROM users WHERE status=1,建INDEX(status, user_id, name)就不再读数据页 - 分区表对 I/O 优化效果有限,除非是按时间范围做冷热分离,且查询条件能精准命中分区
硬件与文件系统配置踩坑点
再好的 MySQL 配置也扛不住底层 IO 路径上的低效设计。SSD 不是插上就完事,挂载方式、IO 调度器、甚至 RAID 模式都会影响最终表现。
- 别用 RAID 5/6 做数据库存储——写惩罚严重,IOPS 折损明显;RAID 10 是更稳妥的选择
- XFS 文件系统比 ext4 更适合高并发写入,挂载时加
noatime,nodiratime,nobarrier(仅限有 UPS 或 BBU 的环境) -
iostat -x 1看r_await/w_await,若持续 >10ms(SSD)或 >20ms(NVMe),说明 IO 请求已在排队,不是 MySQL 参数问题,是硬件或队列深度瓶颈 - 云主机要注意 IOPS 配额:AWS gp3 默认 3000 IOPS,阿里云 ESSD 有 burst 模式,突发后会降速,不能只看峰值
真正难的不是调参,而是区分“是 MySQL 在等磁盘”,还是“磁盘根本没准备好被等”。IO 优化永远要从 iostat 和 SHOW ENGINE INNODB STATUS 的输出开始,而不是直接改 my.cnf。











