需用shell工具从全量备份中提取单个schema:先定位CREATE DATABASE myapp起始行,再截取至下一CREATE DATABASE前;导入前须确保库存在、去除DEFINER、过滤非目标库INSERT,并统一字符集与SQL模式。

从 mysqldump 全量备份里提取单个 schema
全量备份文件(比如 backup.sql)通常包含所有库的 CREATE DATABASE、USE、建表和插入语句。直接用 mysql 导入会还原全部库,但你只想恢复其中某一个(比如 myapp),就得先“切”出来。
关键不是靠 MySQL 自身命令,而是用 shell 工具做文本切片——mysqldump 输出有固定模式,可被精准定位。
- 确认备份文件是纯文本格式(非压缩或加密),且未启用
--skip-comments以外的干扰选项 - 检查开头是否有
CREATE DATABASE `myapp`和紧随其后的USE `myapp`;这是最可靠的锚点 - 用
sed -n '/^CREATE DATABASE `myapp`/,/^CREATE DATABASE `/p' backup.sql提取区间(注意末尾反引号后换行符必须匹配) - 更稳妥的做法是:先用
grep -n '^CREATE DATABASE `myapp`' backup.sql找起始行号,再用sed -n '123,456p' backup.sql > myapp.sql手动截取(避免跨库语句误截)
导入前必须处理的三个隐性依赖
光把 myapp 的 SQL 拿出来还不够。MySQL 不认孤立的 CREATE TABLE,它需要上下文环境。
- 备份中所有
CREATE TABLE默认带`myapp`.`table_name`这种全限定名,但如果你没提前建库,USE语句又缺失,会报错ERROR 1049 (42000): Unknown database 'myapp' - 必须确保目标实例上已存在
myapp库(哪怕空库),或在提取出的 SQL 开头手动加一行CREATE DATABASE IF NOT EXISTS `myapp`; - 若原备份含存储过程/函数/事件,它们默认绑定到数据库名,但创建时可能依赖
DEFINER用户权限;导入前得用sed 's/DEFINER=`[^`]*`@`[^`]*`//'去掉,否则可能报Access denied
跳过其他库的 INSERT 语句(防止污染)
全量备份里,INSERT 语句未必都紧跟在对应 CREATE TABLE 后面——尤其当开启 --skip-extended-insert 或使用 --tab 时,数据可能分散。更常见的是:一个库的 INSERT 被另一个库的 CREATE DATABASE 截断。
- 别信“只取
USE `myapp`到下一个USE之间”的做法——USE可能根本不存在,或被注释掉 - 安全做法是:提取完所有属于
myapp的CREATE和INSERT后,用grep -v '^INSERT INTO `[^`]*`' myapp.sql再筛一遍,只保留INSERT INTO `myapp`.开头的行 - 如果备份用了
--skip-extended-insert,单条INSERT很长,用grep -A 10000 '^INSERT INTO `myapp`.' myapp.sql | grep -B 10000 '^$' | grep -v '^$'容易漏末尾;建议改用awk按块处理
字符集与 SQL 模式不一致导致的静默失败
备份时的 character_set_server 或 sql_mode 和当前实例不同,会导致建表失败或字段截断,但错误可能藏在日志里,mysql 命令本身不报错。
- 打开备份文件,搜
SET @OLD_CHARACTER_SET_CLIENT,看开头几行是否设定了CHARACTER SET utf8mb4;如果目标库是latin1,建表会失败 - 导入前先执行
mysql -e "SET NAMES utf8mb4; SET sql_mode='STRICT_TRANS_TABLES';" -D myapp < myapp.sql,显式对齐环境 - 如果备份里有
ENGINE=InnoDB ROW_FORMAT=DYNAMIC,而目标 MySQL 版本低于 5.7.9,会提示Unknown table engine 'InnoDB'—— 实际是 ROW_FORMAT 不支持,得手动删掉该参数
真正麻烦的不是找不到某个库,而是找到后因字符集、SQL 模式、存储引擎细节不匹配,导致表结构建了一半、数据插了部分、后续查询结果错乱。这些点不会报红字,但会让恢复等于白做。










