大表访问卡在文件系统层,是因为ext4/XFS挂载参数不当、NFS等网络文件系统缺乏direct I/O支持或云盘未启用noatime等,导致I/O饱和(%util>90%、await>20ms),而非SQL或索引问题。

为什么大表访问会卡在文件系统层?
MySQL大表访问慢,但 EXPLAIN 显示走了索引、SHOW PROCESSLIST 看线程状态是 Sending data 或 Copying to tmp table,且磁盘 I/O 持续跑满——这时候问题大概率不在 SQL 或索引,而在底层文件系统。常见诱因包括:ext4 单文件大小限制(虽理论支持 16TB,但实际受 block size 和 inode 分配策略影响)、XFS 的 allocsize 默认值导致小写放大、NFS/CIFS 等网络文件系统缺乏 direct I/O 支持、以及某些云盘挂载时未启用 noatime 或 barrier=0。
检查文件系统是否成为瓶颈
别急着调参,先确认是不是它拖慢了:
- 用
iostat -x 1观察%util和await:若%util长期 >90% 且await>20ms,说明 I/O 设备或文件系统已饱和 - 查 MySQL 数据目录所在分区:运行
df -T /var/lib/mysql,确认是ext4还是xfs - 看内核日志有无警告:
dmesg | grep -i "ext4\|xfs\|io",重点关注 “EXT4-fs warning” 或 “XFS: possible I/O bottleneck” 类提示 - 检查挂载选项:
mount | grep mysql,留意是否含noatime、barrier=0(仅限有 UPS 的环境)、inode64(XFS 必开)
针对 ext4 和 XFS 的关键修复项
不同文件系统要动的参数差异很大,错配反而更慢:
-
ext4:确保挂载时加noatime,nodiratime,barrier=1(除非你有电池保护 RAID 卡,否则不建议关 barrier);data=ordered是安全默认,别轻易切writeback -
XFS:必须启用inode64(避免 inode 分配集中在前几个 AG),推荐加allocsize=64k(匹配 InnoDB 的innodb_page_size),挂载时加logbsize=256k提升日志吞吐 - 无论哪种,都禁用
atime:没业务真需要记录访问时间,noatime能省下大量小 I/O - 避免在 NFS 上存 InnoDB 表空间:MySQL 官方明确不支持;哪怕强制挂载,也会因锁机制和缓存一致性引发随机延迟
MySQL 配置需与文件系统对齐
光调文件系统不够,MySQL 层也要配合:
-
innodb_flush_method必须设为O_DIRECT(XFS)或O_DSYNC(ext4),禁用系统页缓存干扰;设成fdatasync(默认)在大表场景下易引发 double-buffering -
innodb_io_capacity和innodb_io_capacity_max要按实际磁盘 IOPS 设置:SSD 可设为 2000/4000,NVMe 可到 8000+;设太低会抑制预读,太高则刷脏页过猛抢 I/O - 禁用
innodb_doublewrite仅当使用带断电保护的企业级 SSD 且文件系统支持原子写(如 XFS with reflink)——普通环境别碰 - 确认
innodb_file_per_table=ON,避免单个ibdata1文件膨胀到几十 GB 后触发 ext4 的 extent 分配碎片化
文件系统层的问题最隐蔽:它不报错,只让查询变慢、抖动、偶发超时。一旦确认是它,改挂载参数或换文件系统比调 SQL 有效十倍——但切记,O_DIRECT 和 inode64 这类开关,开之前必须验证备份可恢复。


















