最可靠方法是用awk以分号为记录分隔符识别完整INSERT块:awk 'BEGIN{RS=";"; FS="\n"} /INSERT INTO / {for(i=1;i<=NF;i++) if($i ~ /INSERT INTO /) {match($i, /([^]*)`/); print substr($i, RSTART+1, RLENGTH-2)}}' backup.sql | sort | uniq -c | sort -nr

怎么看 mysqldump 备份文件里每张表占多少行
直接用 grep 数 INSERT INTO 行数不靠谱——有些 INSERT 是多行值、有些带注释、有些被分隔符截断。更稳的办法是匹配表名开头的 INSERT INTO `table_name` 模式,再按表聚合计数。
- 先用
grep -oP "INSERT INTO `\K[^`]+" backup.sql | sort | uniq -c | sort -nr提取所有被插入的表名并计频次(注意:只适用于单库备份、且表名含反引号) - 如果备份含多个库,加
-B1看前一行的USE `db_name`,或改用awk跨行状态机处理 - 别信
wc -l对整个文件跑的结果——注释、空行、DELIMITER、SET 语句全算进去了,偏差极大
用 awk 统计每张表的 INSERT 数据行数(含跨行 INSERT)
真正可靠的统计必须识别 INSERT 块边界:INSERT INTO 开头 + 分号结尾,中间可能换行。用 awk 的记录分隔符(RS)设为 ;,再逐块匹配,比逐行 grep 准确得多。
- 执行:
awk 'BEGIN{RS=";"; FS="\n"} /INSERT INTO `/ {for(i=1;i - 关键点:把分号当行结束符,避免 INSERT 多值跨行导致漏匹配
- 性能注意:大备份(>1GB)时
awk可能吃内存,可先用head -n 1000000试跑逻辑,再全量执行
为什么不能只看 .sql 文件大小来判断表大小
文件体积 ≠ 实际数据量。一张只有 10 行但含长文本字段的表,生成的 INSERT 可能比 10 万行整型主键表还大;而 mysqldump --skip-extended-insert 会让每个 INSERT 单独一行,文件直接膨胀 3–5 倍。
-
mysqldump --compact会省略注释和多余空格,压缩率约 15–20%,但不影响 INSERT 行数统计逻辑 - 如果备份用了
--hex-blob,二进制字段转成 0x... 形式,体积翻倍,但表行数不变 - 真实数据量参考应以恢复后
SELECT COUNT(*) FROM table或information_schema.TABLES为准,.sql 文件只是中间态
遇到 /*!40101 SET */ 这类条件注释怎么过滤干净
这些 MySQL 扩展注释会被 grep 或 awk 当作普通行匹配,干扰表名提取。它们以 /*! 开头、*/ 结尾,可能跨多行,必须前置清理或跳过。
- 简单方案:先用
sed '/^\/\*![0-9]\+ /d' backup.sql > clean.sql删除单行条件注释(注意空格位置) - 复杂场景(跨行注释):用
awk '/\/\*![0-9]+ /{in_cond=1; next} /\*\//{in_cond=0; next} !in_cond'流式过滤 - 别用
grep -v直接删——它会误杀含/*!字样的真实 SQL(比如字段名或注释内容)
--skip-extended-insert ——它让每条记录独立成 INSERT,awk 按分号切分就完全失效,得切回按行匹配 + 状态机跟踪 INSERT 块起止。










