information_schema.tables.table_rows不准,因其对InnoDB仅为估算值,偏差常超50%;EXPLAIN SELECT COUNT(*)的rows更准且轻量;精确统计需分批、设超时、跳过失败表。

直接查 information_schema.tables 为什么不准
很多人第一反应是查 information_schema.tables 的 table_rows 字段,但这个值对 InnoDB 表只是**估算值**,尤其在有频繁增删改、没做 ANALYZE TABLE 的库中,偏差可能高达 50% 以上。MyISAM 表倒是精确的,但现在几乎没人用 MyISAM 了。
所以别信 table_rows,真要“快速且相对准”,得换思路。
用 SELECT COUNT(*) 逐表执行的陷阱
写个脚本循环所有表跑 SELECT COUNT(*) FROM `db`.`table` 看似最准,但问题明显:
- 大表(比如上亿行)会触发全表扫描,锁等待高、IO 压力大,可能拖慢线上业务
- 如果某张表正在被 DDL(如 ALTER TABLE)占用,
COUNT(*)会被阻塞,整个统计卡住 - 没有超时控制的话,一个慢查询可能让脚本挂十几分钟
除非你明确知道所有表都很小,否则不建议裸跑 COUNT(*)。
折中方案:用 EXPLAIN + rows 快速估算
对大多数 InnoDB 表,EXPLAIN SELECT COUNT(*) FROM tbl 返回的 rows 值,比 information_schema.tables.table_rows 更贴近当前真实值——因为它是基于最新统计信息(只要近期做过 ANALYZE TABLE 或自动收集开启)。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
你可以用下面这段 SQL 生成批量 EXPLAIN 语句:
SELECT CONCAT('EXPLAIN SELECT COUNT(*) FROM `', table_schema, '`.`', table_name, '`;')
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
AND table_type = 'BASE TABLE';
然后把结果复制进 MySQL 执行,再从输出里提取 rows 列。注意:
- 确保
innodb_stats_auto_recalc = ON(MySQL 5.6.6+ 默认开启) - 如果某张表长期没更新,手动跑一次
ANALYZE TABLE `db`.`tbl` -
EXPLAIN不加锁、不扫数据页,耗时通常在毫秒级
真正要精确又不想停业务?只能分批 + 超时 + 错误跳过
如果审计或迁移场景硬性要求精确值,就得接受“慢但可控”。推荐用 shell + mysql 客户端组合,核心逻辑是:
- 用
SELECT table_schema, table_name FROM information_schema.tables拿表列表 - 对每张表执行:
mysql -e "SELECT COUNT(*) FROM \`$db\`.\`$tbl\`" --connect-timeout=10 --max-allowed-packet=128M - 捕获非零退出码(超时/锁等待/权限拒绝)并记录,继续下一张
- 把耗时 >5s 的表单独标记,后续人工确认
别指望一条 SQL 或一个命令搞定“全库精确+快+稳”——这三个目标在 MySQL 里天然互斥。最常被忽略的是:没提前检查 max_execution_time 和 wait_timeout,导致中间某张表超时后整个流程静默失败。

















