如何从已导出的.sql.gz数据库备份文件中移除无用超大表
从压缩SQL备份中剔除指定无用表的无侵入导入方案
不需要重新导出源库,不需要解压全量备份生成中间文件,也不需要逐行手动注释语句,直接通过流式过滤的方式在导入过程中跳过目标无用表的所有关联语句即可,全程磁盘开销几乎为0,也能规避之前碰到的视图创建报错问题。
具体操作步骤
- 先确认所有需要剔除的表的准确名称,包括触发
Row size too large (> 8126)报错的大表,以及确认业务完全不用、备份末尾本来就会删除的其他表,注意表名大小写要和备份文件内的写法完全一致(Linux环境下MySQL表名大小写敏感)。 - 直接执行以下过滤导入命令,把命令里的表名、路径、数据库连接信息替换成实际值:
zcat /your/path/database.sql.gz | awk ' BEGIN { # 下方括号内填入所有需要剔除的表名,格式为 skip_tables["你的表名"] = 1 skip_tables["oversize_bad_table"] = 1 skip_tables["other_unused_table_1"] = 1 skip_tables["other_unused_table_2"] = 1 in_skip = 0 } # 匹配建表、插入数据的语句块起始标记 /^-- Table structure for table/ || /^-- Dumping data for table/ { match($0, /`([^`]+)`/, res) cur_tbl = res[1] in_skip = (cur_tbl in skip_tables) ? 1 : 0 } # 匹配视图、触发器、存储过程、函数的创建语句起始 /^CREATE.*TRIGGER/ || /^CREATE.*ALGORITHM/ || /^CREATE.*PROCEDURE/ || /^CREATE.*FUNCTION/ { for (t in skip_tables) { if (index($0, "`" t "`") > 0) { in_skip = 1 if (index($0, ";") > 0) in_skip = 0 next } } } # 跳过被过滤对象的多行语句,直到遇到语句结束分号 in_skip == 1 { if (index($0, ";") > 0) in_skip = 0 next } # 其余正常语句直接输出给mysql导入 { print } ' | mysql -u {your_db_user} -p {your_target_db}
方案说明
- 整个处理过程是流式管道操作,不会把压缩包全量解压到本地磁盘,处理速度和直接用zcat导入的速度差异极小,不会额外占用大量磁盘空间。
- 过滤逻辑会自动识别目标表的建表语句、全量INSERT数据语句,从根源上避免行大小超限的报错。
- 针对之前碰到的
CREATE ALGORITHM类视图创建报错,逻辑会自动识别所有引用了被剔除表的视图、触发器、存储过程、函数,把对应完整语句直接跳过,不会出现建对象时找不到表的错误。 - 由于这些被剔除的表本身业务不会使用,且原备份末尾本来就包含这些表的删除语句,跳过全量相关语句不会导致数据不一致,也不会残留脏数据。
预校验建议
- 正式导入前可以先去掉命令末尾的mysql导入段,导出前1万行过滤结果做校验,确认过滤逻辑符合预期后再执行正式导入,校验命令参考:
zcat /your/path/database.sql.gz | awk '替换成上面的awk过滤逻辑' | head -n 10000 > filter_test.sql
- 打开
filter_test.sql确认没有目标表的相关语句即可。
内容的提问来源于stack exchange,提问作者Jack 't Jong
相关产品推荐
相关产品推荐

