MySQL 8 容器导入 58GB SQL:别和 source 硬刚,先把恢复链路做稳

作者:Administrator 发布时间: 2026-05-01 阅读量:8

58GB SQL 文件导进容器里的 MySQL 8,看起来只是一个命令问题,实际更像一次小型恢复演练。真正会把人拖死的,不是导入慢,而是导到一半乱码、报错、中断、重复导、资源打满,最后你不知道现在数据库到底处在什么状态。

所以处理大 SQL 导入,第一原则不是“怎么最快”,而是“怎么稳、怎么能观察、怎么能恢复”。

不要用 source 和交互终端硬顶

MySQL 客户端里的 source 适合小文件、临时脚本,不适合几十 GB 的恢复任务。它是交互式执行,日志输出和终端开销会拖慢过程;更麻烦的是,很多人直接进入 MySQL 后 source file.sql,没有显式指定字符集,中文字段一旦导成乱码,后面就不是慢的问题,而是重来。

更稳的方式是用 mysql 客户端做流式导入,并明确字符集:

BASH
mysql -u root -p \ --default-character-set=utf8mb4 \ --binary-mode=1 \ --max_allowed_packet=1G \ target_db < /backup/big_dump.sql

这不是魔法,也不是多线程导入。它只是少了交互式开销,行为更可控,并且把编码、二进制模式和大包限制先说清楚。

导入前先做四个确认

大文件恢复前,先别急着敲命令。至少确认四件事:

SQL
SHOW VARIABLES LIKE 'character_set%'; SHOW VARIABLES LIKE 'max_allowed_packet'; SELECT @@sql_mode; SHOW DATABASES;

然后在宿主机确认容器资源和磁盘:

BASH
docker stats mysql8 id mysql || true df -h du -h /backup/big_dump.sql

如果数据盘空间不够、容器内存限制过低、目标库字符集不对,这时候发现还来得及。导入 40GB 之后才发现,基本就是折磨自己。

外键和唯一检查可以临时关,但要知道风险

很多导入建议都会写:关闭外键检查、唯一检查、自动提交。方向没错,但不能把它当万能加速器。

BASH
mysql -u root -p target_db -e "SET GLOBAL max_allowed_packet=1073741824;"

真正对当前会话生效的设置,最好放进导入命令里:

BASH
mysql -u root -p \ --default-character-set=utf8mb4 \ --binary-mode=1 \ --max_allowed_packet=1G \ --init-command="SET FOREIGN_KEY_CHECKS=0; SET UNIQUE_CHECKS=0; SET SQL_MODE='NO_ENGINE_SUBSTITUTION';" \ target_db < /backup/big_dump.sql

这里要讲清楚边界:关闭检查适合恢复一份结构和数据都可信的 dump,不适合导入来源不明、结构可能不一致的数据。你是在降低导入过程的校验成本,不是在提升数据质量。

顺手提一嘴,像 ComfyUI、Agent 工作台、数据库恢复演练这类环境,最好别和生产业务混在一台机器上。单独开一台干净的实验服务器,把端口、模型、数据卷和日志都隔开,出问题也好回滚。雨云这类轻量云服务器拿来做 Agent/ComfyUI/数据库演练机比较顺手,临时扩容和重装都不心疼。

给 Agent 和开发实验单独留一台干净服务器
适合跑 ComfyUI、测试数据库恢复、部署 MCP/Agent 服务,环境隔离,重装方便。
查看雨云服务器方案 →

中断以后,别盲目 sed 跳行

大 SQL 中途报错,最常见的冲动是用 sed 跳过前面若干行继续导。问题是,SQL 语句不一定一行一条,尤其是大批量 INSERT。按行切,很容易从一条语句中间开始,导入直接变成新的语法错误。

mysql -f 的作用是遇到错误继续执行。它可以用于某些“已存在对象”“单条坏数据”场景,帮助流程继续往后跑。

BASH
mysql -u root -p -f \ --default-character-set=utf8mb4 \ --binary-mode=1 \ --max_allowed_packet=1G \ target_db < /backup/big_dump.sql

但要注意,-f 不是严格意义上的断点续传。它不会聪明地理解你的业务进度,也不会保证重复 INSERT 没有副作用。如果 dump 里没有幂等设计,重复执行可能导致重复数据或大量错误。

更稳的断点方案是:

  • 如果 dump 按表拆分,找到失败表,从该表重新处理。
  • 如果使用 mysqldump,尽量在导出阶段按库/表拆文件,别把所有东西压成一个巨型 SQL。
  • 如果源库还在,优先重新导出失败表,而不是硬切 58GB 文件。
  • 如果只能继续跑,先在测试库验证 -f 后的错误类型,再决定是否用于正式库。

进度观察要独立于导入进程

导入大文件时,不要盯着终端发呆。最基本的观察有三类。

看 MySQL 正在做什么:

BASH
mysql -u root -p -e "SHOW PROCESSLIST;"

看容器资源是否打满:

BASH
docker stats mysql8

看表数量和数据量是否增长:

SQL
SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'target_db';

如果你通过宿主机监控进程 IO,也要小心容器 PID 和权限问题。比起写一段很复杂的百分比脚本,更可靠的是保留导入日志、记录开始时间、周期性采样表数量和数据目录大小。

收尾比导入更重要

导入完成后,别直接宣布恢复成功。至少做一轮收尾:

BASH
mysql -u root -p target_db -e "SET FOREIGN_KEY_CHECKS=1; SET UNIQUE_CHECKS=1; COMMIT;" mysql -u root -p target_db -e "SHOW TABLES;" mysql -u root -p target_db -e "CHECK TABLE some_important_table;"

再抽样查核心业务表:记录数、中文字段、时间字段、金额字段、外键关联、索引状态。恢复任务的验收标准不是“命令跑完”,而是“业务能读、数据没乱码、关键表完整、错误日志可解释”。

以后别再交付一个 58GB 单文件

这次能导完,不代表方案健康。真正应该沉淀的是恢复预案:导出按表拆分、压缩校验、恢复脚本、日志路径、校验 SQL、回滚方案、演练记录。

大 SQL 导入没有一条神命令。它拼的是准备、观察和可恢复性。把这套链路整明白,下次遇到 100GB、200GB,也不会从第一步就开始赌命。