查表空间应使用 information_schema.tables 表,因其包含 data_length、index_length 等真实磁盘占用字段;而 schemata 仅提供估算值且不准确。

查表空间要用 INFORMATION_SCHEMA.TABLES,不是 INFORMATION_SCHEMA.SCHEMATA
很多人一上来就查 SCHEMATA,但那里只有数据库大小的估算值(DATA_LENGTH + INDEX_LENGTH 字段为空或不准),真正能拿到每张表物理尺寸的,是 TABLES 表。它包含 DATA_LENGTH、INDEX_LENGTH、DATA_FREE 等真实磁盘占用字段,前提是存储引擎支持(InnoDB 和 MyISAM 都行,Memory 表不计入)。
注意:TABLES 中的数值单位是字节,不是 MB 或 GB;且 DATA_FREE 只对 InnoDB 表有意义(表示已分配但未使用的空间,比如删除后未收缩的部分)。
统计某库所有表总空间的 SQL 要加 SUM() 并按引擎过滤
直接 SELECT * 看不到汇总结果,必须聚合。常用写法:
SELECT SUM(DATA_LENGTH) AS data_size, SUM(INDEX_LENGTH) AS index_size, SUM(DATA_LENGTH + INDEX_LENGTH) AS total_size, SUM(DATA_FREE) AS free_space FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'your_db_name' AND ENGINE IS NOT NULL;
关键点:
-
ENGINE IS NOT NULL排除视图(TABLE_TYPE = 'VIEW'的记录没有空间字段) - 如果只关心 InnoDB 表,可加
AND ENGINE = 'InnoDB' - MySQL 8.0+ 中,
INFORMATION_SCHEMA查询可能被限制为只读用户不可见部分系统表,需确认账号有PROCESS权限或使用performance_schema替代路径
DATA_LENGTH 和 INDEX_LENGTH 不等于磁盘文件大小
这两个字段反映的是存储引擎“认为”已用的数据页和索引页总量,但实际文件大小还受以下影响:
- InnoDB 表空间自动扩展时预留的空闲区(
innodb_autoextend_increment) - 临时表、undo log、change buffer 占用的空间不计入
TABLES - 压缩表(
ROW_FORMAT=COMPRESSED)下,DATA_LENGTH是解压后逻辑大小,非磁盘实际字节数 - 分区表会把每个分区单独列为一行,
SUM()仍有效,但要注意TABLE_NAME含分区名后缀
想看单表详细空间分布?补上 TABLE_ROWS 和平均行长
光看字节数不够直观,结合行数能判断是否膨胀。例如:
SELECT TABLE_NAME, ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS size_mb, TABLE_ROWS, ROUND((DATA_LENGTH + INDEX_LENGTH) / NULLIF(TABLE_ROWS, 0), 0) AS avg_row_bytes FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'your_db_name' AND ENGINE = 'InnoDB' ORDER BY size_mb DESC LIMIT 10;
这里 NULLIF(TABLE_ROWS, 0) 防止除零错误;avg_row_bytes 明显大于预期(比如 VARCHAR(500) 实际只存 20 字符却算出 300 字节),往往说明存在大量碎片或填充(PAD_CHAR_TO_FULL_LENGTH 开启时)。
真正麻烦的是那些 DATA_FREE 很大但 TABLE_ROWS 为 0 的表——大概率是删光了数据但没执行 OPTIMIZE TABLE,空间没归还给文件系统。











