ddl 导入必须在 dml 之前完成,否则因表或约束缺失导致 error 1146 或 1217;需分离 ddl(create table 等)与 dml(insert/copy),并校验字符集与时区一致性。
ddl 导入必须在 dml 之前完成
结构(表、索引、约束)没建好,insert 就会报 error 1146 (42s02): table 'xxx' doesn't exist 或 error 1217 (hy000): cannot delete or update a parent row: a foreign key constraint fails。这不是顺序“建议”,是 mysql / postgresql 等主流数据库的硬性执行依赖。
实操建议:
- 确认备份文件中 DDL 部分以
CREATE TABLE、ALTER TABLE ... ADD CONSTRAINT等开头,且不含INSERT、UPDATE;DML 部分只含INSERT INTO ... VALUES或COPY语句 - 用
head -n 100 backup.sql快速扫前几行,看是否以SET FOREIGN_KEY_CHECKS=0;+DROP TABLE IF EXISTS+CREATE TABLE开头 - 若 DDL 文件里混了
INSERT(常见于 mysqldump 未加--no-data或导出时没分离),必须先用脚本或sed拆开,否则恢复必断
mysqldump 分离导出时要慎用 --skip-triggers 和 --skip-routines
默认 mysqldump 会把触发器、存储过程、函数一并写进 DDL 文件,但它们不是“结构”的必需部分——有些环境禁止创建函数(如阿里云 RDS 默认禁用 log_bin_trust_function_creators),强行导入会卡在 CREATE FUNCTION 报错,导致后续 DDL 中断。
实操建议:
- 生产恢复优先用
mysqldump --no-data --skip-triggers --skip-routines db_name > schema.sql导出纯表结构 - 单独用
mysqldump --no-create-info --skip-triggers db_name > data.sql导出数据(--no-create-info确保不含 DDL) - 如果业务强依赖触发器,不要跳过,但需提前在目标库执行
SET GLOBAL log_bin_trust_function_creators = 1;(MySQL 5.7+),否则CREATE TRIGGER会因 binlog 安全限制失败
PostgreSQL 的 pg_dump 需显式控制 --section=pre-data / --section=data / --section=post-data
pg_dump 默认把所有内容混在一个文件里,靠注释标记段落(如 -- Section: pre-data),但 psql 不会自动按段落执行——它只是顺序执行。所谓“顺序恢复”,本质是人工或脚本识别段落边界后分三批导入。
实操建议:
- 导出时直接分三份:
pg_dump --section=pre-data db > pre.sql、pg_dump --section=data db > data.sql、pg_dump --section=post-data db > post.sql -
pre-data含CREATE TABLE、CREATE TYPE;post-data含CREATE INDEX、ALTER TABLE ... ADD CONSTRAINT、CREATE TRIGGER;data只有COPY或INSERT - 恢复时严格按
psql -f pre.sql→psql -f data.sql→psql -f post.sql执行;别把post.sql提前,否则外键/索引可能引用尚未填充数据的表,导致invalid page in block类错误
导入大文件时 disable keys 和 autocommit 是性能关键,但不能滥用
MySQL 下 DISABLE KEYS 只对 MyISAM 有效,InnoDB 完全忽略;而 SET autocommit=0 + 批量 COMMIT 对两者都重要。但很多人误以为关掉唯一键检查能加速导入,其实 InnoDB 唯一键校验无法跳过,关了反而让冲突延迟到 COMMIT 时报错,更难定位。
实操建议:
- MyISAM 表:导入前加
/*!40000 ALTER TABLE `tbl` DISABLE KEYS */;,导入后加/*!40000 ALTER TABLE `tbl` ENABLE KEYS */; - InnoDB 表:重点做
SET unique_checks=0(仅跳过唯一索引重复检查)、SET foreign_key_checks=0(跳过外键约束),但必须确保 DML 数据本身无冲突,否则 COMMIT 时崩 - 无论哪种引擎,都应在 DML 文件头部加
SET autocommit=0;,尾部加COMMIT;,避免每行 INSERT 都刷盘
真正容易被忽略的是字符集和时区:mysqldump 默认用 SET NAMES utf8mb4,但如果目标库 collation_server 是 utf8mb4_unicode_ci 而源库是 utf8mb4_general_ci,某些 emoji 插入会静默截断;恢复前务必核对 SHOW VARIABLES LIKE 'character_set%'; 和 SHOW VARIABLES LIKE 'time_zone';










