mysqldump 恢复与导入
导学
备份的价值在于恢复。.sql 文件拿到手后,如何安全、高效地还原到数据库?小文件直接 mysql < file.sql,大文件需要分步处理,生产环境还要考虑字符集、外键约束、触发器执行顺序等细节。
定义
恢复(Restore):将备份的 SQL 文件重新执行到 MySQL 服务器,重建数据库、表结构和数据。导入(Import):将数据文件加载到已有表结构中,通常指追加数据而非重建表。
场景一:全库恢复
当前数据状态:假设服务器刚重装,MySQL 为空,只有系统库。
SHOW DATABASES;
| Database |
|---|
| information_schema |
| mysql |
| performance_schema |
| sys |
操作语句(命令行):
mysql -u root -p < full_backup_20240115.sql
输入密码后,MySQL 逐行执行 SQL 文件中的语句。
操作后数据状态:
SHOW DATABASES;
| Database |
|---|
| company |
| information_schema |
| mysql |
| performance_schema |
| sys |
USE company;
SELECT emp_name FROM employees;
| emp_name |
|---|
| 大翔 |
| 白歌 |
结果解读:全库恢复会重建备份时存在的所有数据库、表、数据、存储过程、触发器等。如果目标服务器已有同名数据库,备份文件中的 DROP TABLE IF EXISTS 会先删除旧表,再创建新表。
场景二:单库恢复到新数据库名
操作语句:将 company 库的备份恢复到新库 company_backup。
# 方法:先创建目标库,然后过滤原 SQL 中的库名
mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS company_backup;"
# 用 sed 替换库名(仅适用于简单场景)
sed 's/`company`/`company_backup`/g' company_backup.sql | mysql -u root -p
验证:
USE company_backup;
SELECT emp_name FROM employees;
| emp_name |
|---|
| 大翔 |
| 白歌 |
结果解读:mysqldump 生成的 SQL 文件包含 USE company;,直接执行会恢复到原库名。通过 sed 替换库名是一种快捷方法,但复杂场景(存储过程、触发器、事件中有硬编码库名)可能替换不全,更稳妥的方式是用 --databases 备份时只备份数据结构,恢复前手动编辑 USE 语句。
场景三:大 SQL 文件分步恢复
问题:100GB 的 SQL 文件直接 mysql < file.sql 可能因网络中断、内存不足而失败,且失败后难以定位进度。
操作语句:
# 方法 1:用 source 命令在 mysql 客户端内执行(支持断点续传感)
mysql -u root -p
-- 在 mysql> 提示符下
SET autocommit=0;
SET unique_checks=0;
SET foreign_key_checks=0;
SOURCE /backup/full_backup.sql;
SET foreign_key_checks=1;
SET unique_checks=1;
COMMIT;
结果解读:
autocommit=0+COMMIT:将所有INSERT包裹在一个大事务中提交,比逐条提交快数倍unique_checks=0:跳过唯一性检查(恢复完再检查),加速导入foreign_key_checks=0:跳过外键检查,避免导入顺序导致的外键约束失败SOURCE在客户端内执行,比管道mysql < file更稳定,且能看到执行进度
场景四:只导入数据(表已存在)
当前数据状态:company 库的 employees 表已存在,结构正确,但数据为空。
USE company;
SELECT COUNT(*) FROM employees;
| COUNT(*) |
|---|
| 0 |
操作语句:从只含数据的 SQL 文件导入。
# 假设 employees_data.sql 是用 --no-create-info 导出的
mysql -u root -p company < employees_data.sql
操作后数据状态:
SELECT emp_name FROM employees;
| emp_name |
|---|
| 大翔 |
| 白歌 |
结果解读:--no-create-info 导出的文件只含 INSERT,不含 DROP 和 CREATE,可以直接导入已有结构的表。如果目标表已有数据,需确保 INSERT 不会触发主键冲突——可用 INSERT IGNORE 或 REPLACE 策略。
场景五:处理字符集问题
问题:备份文件是 utf8mb4,恢复时客户端字符集不对,导致中文乱码。
操作语句:
# 恢复前设置客户端字符集
mysql -u root -p --default-character-set=utf8mb4 company < backup.sql
或在 SOURCE 前执行:
SET NAMES utf8mb4;
SOURCE /backup/backup.sql;
结果解读:--default-character-set=utf8mb4 确保客户端、连接、结果集都使用 utf8mb4,避免中文在传输过程中被错误转码。恢复后验证:
SELECT emp_name, HEX(emp_name) FROM employees WHERE emp_id = 1;
大翔 的 UTF-8 十六进制应为 E5A4A7 E7BF 94(具体值取决于编码),如果显示为 3F3F(问号),说明字符集设置有误。
常见误区
| 误区 | 正解 |
|---|---|
"恢复时直接 mysql < file.sql 就行" | 小文件可以;大文件建议用 SOURCE + 关闭 autocommit/unique_checks/foreign_key_checks,速度提升数倍。 |
| "恢复不会删除现有数据" | 会。备份文件中的 DROP TABLE IF EXISTS 会删除旧表。如需保留,先编辑 SQL 文件删除 DROP 和 CREATE。 |
| "恢复时外键约束自动处理导入顺序" | 不会。如果表 A 有外键依赖表 B,但 A 的 INSERT 在 B 之前,会报错。需 SET foreign_key_checks=0; 跳过。 |
"SOURCE 和 mysql < file 完全一样" | 不完全。SOURCE 在客户端内执行,能看到进度和错误行号;管道方式错误信息可能被吞掉。 |
面试考点
Q:100GB 的 mysqldump 文件怎么快速恢复?
SET autocommit=0; SET unique_checks=0; SET foreign_key_checks=0;;2.SOURCE file.sql;;3.COMMIT;恢复约束。比默认逐条提交快 5~10 倍。如果仍太慢,考虑用LOAD DATA INFILE替代INSERT。
Q:恢复时遇到 Duplicate entry 错误怎么办?
原因:目标表已有数据,备份文件的
INSERT与现有数据主键冲突。解决:1. 先TRUNCATE清空表;2. 或编辑 SQL 文件将INSERT INTO改为INSERT IGNORE INTO;3. 或用REPLACE INTO(会覆盖现有数据)。
Q:如何只恢复备份中的某一张表?
方法 1:用
grep提取该表的DROP/CREATE/INSERT语句到新文件,再执行。方法 2:用sed删除其他表的语句。方法 3:恢复全库到新实例,再用mysqldump导出目标表。
小结
- 全库恢复:
mysql -u root -p < backup.sql - 大文件加速恢复:
SET autocommit=0; unique_checks=0; foreign_key_checks=0; SOURCE file.sql; COMMIT; - 字符集:
--default-character-set=utf8mb4或SET NAMES utf8mb4; - 恢复前确认备份文件是否包含
DROP TABLE,避免误删生产数据
下一章引子:mysqldump 是逻辑备份,适合小库和迁移;但生产环境的大库需要更快、不锁表的物理备份方案——xtrabackup。