查 information_schema.tables 的 table_rows 字段不可靠,因 innodb 表仅为估算值,偏差可能超 50%;myisam 虽准确但已极少使用。

直接查 information_schema.tables 不可靠
很多人第一反应是查 information_schema.tables 里的 table_rows 字段,但这个值对 InnoDB 表只是**估算值**,尤其在表有频繁增删、没做 ANALYZE 或 MySQL 版本较老(如 5.7 之前)时,偏差可能达 50% 以上。MyISAM 表才准确,但如今极少用。
用 SELECT COUNT(*) 逐表执行最准,但太慢怎么办
全库几十上百张表,每张都跑 SELECT COUNT(*) FROM table_name,不仅耗时,还可能锁表(尤其未加 READ COMMITTED 隔离级别或大表无主键时)。关键不是“能不能”,而是“怎么组织执行更可控”:
- 优先在从库或低峰期执行,避免影响主库写入
- 对单表加
SQL_NO_CACHE(MySQL 5.7+ 已默认禁用查询缓存,可忽略) - 用
SELECT COUNT(*) FROM table_name USE INDEX (PRIMARY)强制走主键索引,避免全表扫描(尤其当有大字段或二级索引更宽时) - 对超大表(如 >1000 万行),先用
EXPLAIN确认执行计划是否走了索引;若没走,说明缺失主键或索引损坏,得先修复
生成批量统计 SQL 的安全写法
别手写一百条 COUNT,用 information_schema 动态拼接,但要注意过滤视图、系统表和临时表:
SELECT CONCAT('SELECT ''', table_name, ''' AS table_name, COUNT(*) AS row_count FROM `', table_schema, '`.`', table_name, '`;')
FROM information_schema.tables
WHERE table_schema = 'your_db_name'
AND table_type = 'BASE TABLE'
AND engine = 'InnoDB';
复制结果后在客户端逐条执行(别用 mysql -e 直接管道执行,出错难定位)。如果想导出到文件再执行,加 --skip-column-names -N 参数避免表头干扰。
替代方案:采样估算 + 精确补漏
对实时性要求不高的场景(如运维报表),可以折中:
- 先快速扫一遍
table_rows,标记出table_rows 的小表——这些表直接 <code>COUNT毫无压力 - 对大表,用
SELECT COUNT(*) FROM t TABLESAMPLE SYSTEM (1)(MySQL 8.0.22+ 支持)抽 1% 样本估算,再乘以 100;误差通常在 ±10% 内 - 真正需要精确值的表(比如账务相关),单独列出来重点处理
真正麻烦的从来不是语法,而是你不知道某张表有没有被 ALTER TABLE ... DISABLE KEYS 过,或者是不是分区表里某些分区已损坏——这些都会让 COUNT 结果异常或卡死。动手前,先 SHOW CREATE TABLE 看一眼结构更省时间。











