系统实践
用 SQL 查看 MySQL 数据库和表的大小
使用 information_schema.tables 分别查看 MySQL 实例、数据库和单表的数据大小、索引大小与总占用,并理解这些统计值的边界。

本文最初发布于 2018 年,只记录了如何汇总
data_length。这次迁移补上了索引大小、总占用、排序和统计值误差,并按 MySQL 8.4 文档重新核验。
MySQL 的 information_schema.tables 保存了各个数据库和表的元数据。查询容量时,最常用的两个字段是:
data_length:表数据占用的字节数。对于 InnoDB,它表示聚簇索引分配空间的近似值。index_length:索引占用的字节数。对于 InnoDB,它主要对应非聚簇索引分配空间的近似值。
因此,查看一张表的大致总占用时,通常要计算 data_length + index_length,不能只看原文使用的 data_length。

上图为本次迁移新绘制的概念示意图,用于解释容量组成,不代表 MySQL 在磁盘上的真实物理布局。
查看每个数据库的大小
下面的查询会按总占用从大到小列出业务数据库,并分别展示数据、索引和总大小:
SELECT
table_schema AS database_name,
ROUND(SUM(data_length) / 1024 / 1024, 2) AS data_mb,
ROUND(SUM(index_length) / 1024 / 1024, 2) AS index_mb,
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS total_mb
FROM information_schema.tables
WHERE table_schema NOT IN (
'information_schema',
'mysql',
'performance_schema',
'sys'
)
GROUP BY table_schema
ORDER BY total_mb DESC;
这里排除了四个 MySQL 系统数据库。如果你就是要检查整个实例的元数据占用,可以去掉 WHERE 条件。
查看指定数据库的大小
假设数据库名为 home:
SELECT
table_schema AS database_name,
ROUND(SUM(data_length) / 1024 / 1024, 2) AS data_mb,
ROUND(SUM(index_length) / 1024 / 1024, 2) AS index_mb,
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS total_mb
FROM information_schema.tables
WHERE table_schema = 'home'
GROUP BY table_schema;
数据库名是固定值时可以直接写在 SQL 中。如果名称来自外部输入,应使用参数化查询,避免字符串拼接带来的注入风险。
查看数据库中每张表的大小
排查哪个表增长最快时,逐表排序比只看数据库总量更有用:
SELECT
table_name,
engine,
table_rows,
ROUND(data_length / 1024 / 1024, 2) AS data_mb,
ROUND(index_length / 1024 / 1024, 2) AS index_mb,
ROUND((data_length + index_length) / 1024 / 1024, 2) AS total_mb
FROM information_schema.tables
WHERE table_schema = 'home'
AND table_type = 'BASE TABLE'
ORDER BY data_length + index_length DESC;
table_type = 'BASE TABLE' 用于排除视图。视图在 information_schema.tables 中也有记录,但大多数容量字段为 0 或 NULL。
查看指定表的大小
例如查看 home.members:
SELECT
table_schema,
table_name,
ROUND(data_length / 1024 / 1024, 2) AS data_mb,
ROUND(index_length / 1024 / 1024, 2) AS index_mb,
ROUND((data_length + index_length) / 1024 / 1024, 2) AS total_mb,
ROUND(data_free / 1024 / 1024, 2) AS data_free_mb
FROM information_schema.tables
WHERE table_schema = 'home'
AND table_name = 'members';
data_free 表示已分配但尚未使用的空间,但它的含义受存储引擎和表空间方式影响。使用共享表空间时,它可能反映整个表空间的空闲量,不能直接理解成这张表“可回收”的空间。
为什么结果不是磁盘文件的精确大小
这些字段是表统计信息,不是通用的磁盘计量接口。MySQL 8.4 官方文档指出:
- InnoDB 的
data_length和index_length是根据页数计算的近似分配空间。 - 表统计值可能来自缓存,默认过期时间由
information_schema_stats_expiry控制。 - InnoDB 的
table_rows也是优化器使用的估算值,不等同于精确的COUNT(*)。 - 分区表、共享表空间和不同存储引擎会让字段含义有所差异。
如果容量结果明显滞后,可以先评估在业务低峰对目标表执行:
ANALYZE TABLE home.members;
ANALYZE TABLE 会更新表统计,但它不是纯粹的无成本读取操作。执行时需要相应权限,也可能对表产生读锁和资源开销;生产环境应结合表大小、负载和变更流程安排。
容量排查不只看一个数字

上图为本次迁移新绘制的排查流程示意图。
发现数据库变大后,可以继续检查:
- 增长主要来自数据还是二级索引。
- 哪些表增长最快,是否符合业务量变化。
- 是否存在重复或长期不用的索引。
- 日志、历史记录和软删除数据是否有保留周期。
- 备份、恢复和归档时间是否仍满足目标。
- 磁盘、表空间与数据库统计之间是否存在明显差异。
information_schema.tables 很适合快速定位容量热点,但真正的容量治理还需要趋势监控、业务语义和恢复验证。
参考:MySQL 8.4 官方文档中的 INFORMATION_SCHEMA TABLES 表与 ANALYZE TABLE。

