data_length是innodb逻辑页估算值,非磁盘实际大小,因采样统计、未回收碎片、undo/redo日志、行格式压缩及统计滞后等因素导致与物理文件差异显著。

information_schema 中的 data_length 是估算值,不是磁盘实际占用大小,直接查它快但不准——尤其是 InnoDB 表,因为 MySQL 默认只采样部分页来统计,表越大误差越明显。
为什么 data_length 和磁盘实际大小对不上
data_length 来自 information_schema.tables,本质是存储引擎(主要是 InnoDB)上报的“逻辑数据页估算量”,不包含:
- 表碎片(data_free 可能很大,但未被计入 data_length)
- undo log、redo log、临时段等非表空间文件
- 行格式变化(如 ROW_FORMAT=COMPRESSED)导致物理压缩,data_length 仍按未压缩逻辑大小报
- innodb_stats_persistent 关闭时,统计信息可能长期未更新,data_length 滞后
SELECT SUM(data_length) 能不能信
可以快速看趋势,不能用于容量规划或告警阈值判断。常见误用场景包括:
- 用 SUM(data_length + index_length) 算出 “12.4GB”,但 du -sh /var/lib/mysql/dbname/ 显示 18.7GB
- 对比主从库 data_length 差异判断同步延迟,结果误判(从库统计信息未刷新)
- 在分库分表迁移前仅依赖该值评估目标实例磁盘需求,上线后爆盘
查 data_length 的安全写法
避免除零、NULL、字符集混乱导致结果异常:
- 必须加 WHERE table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys'),否则会混入系统库干扰排序
- data_length 和 index_length 允许为 NULL,需用 IFNULL() 包裹
- 单位换算推荐统一用 / 1024 / 1024(MB),避免 1024*1024*1024 写错顺序引发溢出
- 示例(查各库总大小,含数据+索引,单位 MB):
SELECT
table_schema AS db_name,
ROUND(SUM(IFNULL(data_length, 0) + IFNULL(index_length, 0)) / 1024 / 1024, 2) AS size_mb
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
GROUP BY table_schema
ORDER BY size_mb DESC;
什么时候必须绕过 information_schema 直接看文件系统
当需要精确值时,比如:
- 迁移前校验磁盘余量是否足够
- 审计要求提供“磁盘级”存储报告
- 发现 data_free 明显偏高,怀疑存在严重碎片
- 使用了加密表空间(ENCRYPTION='Y'),data_length 不反映加密膨胀后的体积
这时得用 du -sb /var/lib/mysql/{db_name}/,注意路径要和 SHOW VARIABLES LIKE 'datadir'; 一致,且需 MySQL 用户有读权限——别忘了 .ibd 文件才是真实载体,.frm 或 .opt 可忽略。











