不安全,除非所有文件均为纯INSERT语句且无重复DDL;直接cat合并含CREATE TABLE等语句的dump会导致“relation already exists”或语法错误。

用 cat 合并多个 SQL 转储文件是否安全?
不安全,除非你确认所有文件都是纯 INSERT 语句且无重复表结构定义。常见错误是合并后执行报错:ERROR: relation "xxx" already exists 或 syntax error at or near "CREATE" —— 因为多个 mysqldump 或 pg_dump 输出里都含 CREATE TABLE 和 SET 语句,直接拼接会冲突。
真正能安全 cat 合并的,只有两类场景:pg_dump --data-only 输出(不含 DDL),或你自己手写的、只含 INSERT 的批量数据文件。
- 检查每个文件头:运行
head -n 5 file1.sql,看是否有CREATE TABLE、BEGIN、SET等语句 - 如果含 DDL,先用
sed或awk过滤掉重复结构(比如只留第一个文件的 DDL,其余只留INSERT) - 合并前统一编码:用
file -i *.sql查编码,避免 UTF-8 和 Latin-1 混用导致导入乱码
PostgreSQL 下如何分步合并再导入?
PostgreSQL 对事务和语句顺序更敏感,不能简单 cat a.sql b.sql | psql。关键在于分离 DDL 和 DML,并控制执行顺序。
- 提取第一个文件的 DDL(含
CREATE,ALTER,COMMENT):sed -n '/^--/!{/^s*$/b; /;/!{H;d;}; x;s/ $//; s/^;//; /CREATE|ALTER|COMMENT/p; x;}' dump1.sql > schema.sql - 提取所有文件的
INSERT语句(跳过注释和空行):grep -E '^[[:space:]]*INSERT INTO' *.sql > data.sql - 导入时加
-v ON_ERROR_STOP=1防止一条错全盘跳过:psql -v ON_ERROR_STOP=1 -f schema.sql db_name && psql -v ON_ERROR_STOP=1 -f data.sql db_name
MySQL 导入多个 SQL 文件时为什么卡住或报错?
MySQL 客户端默认不支持多语句批处理中的部分失败恢复,且对大文件缓冲区敏感。典型现象是执行到一半停住、报 ERROR 2006 (HY000): MySQL server has gone away,或插入数据量远少于预期。
- 必须设置
max_allowed_packet大于最大单条INSERT体积(查看SELECT @@max_allowed_packet,建议设为 512M) - 禁用自动提交:
mysql -e "SET autocommit=0;" db_name && mysql db_name - 避免用
source在交互式客户端里加载大文件 —— 它不校验语法,容易静默失败;改用命令行重定向
有没有比 cat 更可靠的合并方式?
有,但取决于你控制不了源头还是能改导出逻辑。最稳的方式其实是绕过合并,改用程序化导入。
- 用
find *.sql -name "*.sql" -exec mysql db_name 逐个导入(注意:无事务保证,失败后需手动清理) - 写个简单 shell 循环,每导入一个文件前加日志和检查:
for f in *.sql; do echo "Importing $f"; mysql db_name - 如果文件来自不同环境(如分库导出),务必先统一
SET NAMES utf8mb4和SET FOREIGN_KEY_CHECKS=0,否则外键约束会中断导入
真正麻烦的不是合并动作本身,而是各数据库对“可执行 SQL 流”的定义不一致 —— PostgreSQL 认为带 \connect 的是合法脚本,MySQL 直接报错。别假设 cat 是通用解法,先看内容再动手。










