查大表应优先用information_schema.tables的TABLE_ROWS估算行数,因其毫秒级响应;但InnoDB下该值为10%–20%偏差的采样估算,仅适用于快速筛查而非精确计数。

查大表为什么要用 information_schema.tables
因为直接 SELECT COUNT(*) 扫全表太慢,尤其上亿行;而 information_schema.tables 里存的是引擎统计的近似行数(TABLE_ROWS),查起来毫秒级,适合快速筛查。
注意:这个值对 InnoDB 是估算值,可能偏差 10%–20%,不能用于精确计数,但足够识别“哪个表明显比其他大”。
-
TABLE_SCHEMA是数据库名,必须加WHERE过滤,否则跨库查询极慢 -
TABLE_TYPE = 'BASE TABLE'排除视图,避免干扰 - 别信
DATA_LENGTH + INDEX_LENGTH简单相加——InnoDB表空间共享时会重复计算
怎么写高效查询语句(带排序和阈值)
目标是列出大于 1GB 的表,并按大小倒序排。关键在只查必要字段、加索引提示、避免全表扫描 information_schema。
SELECT
TABLE_SCHEMA,
TABLE_NAME,
ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024 / 1024, 2) AS size_gb,
TABLE_ROWS
FROM information_schema.tables
WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
AND TABLE_TYPE = 'BASE TABLE'
AND (DATA_LENGTH + INDEX_LENGTH) > 1024*1024*1024
ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC
LIMIT 20;
- 用
ROUND(..., 2)直接算 GB,避免客户端再处理浮点 -
TABLE_SCHEMA NOT IN (...)必须写,否则查系统库会卡住或权限报错 - MySQL 8.0+ 中
information_schema查询默认走缓存,但老版本建议加SQL_NO_CACHE防误判(不过实际影响小)
TABLE_ROWS 为什么不准?什么场景下能信
TABLE_ROWS 在 InnoDB 下是采样估算,每次 ANALYZE TABLE 后更新;MyISAM 才是精确值(但基本没人用了)。
- 如果刚大批量
DELETE或INSERT,TABLE_ROWS滞后,需手动ANALYZE TABLE db.table_name - 分区表的
TABLE_ROWS是各分区之和,但DATA_LENGTH可能包含空闲空间,导致“行数少但占空间大” - 真正要确认膨胀,得看
DATA_FREE:值大于 0 且持续增长,说明有大量删除未回收
查出来的大表,下一步该盯什么字段
光知道“大”没用,得定位膨胀来源——是数据本身多?索引太重?还是碎片高?
- 重点看
AVG_ROW_LENGTH:如果远高于业务字段总和(比如字段加起来才 200 字节,却显示 2000),大概率有大字段(TEXT/BLOB)或行溢出 - 对比
INDEX_LENGTH / DATA_LENGTH:比值 > 0.5 说明索引可能过度设计,尤其是给低区分度字段建了普通索引 -
DATA_FREE> 0 且占DATA_LENGTH10% 以上,就要考虑OPTIMIZE TABLE(但线上慎用,会锁表)
真正麻烦的不是“怎么查”,而是查完发现 DATA_LENGTH 和 TABLE_ROWS 都对不上业务预期——这时候得去翻 binlog 或应用日志,看是不是有隐式类型转换导致索引失效,进而引发全表扫描写入放大。










