直接查 information_schema.tables 的 table_rows 不准,因为它是 innodb 的估算值,误差可达10%~50%;准确行数必须用 select count(*),建议用脚本自动循环执行并单独提交,避开系统表、处理特殊字符、设置超时,结果导出为csv。

直接查 information_schema.tables 为什么不准?
因为 TABLE_ROWS 在 InnoDB 表中是估算值,SHOW TABLE STATUS 也一样——MySQL 不实时维护精确行数,尤其在有频繁 DELETE/INSERT 的表上,误差可能达 10%~50%。如果你需要审计、迁移前校验或生成报表,不能依赖这个字段。
用 SELECT COUNT(*) 逐表执行但不锁表
真正准确的行数必须走 COUNT(*),但全库几十上百张表手动写 SQL 太累,还容易漏。关键点在于:避免长事务和表级锁。InnoDB 下 COUNT(*) 走的是聚簇索引遍历,不加写锁,但会持有读视图(MVCC),所以建议在低峰期跑,且每条语句单独提交。
实操建议:
- 用存储过程或客户端脚本生成语句,例如:
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' AND table_type = 'BASE TABLE'; - 把结果导出为 SQL 文件后执行,不要用事务包裹所有
COUNT(*),否则事务过长会拖慢其他业务 - 对超大表(比如 >5000 万行),先用
EXPLAIN看是否能走覆盖索引;如果COUNT(*)执行超过 30 秒,考虑加LIMIT 1验证语句语法,再分批处理
Python 脚本自动收集并输出 CSV
比纯 SQL 更可控,还能跳过系统表、忽略视图、超时中断、记录耗时。核心是用 mysql-connector-python 或 pymysql 连接后循环执行 COUNT(*)。
注意几个坑:
-
information_schema和performance_schema表不能直接COUNT(*),会报错,需显式过滤:WHERE table_schema NOT IN ('information_schema', 'performance_schema', 'mysql') - 表名含特殊字符(如短横线、中文)时,
CONCAT拼接的 SQL 必须用反引号包裹table_name - 某些表可能被其他会话锁住(比如正在 ALTER),加上
timeout=10参数防止脚本卡死 - 结果建议写入 CSV 时用
csv.writer而非字符串拼接,避免字段含逗号或换行导致格式错乱
为什么不用 mysqldump --no-data + 行数统计?
有人想靠解析 mysqldump --no-data 输出的 CREATE TABLE 来推断大小,这是误区。dump 不包含行数信息;而 --tab 导出的文本文件虽可 wc -l,但前提是表已导出且没压缩,实际效率更低、磁盘开销更大,还引入了额外 I/O 和权限问题。
真正省事又准的方式,还是脚本驱动 COUNT(*) ——只要别忘了给大表留缓冲时间,也别把结果硬塞进一个超长事务里。











