mysql数据库误删恢复

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. 第一时间处理

误删后优先做以下处理:

  1. 不要继续往原库写入数据。
  2. 不要执行 PURGE BINARY LOGS
  3. 不要重启或清理 MySQL 数据目录。
  4. 优先确认是否开启 binlog,以及 binlog 文件是否还在。
  5. 恢复操作不要直接打到原库,先恢复到临时 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 是否包含以下内容:

  1. CREATE DATABASE lakehouse
  2. 所有 CREATE TABLE
  3. 初始导入数据
  4. 后续所有 DML 变更

如果 binlog 不包含建库、建表或初始数据,则只能恢复部分数据。

6. 生成恢复 SQL

不要把所有 binlog 都用同一个 --stop-position 一次性生成,建议拆成两段:

  1. 完整回放 binlog.000002binlog.000017
  2. 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;

如果确认小写表有数据、大写表是服务启动后新建的空表,处理原则是:

  1. 停止服务。
  2. 删除大写空表。
  3. 将小写表重命名为大写。
  4. 再启动服务验证。

生成删除大写表 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. 推荐的恢复流程

如果再次发生类似事故,建议按以下顺序执行:

  1. 立即停止业务写入。
  2. 确认 binlog 是否开启。
  3. SHOW BINARY LOGS,确认可用 binlog 范围。
  4. 使用 mysqlbinlog --no-defaults 解析最近 binlog。
  5. 定位 DROP DATABASEDROP TABLE 的时间和 position。
  6. 优先恢复到临时 MySQL 实例。
  7. 有全量备份时:先导全量备份,再回放全量备份之后到误删前的 binlog。
  8. 无全量备份时:从现有最早 binlog 开始尝试重放到误删前。
  9. 验证表数量、核心表数据量、业务启动情况。
  10. 验证无误后再导出恢复后的完整 SQL 备份。
  11. 再决定是否回灌到生产库或切换服务连接。

12. 预防措施

建议生产环境至少保留以下机制:

  1. 每日全量备份。
  2. binlog 保留周期不少于 7 到 15 天。
  3. 备份文件异机保存。
  4. 定期做恢复演练。
  5. 生产账号禁止随意执行 DROP DATABASE
  6. 高危 SQL 执行前增加人工确认或审批。

本次已补充定时备份方案:

  • 201 服务器每日备份 lakehouse
  • 本地保留 10 天
  • 备份文件上传到 200 服务器
  • 200 服务器同样清理 10 天前备份
相关推荐
IvorySQL1 小时前
PostgreSQL 技术日报 (6月3日)|复制日志补丁更新,PG 黑客坊开启
数据库·人工智能·postgresql
j7~1 小时前
【MYSQL】图形化界面使用说明-- MYSQL(workbench)
数据库·mysql·mysql图形化界面·mysqlworkbench
m0_653031361 小时前
(文档)第124讲:异构数据库同步利器 — SynchDB使用全攻略
数据库
_Kafka_1 小时前
Oracle EBS 有期间控制的模块
数据库·oracle
潮起鲸落入海2 小时前
mysql的client和server基本使用
mysql
light blue bird2 小时前
工序 BOM 协同系统架构多模块组件
数据库·信息可视化·.net
appearappear2 小时前
优雅实现・高并发下大量数据乐观锁批量更新(MySQL 最优实践)
数据库·mysql
TG_yunshuguoji2 小时前
腾讯云代理商:腾讯云CloudBase数据库操作全解析
数据库·人工智能·云计算·腾讯云·cloudbase
废弃的小码农3 小时前
APP测试--adb使用介绍
python·测试工具·adb