InnoDB脏页刷盘卡住表现为innodb_buffer_pool_pages_dirty持续升高,主因是innodb_io_capacity配置过低或磁盘吞吐不足;需结合SHOW STATUS、iostat及PROCESSLIST综合诊断。

查 InnoDB 的脏页刷盘是否卡住
InnoDB 会把修改先写入 buffer pool,再异步刷到磁盘;如果刷盘跟不上写入节奏,innodb_buffer_pool_pages_dirty 会持续升高,innodb_io_capacity 配置偏低或磁盘吞吐不足时尤其明显。
实操建议:
- 用
SHOW STATUS LIKE 'Innodb_buffer_pool_pages_dirty';查当前脏页数,配合SHOW STATUS LIKE 'Innodb_buffer_pool_write_requests';看写入压力 - 检查
innodb_io_capacity是否远低于磁盘随机写 IOPS(如 SATA SSD 实际约 3–5k,却配成 200) - 观察
innodb_log_waits是否非零——说明 redo log 刷盘慢,间接拖累 buffer pool 刷盘节奏 - 避免在高峰写入期执行
FLUSH TABLES WITH READ LOCK,它会强制同步刷脏页,瞬间放大 IO 压力
MyISAM 表全表扫描触发大量顺序读
MyISAM 没有 buffer pool,每次查询都直接读磁盘文件;SELECT * 或无索引 WHERE 条件扫大表时,key_reads 和 key_read_requests 比值会接近 1,说明几乎没走 key cache 缓存。
实操建议:
- 用
SHOW STATUS LIKE 'Key%';查Key_reads / Key_read_requests,高于 0.01 就说明缓存失效严重 -
key_buffer_size不是越大越好:超过物理内存 25% 可能引发 swap,反而拖慢 IO - MyISAM 的
.MYD文件是纯数据堆叠,ORDER BY或LIMIT无法跳过中间行,必须读完整块——别指望“只取前 10 行”就能省 IO - 批量插入时关闭
myisam_recover_options并设delay_key_write=ON,否则每条 INSERT 都刷索引
同一张表上 InnoDB 和 MyISAM 引擎混用的 IO 冲突
MySQL 允许同库不同表用不同引擎,但共用同一个磁盘设备时,InnoDB 的随机写 + MyISAM 的顺序读会互相干扰——前者需要低延迟响应,后者倾向吞吐优先,磁盘队列深度容易打满。
实操建议:
- 用
iostat -x 1观察%util接近 100 且await> 20ms 时,大概率是混合 IO 导致调度混乱 - 不要给 MyISAM 表加
AUTO_INCREMENT主键——它会强制每次插入都更新索引文件头,变成随机小写 - InnoDB 的
innodb_flush_method=O_DIRECT会绕过 OS cache,而 MyISAM 完全依赖 OS cache,混用时 OS 层缓存策略失效更明显 - 迁移老 MyISAM 表前,先用
mysqldump --no-create-info --skip-extended-insert导出,避免单条 INSERT 触发多次磁盘寻道
临时表和排序区溢出到磁盘引发隐式 IO
当 GROUP BY、ORDER BY 或子查询结果集超出 sort_buffer_size 或 tmp_table_size,MySQL 会把中间结果写进 /tmp 或 tmpdir 下的磁盘临时文件——这个过程不记入引擎统计,但真实消耗 IO。
实操建议:
- 监控
Created_tmp_disk_tables增速,若与Created_tmp_tables比值 > 0.1,说明排序/分组频繁落盘 -
tmp_table_size和max_heap_table_size必须设为相同值,否则以较小者为准 - 避免在
ORDER BY字段上使用函数(如ORDER BY UPPER(name)),会导致无法利用索引,强制走 filesort - SSD 上可把
tmpdir指向 RAM disk(如/dev/shm),但注意 MySQL 进程需有写权限,且重启后内容不保留
真正卡住 IO 的,往往不是单个大表,而是多个小动作叠加:一个慢查询触发 filesort、一个脏页刷盘延迟、再加一个 MyISAM 全表扫描——它们各自看都不致命,合起来就把磁盘队列堵死了。查的时候别只盯引擎层指标,iostat 和 SHOW PROCESSLIST 得交叉着看。










