如何通过查询InformationSchema表了解MySQL中特定表的磁盘使用量?
- 内容介绍
- 文章标签
- 相关推荐
本文共计839个文字,预计阅读时间需要4分钟。
MySQL 没有直接的 `SHOW TABLE SIZE` 命令,实际有效的办法只有查询 `INFORMATION_SCHEMA.TABLES`。这里,`DATA_LENGTH` 和 `INDEX_LENGTH` 字段加起来即为该表实际占用的磁盘字节数(不含碎片、undo log、binlog)。
注意:这个视图的数据是「采样值」,不是实时精确值——InnoDB 会定期更新统计信息,所以刚删完大量数据后,数值可能滞后几分钟。如果要强制刷新,可执行 ANALYZE TABLE table_name。
DATA_LENGTH 和 INDEX_LENGTH 分别代表什么
DATA_LENGTH 是表数据页(B+树叶子节点)占用的字节数;INDEX_LENGTH 是所有二级索引(非聚簇索引)页的字节数。主键索引已计入 DATA_LENGTH(因为 InnoDB 聚簇表数据即主键)。
- 对 MyISAM 表,
DATA_LENGTH对应.MYD文件大小,INDEX_LENGTH对应.MYI文件大小 - 对 InnoDB 表,这两个值都来自
ibdata1或独立表空间(.ibd),但不等于文件系统里.ibd的大小——因为包含空闲页、未 purge 的旧版本等 - 如果启用了
innodb_file_per_table=OFF,所有表共享系统表空间,这时TABLE_SCHEMA为mysql或information_schema的表也会显示非零值,但不能直接映射到单个文件
常用查询语句及注意事项
查当前库所有表容量(按大小倒序):
SELECT TABLE_NAME, ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS size_mb, ROUND(DATA_LENGTH / 1024 / 1024, 2) AS data_mb, ROUND(INDEX_LENGTH / 1024 / 1024, 2) AS index_mb FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC;
关键点:
- 务必加上
WHERE TABLE_SCHEMA = DATABASE(),否则会扫全实例所有库,慢且权限可能不足 - 避免用
WHERE TABLE_SCHEMA = 'xxx'硬编码,容易拼错库名或忽略大小写(Linux 下库名区分大小写) - 不要用
ROUND(... / 1024 / 1024 / 1024, 2)算 GB——小表会显示0.00,掩盖真实差异;先按 MB 看,再挑大的单独算 GB - 如果某张表
DATA_LENGTH = 0但行数不为 0,大概率是表被 TRUNCATE 过但统计未更新,执行ANALYZE TABLE即可
为什么 du -sh *.ibd 和查询结果不一致
文件系统命令看到的是 .ibd 文件大小,而 INFORMATION_SCHEMA.TABLES 显示的是「已分配并使用的页空间」。两者差值常见于:
- InnoDB 启动时预分配空间(尤其
innodb_autoextend_increment较大时) - 删除大量行后,空间未立即回收给操作系统(需
OPTIMIZE TABLE或ALTER TABLE ... ENGINE=InnoDB) - 存在未 purge 的历史版本(长事务、高
innodb_max_purge_lag) - 加密表或压缩表(
ROW_FORMAT=COMPRESSED)中,DATA_LENGTH是解压后逻辑大小,du是压缩后物理大小
线上排查磁盘爆满时,优先信 du;判断「哪些表真正在吃空间」,优先信 INFORMATION_SCHEMA 的聚合值。
本文共计839个文字,预计阅读时间需要4分钟。
MySQL 没有直接的 `SHOW TABLE SIZE` 命令,实际有效的办法只有查询 `INFORMATION_SCHEMA.TABLES`。这里,`DATA_LENGTH` 和 `INDEX_LENGTH` 字段加起来即为该表实际占用的磁盘字节数(不含碎片、undo log、binlog)。
注意:这个视图的数据是「采样值」,不是实时精确值——InnoDB 会定期更新统计信息,所以刚删完大量数据后,数值可能滞后几分钟。如果要强制刷新,可执行 ANALYZE TABLE table_name。
DATA_LENGTH 和 INDEX_LENGTH 分别代表什么
DATA_LENGTH 是表数据页(B+树叶子节点)占用的字节数;INDEX_LENGTH 是所有二级索引(非聚簇索引)页的字节数。主键索引已计入 DATA_LENGTH(因为 InnoDB 聚簇表数据即主键)。
- 对 MyISAM 表,
DATA_LENGTH对应.MYD文件大小,INDEX_LENGTH对应.MYI文件大小 - 对 InnoDB 表,这两个值都来自
ibdata1或独立表空间(.ibd),但不等于文件系统里.ibd的大小——因为包含空闲页、未 purge 的旧版本等 - 如果启用了
innodb_file_per_table=OFF,所有表共享系统表空间,这时TABLE_SCHEMA为mysql或information_schema的表也会显示非零值,但不能直接映射到单个文件
常用查询语句及注意事项
查当前库所有表容量(按大小倒序):
SELECT TABLE_NAME, ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS size_mb, ROUND(DATA_LENGTH / 1024 / 1024, 2) AS data_mb, ROUND(INDEX_LENGTH / 1024 / 1024, 2) AS index_mb FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC;
关键点:
- 务必加上
WHERE TABLE_SCHEMA = DATABASE(),否则会扫全实例所有库,慢且权限可能不足 - 避免用
WHERE TABLE_SCHEMA = 'xxx'硬编码,容易拼错库名或忽略大小写(Linux 下库名区分大小写) - 不要用
ROUND(... / 1024 / 1024 / 1024, 2)算 GB——小表会显示0.00,掩盖真实差异;先按 MB 看,再挑大的单独算 GB - 如果某张表
DATA_LENGTH = 0但行数不为 0,大概率是表被 TRUNCATE 过但统计未更新,执行ANALYZE TABLE即可
为什么 du -sh *.ibd 和查询结果不一致
文件系统命令看到的是 .ibd 文件大小,而 INFORMATION_SCHEMA.TABLES 显示的是「已分配并使用的页空间」。两者差值常见于:
- InnoDB 启动时预分配空间(尤其
innodb_autoextend_increment较大时) - 删除大量行后,空间未立即回收给操作系统(需
OPTIMIZE TABLE或ALTER TABLE ... ENGINE=InnoDB) - 存在未 purge 的历史版本(长事务、高
innodb_max_purge_lag) - 加密表或压缩表(
ROW_FORMAT=COMPRESSED)中,DATA_LENGTH是解压后逻辑大小,du是压缩后物理大小
线上排查磁盘爆满时,优先信 du;判断「哪些表真正在吃空间」,优先信 INFORMATION_SCHEMA 的聚合值。

