当前位置: 首页 > news >正文

# 一次 MySQL DELETE 误操作的数据恢复尝试实录


## 背景
2026年1月20日中午,有人在生产环境执行了一条 DELETE 清理脚本,想删除 xxx 表中属于2026年订单的数据。
结果:删了 206,689 行。
---
## 第一步:还原操作过程
查生产sql日志
11:51:12

CREATE TABLE xxx_2026 ... 11:51:27

INSERT INTO xxx_2026 SELECT * FROM ... (备份完成) 11:53:00

DELETE FROM xxx WHERE orderno IN (SELECT orderno FROM tb_order_2026) (执行耗时: 116.287s)

**操作逻辑**:tb_order.sh 脚本的标准流程是——先 INSERT 到年度备份表,再 DELETE 主表。备份已完成,DELETE 也执行了。
**删了多少?**
`_2026` 备份表记录了 206,689 行,这基本上就是被 DELETE 掉的行数。但精确数字因为日志被截断,始终没能确认。


## 第二步:发现第二个 DELETE 没执行
脚本本意是删两批:
- 第一批:2026-01-01 ~ 2026-01-06 的订单 ✅ 已执行
- 第二批:2026-01-06 ~ 2026-01-11 的订单 ❌ 未执行
查日志发现,第二次 DELETE 报了语法错误:
SQL 语法错误: DELETE FROM ... WHERE "orderno" IN (...)


**原因**:Navicat 传参时 SQL 被双引号包住,导致语法错误,第二次 DELETE 根本没有执行。这意味着 2026-01-06~11 的数据还在主表里,没丢。



## 第三步:停止定时任务,防止再次触发
crontab 显示,每月 15/16/23 号凌晨 3 点会执行 tb_order.sh:
每月15/16/23号凌晨跑清理脚本
0 3 15,16,23 * * /opt/tb_order.sh 0 4 15,16,23 * * /opt/tb_pay_info.sh


紧急执行:
```bash
systemctl stop crond
暂停定时任务,防止23号凌晨脚本再次执行。

第四步:评估恢复方案
方案一:binlog 闪回
mysqlbinlog --start-datetime="2026-01-20 11:50:00" \
--stop-datetime="2026-01-20 12:00:00" \
/var/lib/mysql/mysql-bin.000001 | grep "DELETE"
结果:无 binlog。该 数据库为自建的 实例没有开启 binlog,无法用 mysqlbinlog 恢复。


方案二:HBR 全量备份

# 查 HBR 备份日志
grep "2026-01-19" /usr/local/aegis/hbrclient/logs/backup_job-*.log
# 结果:
# backup_job-14940.log: 2026-01-19 02:02:00 开始全盘备份
# backup_job-14940.log: 2026-01-19 03:00:06 全盘备份完成
HBR 每天凌晨 2 点有全盘备份,包含 /var/lib/mysql。理论上可以从 HBR 恢复一个副本,再导出被删数据后插回主表。
但 HBR 恢复操作复杂,需要:申请副本 → 挂载 → 启动临时实例 → 导出数据 → 清理副本。步骤多,风险高,暂时没有执行。


方案三:INSERT IGNORE 回滚(最终方案)
_2026 备份表有 206,689 行,结构已知(id 主键 + orderno 索引)。
回滚 SQL:
sql
-- 分批插回,每批1000行
INSERT IGNORE INTO xxx
SELECT * FROM xxx_2026
WHERE id BETWEEN 1 AND 1000;
INSERT IGNORE INTO xxx
SELECT * FROM xxx_2026
WHERE id BETWEEN 1001 AND 2000;
-- ... 以此类推

INSERT IGNORE 的好处:如果 2026-01-06~11 的数据(没被删的那批)和 _2026 里有主键冲突,不会报错直接跳过。
但回滚最终没有执行完——因为 SHOW CREATE TABLE 结果没拿到,无法精确确认主键列名,回滚 SQL 暂停。

踩的坑
坑一:SQL 被双引号包住导致语法错误

Navicat 传参习惯会把变量用双引号包住,但 MySQL 里字符串应该用单引号,双引号是用于表名列名的。这导致第二次 DELETE 失败,数据没有按预期删除干净。
教训:Navicat 传参时确认 SQL 语法,不要依赖 GUI 自动加引号。

坑二:日志里的 COUNT 结果被截断
11:51:27 INSERT INTO xxx_2026 SELECT * FROM ...
11:51:27 SELECT COUNT(*) FROM ...
查询执行了 11.733s,日志里能看到语句发出,但结果数字被截断。始终不知道精确删了多少行,只能靠 _2026 表的行数反推。
教训:生产执行重要 SQL 前,先在测试库跑一遍确认结果。

坑三:没有 binlog
该 RDS 实例未开启 binlog,导致无法用 mysqlbinlog 做增量恢复。
教训:生产数据库务必开启 binlog,是数据安全的基本保障
HBR 是全盘备份,包含 /var/lib/mysql,但不包含 binlog 日志文件(binlog 是独立的)。即使恢复了 HBR 副本,也只能恢复到快照点的全量数据,无法做增量。
教训:HBR + binlog 双重保障才是完整的生产数据库备份策略。

总结
DELETE 删了多少
约 206,689 行(从备份表反推)
2026-01-01~06 数据
已备份到 _2025 表,未回滚
2026-01-06~11 数据
因语法错误未删除,仍在主表
定时任务
已停止 crond
binlog
未开启,无法 mysqlbinlog 闪回
HBR 备份
2TB,包含 MySQL 全量数据
INSERT IGNORE 回滚
因主键列名未确认,未执行完


经验总结
1. 生产执行 DELETE 前必做检查清单

□ 在测试库跑一遍,确认影响行数
□ 确认备份已就位(INSERT SELECT 完成)
□ 确认 crontab 已暂停或该时段无定时任务
□ 确认 binlog 已开启
□ 确认 WHERE 条件无误(特别检查引号是单引号)
□ 预估执行时间,设置合适的 max_execution_time
2. 备份表命名规范
备份表加时间戳后缀:xxx_2025 → xxx_20250623_1151,这样即使多次操作,备份不会覆盖。


-- 检查是否开启
SHOW VARIABLES LIKE 'log_bin';
SHOW VARIABLES LIKE 'expire_logs_days';
4. 脚本 DELETE 改为 UPDATE 标志位
tb_order.sh 逻辑是 INSERT + DELETE,更安全的做法是:
-- 不删除,只标记删除状态
UPDATE xxx
SET deleted = 1, delete_time = NOW()
WHERE orderno IN (SELECT orderno FROM tb_order_2025);
这样数据不丢失,随时可以回滚。

相关命令速查
# 查 binlog 是否开启
mysql -e "SHOW VARIABLES LIKE 'log_bin';"
# 查 HBR 备份日志
grep "backup_job" /usr/local/aegis/hbrclient/logs/backup_job-*.log | tail -10
# 查 crontab
crontab -l
cat /etc/cron.d/*
# 暂停定时任务
systemctl stop crond
# 查备份表行数
SELECT COUNT(*) FROM xxx_2025;
# 分批 INSERT IGNORE 回滚(示例)
INSERT IGNORE INTO xxx
SELECT * FROM xxx_2025
WHERE id BETWEEN 1 AND 1000;

http://www.jsqmd.com/news/1119118/

相关文章:

  • MiMo-Code开源16天11K星:小米AI编码Agent的持久记忆和自进化机制
  • 影刀RPA新手教程:跨境电商选品完全指南——AliExpress热卖商品分析与竞品调研自动化
  • 重光研究 | 从首例基金实控人连带赔偿看私募基金维权——管理人全流程失职的责任认定4624号民事判决
  • C++ 虚继承对象内存布局
  • 专注核心需求的纯本地音乐播放器
  • Quark-Auto-Save架构设计与自动化转存技术深度解析
  • 4-Hadoop伪分布式搭建基本流程
  • MC0483过园数统计
  • 【干货】基础知识-图像处理
  • 大模型应用中的“中转层”到底解决了什么问题?
  • 西门子S7协议调试工具的技术架构与生产环境下应用
  • 每日文献阅读-复现|2026 npj Computational Materials:130 万候选如何用 AI 与第一性原理筛出 741 种超导体
  • PCB焊盘设计:SMD与NSMD的选择与应用
  • 华为MetaERP Oracle EBS 各模块业务场景与会计分录对照表。由于无法直接生成 Excel 文件,我将以清晰的表格格式呈现,你可以直接复制到 Excel 中使用。Oracle EBS 各
  • 助睿实验指导7:自媒体运营分析三次过程合并-CSDN博客
  • 亲测速度几十MB/s!2026百度网盘不限速下载黑科技,原来大家都偷偷在用
  • 影刀RPA新手教程:邮件自动发送完全指南——从SMTP配置到批量个性化发送
  • (六)海康工业相机与halcon+C#联合编程
  • Claude Code安全审查实战:从SQL注入检测到CI/CD集成指南
  • 92.从底层原理、编程规范、模块化设计到调试避坑!PLC ST 语言工控项目全流程实战
  • 120 万奖金池里,有一块没人抢的肥肉:RWKV-7 × transformers 训练适配
  • RAG落地踩坑实录:从Demo到生产的差距有多大?
  • S1.1 独立产品的变现模式地图:哪种模式最适合你
  • 通过结构化步骤化解社恐压力
  • Dify 实战指南:从零构建企业级 AI 应用与工作流
  • 华为MetaERP Oracle EBS 各模块业务场景及会计分录汇总表文件信息: 共 11个模块 | 300条业务场景 | 编制日期:2026年7月模块目录表格序号 模块名称 业务场景数 主
  • CBC模式密文篡改攻击:无需密钥,直接实现权限提升
  • OpenHarmony Button 按钮组件全场景开发与 API23 + 适配优化
  • 做电子元器件生产的朋友,国内线圈固定胶生产厂家哪家更靠谱?
  • 分享一个连DeepSeek都说“颜值高”的代码截图工具