必须用data_length+index_length之和才是表逻辑总大小,因data_length仅含聚簇索引数据,不含二级索引等,漏掉会导致低估30%–200%;查时须加table_schema、table_type='base table'、engine is not null过滤。

information_schema.TABLES 是唯一能从 SQL 层拿到每张表空间估算的入口,但直接查 DATA_LENGTH 会严重低估——它不含索引,而 InnoDB 表的索引常占 30%–200% 空间。
为什么只看 DATA_LENGTH 不行?
很多人执行 SELECT table_name, data_length FROM information_schema.tables 就以为是“表大小”,其实 DATA_LENGTH 仅反映聚簇索引中有效数据页的字节数,二级索引、主键 B+ 树非叶子节点、全文索引全在 INDEX_LENGTH 里。漏掉这部分,结果基本不可用。
-
DATA_LENGTH + INDEX_LENGTH才是逻辑总大小(单位:字节) -
DATA_FREE表示已分配但未用的空间(碎片),在innodb_file_per_table=OFF(共享表空间)时必须计入;独立表空间(默认)下可忽略,文件大小 ≈ 前两者之和 -
TABLE_ROWS是采样估算值,InnoDB 下偏差极大,别用它反推空间
查单库所有表必须加哪些过滤条件?
不加过滤会混入系统库、视图、临时表,导致结果错乱或权限报错。最简安全写法:
-
table_schema = 'your_db_name':严格匹配库名(Linux 下区分大小写) -
table_type = 'BASE TABLE':排除视图(VIEW)、分区子表、内部元数据表 -
engine IS NOT NULL:过滤掉MEMORY、CSV等无持久化存储的引擎表(它们DATA_LENGTH为 0) - 若查全局而非单库,还需加
table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
ANALYZE TABLE 什么时候必须执行?
MySQL 5.7 及更早版本默认不自动更新统计信息,首次查可能看到全 0;InnoDB 表在大量 DELETE/UPDATE 后,DATA_LENGTH 可能变小但磁盘没释放——这不是查询不准,是引擎特性。此时需手动刷新:
- 对单表:执行
ANALYZE TABLE your_table再查information_schema.TABLES - 对整库:可批量生成语句:
SELECT CONCAT('ANALYZE TABLE ', table_name, ';') FROM information_schema.tables WHERE table_schema = 'your_db_name' AND table_type = 'BASE TABLE'; - 注意:
ANALYZE TABLE会加读锁,大表慎在业务高峰执行
怎么验证 SQL 查出来的大小是不是真的?
information_schema.TABLES 提供的是逻辑估算值,不是物理磁盘真实用量。要落地验证,得绕开 SQL 层直接看文件系统:
- 独立表空间(
innodb_file_per_table=ON,默认):对应.ibd文件,用du -h /var/lib/mysql/your_db/your_table.ibd - 共享表空间(
innodb_file_per_table=OFF):所有表数据都在ibdata1,查information_schema的DATA_LENGTH完全无意义,只能看ls -lh /var/lib/mysql/ibdata1 - MyISAM 表:查
.MYD+.MYI文件总和
真正关键的不是数字本身多准,而是你是否知道这个数字代表什么、在哪失效、以及下一步该去哪验证——比如 DATA_FREE 明显偏大,就该考虑 OPTIMIZE TABLE;du 和 SQL 结果差几倍,就得立刻查表空间类型。











