应使用 du 命令直接查看文件系统磁盘占用,而非依赖 information_schema.TABLES 或 SHOW TABLE STATUS 中的 DATA_LENGTH 等逻辑值,因其受压缩、未回收空间、系统文件(ibdata1、ibtmp1、binlog等)影响而严重失真。

查 MySQL 数据目录实际磁盘占用用 du,不是看 information_schema.TABLES
MySQL 自带的表统计(比如 information_schema.TABLES)只反映 InnoDB/BLOB 等引擎“逻辑上”声明的大小,DATA_LENGTH 和 INDEX_LENGTH 加起来往往远小于真实磁盘用量。尤其开启 innodb_file_per_table=OFF 时,所有表都挤在 ibdata1 里,逻辑大小完全失真。
真正要看磁盘占了多少,得绕过 MySQL,直接查文件系统:
-
du -sh /var/lib/mysql(Ubuntu/Debian 默认路径) -
du -sh /usr/local/var/mysql(macOS Homebrew 安装常见路径) -
du -sh /var/lib/mysql/mydb单独看某个库的目录(注意:这是物理目录,不是SHOW DATABASES的逻辑名)
加 --max-depth=1 可快速定位大库:du -sh --max-depth=1 /var/lib/mysql | sort -hr
为什么 SHOW TABLE STATUS 显示的 Data_length 和磁盘不一致
这个命令读的是存储引擎维护的元数据,不是文件系统真实字节数。常见偏差来源:
- InnoDB 表启用
ROW_FORMAT=COMPRESSED时,Data_length是压缩前估算值 - 删除大量行后未执行
OPTIMIZE TABLE,ibdata1不会自动收缩,Data_length可能变小但磁盘没释放 - 临时表、undo log、redo log 文件(
ib_logfile*,ibtmp1)完全不出现在任何 MySQL 表统计里,但占空间 - 二进制日志
binlog默认也在数据目录下(除非显式配置log_bin到别处),SHOW MASTER LOGS能看到列表,但不告诉你占多少磁盘
快速定位大表或异常增长的文件
别只盯着 .ibd 文件——InnoDB 表空间文件只是冰山一角。常用排查组合:
- 找最大的
.ibd:find /var/lib/mysql -name "*.ibd" -exec du -h {} \; | sort -hr | head -20 - 看有没有意外的大文件:
ls -lSh /var/lib/mysql | head -10(注意ibdata1,ibtmp1,mysql-bin.*) - 检查慢查询日志是否开着且没轮转:
ls -lh /var/lib/mysql/*slow*(路径取决于slow_query_log_file配置) - 确认
tmpdir是否指向数据目录:SELECT @@tmpdir;,如果返回的是/var/lib/mysql,临时排序/JOIN 产生的临时文件也会撑大目录
误删 ibdata1 或 ib_logfile* 会导致 MySQL 启动失败
这些是 InnoDB 的核心系统文件,不能像普通表文件那样直接 rm。常见错误操作:
- 看到
ibdata1几十个 GB,以为是“垃圾”,直接删掉 → 启动报错Table 'mysql.plugin' doesn't exist或直接拒绝启动 - 停库后删
ib_logfile*,再启动 → 报错InnoDB: The log sequence number in ibdata files does not match... - 用
mysqldump导出后清空数据目录再导入,却忘了ibdata1无法重建 → 导入后表存在但查不到数据
安全清理方式只有两种:彻底重装(导出 SQL + 删除整个目录 + 重装 + 导入),或对单表启用 innodb_file_per_table=ON 后逐个 OPTIMIZE TABLE 并 TRUNCATE 无用表。没有“一键瘦身”捷径。
最常被忽略的一点:MySQL 进程本身可能正在写文件(比如大事务未提交、长连接持有临时表),du 结果和 ls -l 看到的大小可能不一致——因为内核缓存或延迟写入。真要精确比对,得在低峰期停库后统计。










