查 information_schema.tables 不准,因其 data_length 和 index_length 仅反映逻辑页数而非真实磁盘占用;innodb 在 innodb_file_per_table=off 时所有表共用 ibdata1,无法分离单表物理尺寸;最准确方法是登录服务器执行 du -sh 查对应 .ibd 文件。

查 INFORMATION_SCHEMA.TABLES 为什么不准?
直接查 INFORMATION_SCHEMA.TABLES 里的 data_length 和 index_length,常比实际磁盘占用小很多——尤其在 InnoDB 表启用了 innodb_file_per_table=OFF 时,所有表共用 ibdata1,这些字段只反映逻辑页数,不反映真实文件大小。
真正想看“这个表占了多少磁盘”,得结合存储引擎行为和物理文件路径来判断:
- InnoDB 启用
innodb_file_per_table=ON(默认):每个表对应一个.ibd文件,文件大小 ≈ 实际占用 - InnoDB 关闭该选项:所有表数据混在
ibdata1里,TABLES视图无法分离单表物理尺寸 - MyISAM 表:
.MYD+.MYI文件总和基本等于data_length + index_length
用 SELECT 查 InnoDB 表真实大小(需 innodb_file_per_table=ON)
当确认是独立表空间模式后,可以关联 INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES 和 INFORMATION_SCHEMA.TABLES 获取更接近磁盘的估算值:
SELECT
t.table_schema,
t.table_name,
ROUND(t.data_length / 1024 / 1024, 2) AS data_mb,
ROUND(t.index_length / 1024 / 1024, 2) AS index_mb,
ROUND((t.data_length + t.index_length) / 1024 / 1024, 2) AS total_mb,
ROUND(s.file_size / 1024 / 1024, 2) AS file_size_mb
FROM INFORMATION_SCHEMA.TABLES t
JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES s
ON CONCAT(t.table_schema, '/', t.table_name) = s.name
WHERE t.engine = 'InnoDB'
AND t.table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys');
注意:s.file_size 是 InnoDB 内部记录的分配大小,仍可能略大于实际 .ibd 文件(比如有未回收的空闲页),但比 data_length 更贴近磁盘。
直接看文件系统才是最准的(Linux 下)
如果能登录 MySQL 数据目录所在服务器,ls -lh 或 du -sh 是唯一 100% 可信的方式:
- 先查数据路径:
SELECT @@datadir; - 进入对应库目录:
/var/lib/mysql/your_db_name/ - 找
.ibd(InnoDB)或.MYD+.MYI(MyISAM)文件,du -sh *.ibd直接出结果 - 注意:不要用
ls -l看“大小”,而要用du -h,因为稀疏文件或预留空间可能导致ls显示偏小
SHOW TABLE STATUS 的陷阱
SHOW TABLE STATUS LIKE 'tbl_name' 返回的 Data_length 和 Index_length 字段,本质和 INFORMATION_SCHEMA.TABLES 一样,都是从内存/缓存中读取的统计快照,不是实时磁盘扫描结果。
常见误判场景:
- 刚执行过
OPTIMIZE TABLE,但没等 InnoDB 刷脏页到磁盘,SHOW结果可能还没更新 - 表有大量长事务未提交,
data_length会包含被标记为“可复用”但尚未清理的页 - 分区表:
SHOW只显示主分区统计,不自动聚合所有分区
所以它适合快速粗略评估,不能用于容量规划或释放空间验证。
真要确认某张表到底占多少磁盘,别绕弯子——进服务器,du -sh 对应 .ibd 文件。其他所有 SQL 方式,都只是估算。











