mysql数据库误删恢复
1. 事故背景
本次事故为 MySQL 数据库 lakehouse 被误删:
sql
DROP DATABASE `lakehouse`;
后续通过 MySQL binlog 进行时间点恢复。实际定位到的误删信息如下:
- 数据库:
lakehouse - binlog 文件:
binlog.000018 - 误删时间:
2026-06-02 15:18:00 - 误删事件起始位置:
5531995 - 误删事件结束位置:
5532116
恢复原则:回放 binlog 时必须停在 DROP DATABASE 之前,即 binlog.000018:5531995 之前。
2. 第一时间处理
误删后优先做以下处理:
- 不要继续往原库写入数据。
- 不要执行
PURGE BINARY LOGS。 - 不要重启或清理 MySQL 数据目录。
- 优先确认是否开启 binlog,以及 binlog 文件是否还在。
- 恢复操作不要直接打到原库,先恢复到临时 MySQL 实例验证。
3. 检查 binlog 状态
在 MySQL 客户端执行:
sql
SHOW VARIABLES LIKE 'log_bin';
SHOW VARIABLES LIKE 'binlog_format';
SHOW VARIABLES LIKE 'datadir';
SHOW BINARY LOGS;
如果 log_bin = ON,说明有机会通过 binlog 恢复。
本次可用 binlog 文件包括:
text
binlog.000002
binlog.000003
binlog.000004
...
binlog.000018
注意:实际文件名前缀是 binlog.000018,不是 mysql-bin.000018。
4. 使用 mysqlbinlog 定位误删语句
Windows PowerShell 中先设置 MySQL 工具路径:
powershell
$MYSQL_BIN="D:\java\mysql\mysql-8.0.45-winx64\bin"
如果 mysqlbinlog 报错:
text
unknown variable 'default-character-set=utf8'
需要加 --no-defaults,并且必须放在第一个参数位置。
解析最新 binlog:
powershell
& "$MYSQL_BIN\mysqlbinlog.exe" --no-defaults --read-from-remote-server -h 192.168.1.201 -P 3306 -u root -p --base64-output=DECODE-ROWS -vv --result-file=C:\tmp\binlog_000018.txt binlog.000018
搜索误删语句:
powershell
Select-String -Path C:\tmp\binlog_000018.txt -Pattern "DROP DATABASE|DROP SCHEMA|DROP TABLE|lakehouse" -CaseSensitive:$false -Context 10,10
定位到:
text
#260602 15:18:00 server id 1 end_log_pos 5532116 Query
SET TIMESTAMP=1780384680/*!*/;
DROP DATABASE `lakehouse`
误删事件前一个位置为:
text
# at 5531995
因此恢复时应使用:
text
--stop-position=5531995
5. 没有全量备份时的恢复方式
没有全量备份时,只能尝试从现有 binlog 重放。
是否能完整恢复,取决于现有 binlog 是否包含以下内容:
CREATE DATABASE lakehouse- 所有
CREATE TABLE - 初始导入数据
- 后续所有 DML 变更
如果 binlog 不包含建库、建表或初始数据,则只能恢复部分数据。
6. 生成恢复 SQL
不要把所有 binlog 都用同一个 --stop-position 一次性生成,建议拆成两段:
- 完整回放
binlog.000002到binlog.000017 binlog.000018只回放到删库前的位置5531995
生成第一段:
powershell
& "$MYSQL_BIN\mysqlbinlog.exe" --no-defaults --read-from-remote-server -h 192.168.1.201 -P 3306 -u root -p --result-file=C:\tmp\recover_000002_000017.sql binlog.000002 binlog.000003 binlog.000004 binlog.000005 binlog.000006 binlog.000007 binlog.000008 binlog.000009 binlog.000010 binlog.000011 binlog.000012 binlog.000013 binlog.000014 binlog.000015 binlog.000016 binlog.000017
生成第二段,停在删库前:
powershell
& "$MYSQL_BIN\mysqlbinlog.exe" --no-defaults --read-from-remote-server -h 192.168.1.201 -P 3306 -u root -p --stop-position=5531995 --result-file=C:\tmp\recover_000018_before_drop.sql binlog.000018
7. 导入到临时 MySQL 实例
本次临时实例使用本地 MySQL:
powershell
$TARGET_HOST="127.0.0.1"
$TARGET_PORT="3306"
$MYSQL_EXE="$MYSQL_BIN\mysql.exe"
确认本地 MySQL 可连接:
powershell
& "$MYSQL_EXE" --no-defaults -h $TARGET_HOST -P $TARGET_PORT -u root -p -e "SELECT VERSION();"
PowerShell 不支持直接这样使用输入重定向:
powershell
& "$MYSQL_EXE" --binary-mode -h $TARGET_HOST -P $TARGET_PORT -u root -p < C:\tmp\recover_000002_000017.sql
会报:
text
RedirectionNotSupported
应使用 cmd /c 执行导入:
powershell
cmd /c "`"$MYSQL_EXE`" --no-defaults --binary-mode -h $TARGET_HOST -P $TARGET_PORT -u root -p < C:\tmp\recover_000002_000017.sql"
继续导入第二段:
powershell
cmd /c "`"$MYSQL_EXE`" --no-defaults --binary-mode -h $TARGET_HOST -P $TARGET_PORT -u root -p < C:\tmp\recover_000018_before_drop.sql"
8. 常见导入问题
8.1 database exists
如果提前手动创建了 lakehouse,而 binlog 中也包含:
sql
CREATE DATABASE `lakehouse`;
导入会报:
text
ERROR 1007 (HY000): Can't create database 'lakehouse'; database exists
处理方式:
如果临时实例中的 lakehouse 没有需要保留的数据,删除后重新导入:
powershell
& "$MYSQL_EXE" --no-defaults -h $TARGET_HOST -P $TARGET_PORT -u root -p -e "DROP DATABASE lakehouse;"
然后重新导入第一段和第二段 SQL。
8.2 Unknown database 或 Table doesn't exist
如果导入时报:
text
Unknown database 'lakehouse'
Table doesn't exist
说明现有 binlog 可能缺少更早的建库或建表记录。没有全量备份时,这种情况只能恢复部分数据,或者继续查找更早的 binlog、服务器快照、磁盘快照、历史备份。
9. 验证恢复结果
查看 lakehouse 是否存在:
powershell
& "$MYSQL_EXE" --no-defaults -h $TARGET_HOST -P $TARGET_PORT -u root -p -e "SHOW DATABASES LIKE 'lakehouse';"
查看表数量:
powershell
& "$MYSQL_EXE" --no-defaults -h $TARGET_HOST -P $TARGET_PORT -u root -p -e "SELECT COUNT(*) AS table_count FROM information_schema.tables WHERE table_schema='lakehouse';"
本次恢复后结果:
text
table_count = 121
查看所有表:
powershell
& "$MYSQL_EXE" --no-defaults -h $TARGET_HOST -P $TARGET_PORT -u root -p -e "USE lakehouse; SHOW TABLES;"
恢复完成后立即导出一份 SQL 备份:
powershell
& "$MYSQL_BIN\mysqldump.exe" --no-defaults -h $TARGET_HOST -P $TARGET_PORT -u root -p --databases lakehouse --routines --triggers --events --single-transaction --default-character-set=utf8mb4 --result-file=C:\tmp\lakehouse_restored.sql
10. 表名大小写问题
本次恢复过程中使用了 Windows 本地 MySQL。Windows MySQL 通常配置为:
sql
lower_case_table_names = 1
这会导致表名落盘变成小写。
而 Linux MySQL 通常为:
sql
lower_case_table_names = 0
Linux 下表名区分大小写。对于 Camunda 这类固定大写表名的组件,可能出现问题。
例如 Camunda 期望表名:
text
ACT_RE_DECISION_DEF
ACT_RE_DECISION_REQ_DEF
但恢复后可能变成:
text
act_re_decision_def
act_re_decision_req_def
服务启动时可能会重新生成一批大写 ACT_* 空表,导致库里同时存在大写和小写两套 Camunda 表。
检查大小写表:
sql
SELECT TABLE_NAME
FROM information_schema.tables
WHERE table_schema = 'lakehouse'
AND LOWER(TABLE_NAME) LIKE 'act\_%'
ORDER BY TABLE_NAME;
如果确认小写表有数据、大写表是服务启动后新建的空表,处理原则是:
- 停止服务。
- 删除大写空表。
- 将小写表重命名为大写。
- 再启动服务验证。
生成删除大写表 SQL:
sql
SET SESSION group_concat_max_len = 1000000;
SELECT CONCAT(
'SET FOREIGN_KEY_CHECKS=0; ',
GROUP_CONCAT(
CONCAT('DROP TABLE IF EXISTS `lakehouse`.`', UPPER(TABLE_NAME), '`')
ORDER BY TABLE_NAME
SEPARATOR '; '
),
'; SET FOREIGN_KEY_CHECKS=1;'
) AS drop_upper_sql
FROM information_schema.tables
WHERE table_schema = 'lakehouse'
AND TABLE_NAME REGEXP '^act_'
AND BINARY TABLE_NAME = LOWER(TABLE_NAME);
生成小写改大写 SQL:
sql
SET SESSION group_concat_max_len = 1000000;
SELECT CONCAT(
'RENAME TABLE ',
GROUP_CONCAT(
CONCAT('`lakehouse`.`', TABLE_NAME, '` TO `lakehouse`.`', UPPER(TABLE_NAME), '`')
ORDER BY TABLE_NAME
SEPARATOR ', '
),
';'
) AS rename_sql
FROM information_schema.tables
WHERE table_schema = 'lakehouse'
AND TABLE_NAME REGEXP '^act_'
AND BINARY TABLE_NAME = LOWER(TABLE_NAME);
验证:
sql
SHOW TABLES LIKE 'ACT_RE_DECISION%';
SHOW TABLES LIKE 'act_re_decision%';
正确结果应只剩大写 ACT_* 表。
11. 推荐的恢复流程
如果再次发生类似事故,建议按以下顺序执行:
- 立即停止业务写入。
- 确认 binlog 是否开启。
- 查
SHOW BINARY LOGS,确认可用 binlog 范围。 - 使用
mysqlbinlog --no-defaults解析最近 binlog。 - 定位
DROP DATABASE或DROP TABLE的时间和 position。 - 优先恢复到临时 MySQL 实例。
- 有全量备份时:先导全量备份,再回放全量备份之后到误删前的 binlog。
- 无全量备份时:从现有最早 binlog 开始尝试重放到误删前。
- 验证表数量、核心表数据量、业务启动情况。
- 验证无误后再导出恢复后的完整 SQL 备份。
- 再决定是否回灌到生产库或切换服务连接。
12. 预防措施
建议生产环境至少保留以下机制:
- 每日全量备份。
- binlog 保留周期不少于 7 到 15 天。
- 备份文件异机保存。
- 定期做恢复演练。
- 生产账号禁止随意执行
DROP DATABASE。 - 高危 SQL 执行前增加人工确认或审批。
本次已补充定时备份方案:
- 201 服务器每日备份
lakehouse - 本地保留 10 天
- 备份文件上传到 200 服务器
- 200 服务器同样清理 10 天前备份