写点什么

TiDB 误删数据恢复

  • 2024-03-08
    北京
  • 本文字数:4412 字

    阅读完需:约 14 分钟

作者: longzhuquan 原文来源:https://tidb.net/blog/2cc22ccf

背景

在 DBA 的日常工作中,误删除数据是一种常见但令人头疼的问题。作为数据库管理员,DBA 承担着维护数据库完整性和安全性的责任。误删测试数据可能造成项目延期,影响测试,重复工作,误删生产数据可能导致业务中断,客户数据丢失,导致公司面临法律风险。一旦发生误删除,DBA 需要迅速应对,本文主要介绍在 TiDB 数据库中,误删数据后的常见应急措施。

常见场景

  1. drop database 误删除数据库

  2. truncate table 误清空表

  3. drop table 误删除表

  4. delete、update 误删除 / 更新数据

恢复方法

应急操作

TiDB 的事务的实现采用了 MVCC(多版本并发控制)机制,当新写入的数据覆盖旧的数据时,旧的数据不会被替换掉,而是与新写入的数据同时保留,并以时间戳来区分版本。TiDB 通过定期 GC 的机制来清理不再需要的旧数据。因此,GC 没有过期是我们进行数据恢复的基础。


在生产环境中,可以通过适当设置垃圾收集(GC)参数来应对误删除场景,但同时也需要考虑历史版本过多可能引起的性能和容量上的开销。


当出现误删除数据情况时,应在第一时间调整 GC 相关参数,增加 GC 保留时长,操作方法如下:


# 查看gc参数配置show variables like '%tidb_gc_life_time%';# 调整gc参数配置set global tidb_gc_life_time='48h';
复制代码

drop database 误删除数据库恢复 (TiDB v6.4 之前)

确定误操作时间,可以通过 admin show ddl jobs 语句确认误操作时间


MySQL [test]> admin show ddl jobs;+--------+---------+------------+---------------+--------------+-----------+----------+-----------+---------------------+---------------------+--------+| JOB_ID | DB_NAME | TABLE_NAME | JOB_TYPE      | SCHEMA_STATE | SCHEMA_ID | TABLE_ID | ROW_COUNT | START_TIME          | END_TIME            | STATE  |+--------+---------+------------+---------------+--------------+-----------+----------+-----------+---------------------+---------------------+--------+|    116 | test1   |            | drop schema   | queueing     |       102 |        0 |         0 | 2024-03-07 12:59:56 | 2024-03-07 12:59:56 | synced ||    115 | test1   | t2         | add index     | public       |       102 |      112 |     10000 | 2024-03-07 12:41:29 | 2024-03-07 12:41:33 | synced ||    114 | test1   | t1         | add index     | public       |       102 |      110 |     10000 | 2024-03-07 12:41:23 | 2024-03-07 12:41:27 | synced ||    113 | test1   | t2         | create table  | public       |       102 |      112 |         0 | 2024-03-07 12:41:21 | 2024-03-07 12:41:21 | synced ||    111 | test1   | t1         | create table  | public       |       102 |      110 |         0 | 2024-03-07 12:41:21 | 2024-03-07 12:41:21 | synced ||    109 | test    | t2         | add index     | public       |         1 |      106 |     10000 | 2024-03-07 12:40:47 | 2024-03-07 12:40:51 | synced ||    108 | test    | t1         | add index     | public       |         1 |      104 |     10000 | 2024-03-07 12:40:41 | 2024-03-07 12:40:45 | synced ||    107 | test    | t2         | create table  | public       |         1 |      106 |         0 | 2024-03-07 12:40:39 | 2024-03-07 12:40:40 | synced ||    105 | test    | t1         | create table  | public       |         1 |      104 |         0 | 2024-03-07 12:40:38 | 2024-03-07 12:40:38 | synced ||    103 | test1   |            | create schema | public       |       102 |        0 |         0 | 2024-03-07 12:35:14 | 2024-03-07 12:35:14 | synced |+--------+---------+------------+---------------+--------------+-----------+----------+-----------+---------------------+---------------------+--------+10 rows in set (0.73 sec)
复制代码


或通过 TiDB Dashboard 日志搜索功能确认误操作时间



确认下删除时间没超过 GC 时间,即下面 SQL 查询出来的 tikv_gc_safe_point 小于数据删除时间


MySQL [test1]> SELECT * FROM mysql.tidb WHERE variable_name = 'tikv_gc_safe_point';+--------------------+-----------------------------+--------------------------------------------------------------+| VARIABLE_NAME      | VARIABLE_VALUE              | COMMENT                                                      |+--------------------+-----------------------------+--------------------------------------------------------------+| tikv_gc_safe_point | 20240307-13:28:51.993 +0800 | All versions after safe point can be accessed. (DO NOT EDIT) |+--------------------+-----------------------------+--------------------------------------------------------------+1 row in set (0.01 sec)
复制代码


使用 SQL 确认下删除时间。


MySQL [test]> set session tidb_snapshot='2024-03-07 12:59:56';Query OK, 0 rows affected (0.00 sec)
MySQL [test]> show databases;+--------------------+| Database |+--------------------+| INFORMATION_SCHEMA || METRICS_SCHEMA || PERFORMANCE_SCHEMA || mysql || test || test1 || tpcc |+--------------------+7 rows in set (0.00 sec)
MySQL [test]> set session tidb_snapshot='2024-03-07 12:59:57';Query OK, 0 rows affected (0.00 sec)
MySQL [test]> show databases;+--------------------+| Database |+--------------------+| INFORMATION_SCHEMA || METRICS_SCHEMA || PERFORMANCE_SCHEMA || mysql || test || tpcc |+--------------------+6 rows in set (0.01 sec)
复制代码


使用 dumpling 导出要保留的数据


tiup dumpling -uroot  -h192.168.0.1 -P4000 -B test1 --filetype sql -t 4 -F 256MiB -o ./dump_test1 -L ./dump_test1.log --snapshot "2024-03-07 12:59:56"
复制代码


使用 lighting 导出要保留的数据


tiup tidb-lightning -backend tidb -d ./dump_test1 -tidb-host 192.168.0.1 -tidb-password "" -tidb-port 4000 -tidb-user root
复制代码


数据恢复完成

DROP DATABASE 误删除数据库恢复 (TiDB v6.4 之后)

从 TiDB v6.4 版本开始,TiDB 引入了 FLASHBACKUP DATABASE 语法,该语法允许快速恢复误删除的数据库,无需再确认误操作时间,极大地加快了误删除数据库恢复的速度。值得注意的是,该功能同样依赖于 GC(垃圾收集)机制。


MySQL [(none)]> flashback database test1;Query OK, 0 rows affected (0.31 sec)
MySQL [(none)]> show databases;+--------------------+| Database |+--------------------+| INFORMATION_SCHEMA || METRICS_SCHEMA || PERFORMANCE_SCHEMA || mysql || result || test || test1 || tpcc |+--------------------+8 rows in set (0.00 sec)
MySQL [(none)]> use test1;Reading table information for completion of table and column namesYou can turn off this feature to get a quicker startup with -A
Database changedMySQL [test1]> show tables;+-----------------+| Tables_in_test1 |+-----------------+| t1 || t2 |+-----------------+2 rows in set (0.00 sec)
复制代码

TRUNCATE TABLE 误清空表

使用 FLASHBACK TABLE 语句可以快速恢复误清空表导致的数据丢失。值得注意的是,该语句仅能恢复上一次 TRUNCATE 操作丢失的数据。如果需要恢复多次 TRUNCATE 操作前的数据,可以按照 TiDB v6.4 之前版本的 drop database 误删除库的恢复操作进行处理。值得注意的是,该功能同样依赖于 GC(垃圾收集)机制。


MySQL [test1]> truncate table t1;Query OK, 0 rows affected (0.52 sec)
MySQL [test1]> select count(1) from t1;+----------+| count(1) |+----------+| 0 |+----------+1 row in set (0.00 sec)
MySQL [test1]> insert into t1 select * from t2 limit 3;Query OK, 3 rows affected (0.02 sec)Records: 3 Duplicates: 0 Warnings: 0
MySQL [test1]> select * from t1;+------+------------+------------+------------+| id | col1 | col2 | col3 |+------+------------+------------+------------+| 1 | 0f74fa3c18 | 66b149a20e | 0e1e7bf8c8 || 2 | f0f976f0d3 | 75fc7f6174 | d562074867 || 3 | 579cfa1074 | 1d74595138 | e9220d8e86 |+------+------------+------------+------------+3 rows in set (0.00 sec)
MySQL [test1]> flashback table t1;ERROR 1050 (42S01): Table 't1' already existsMySQL [test1]> flashback table t1 to t1_old;Query OK, 0 rows affected (2.03 sec)
MySQL [test1]> select count(1) from t1_old;+----------+| count(1) |+----------+| 10000 |+----------+1 row in set (0.01 sec)
复制代码

DROP TABLE 误删除表

DROP TABLE 误删除表与 TRUNCATE TABLE 误清空数据的处理方式类似,这里就不再赘述。

DELETE、UPDATE 误删除 / 更新数据

DELETE、UPDATE 误删除 / 更新数据与 TiDB v6.4 版本前的 DROP DATABASE 误删除库处理方式相似,只不过在确认误操作时间上相对困难。以下是确定误操作时间的可能思路:


  • TiDB 慢查询日志:如果 DELETE 或 UPDATE 的 SQL 执行时长超过慢查询日志阈值,相关信息将被记录在慢查询日志中。

  • 审计日志:包括 TiDB 审计日志、堡垒机审计、第三方数据库审计软件等。通过审计日志可以追踪到数据库操作的详细信息,包括误删除或误更新的时间戳。

  • 误操作人员的时间描述:误操作人员提供的关于误操作发生时间的描述。虽然这种方式相对主观,但可能有助于缩小确认误操作时间的范围。


通过以上信息,结合 TiDB 提供的 tidb_snapshot 功能,可以进一步确定误操作的确切时间,为后续数据的准确恢复提供基础。

总结建议

总结:TiDB 数据库针对数据库误删除的场景处理方式还是很友好的,多数场景下都能比较快速的找回数据。但恢复比较依赖 GC 机制,如果超过了 GC 的时长,就是能使用备份对误删除的数据进行恢复了。


建议:如果 tidb_snapshot 功能下能够支持将查询出来的数据 insert into/import into 到另一张表,那样误删除 / 更新数据场景下的恢复速度就更快了。


发布于: 38 分钟前阅读数: 4
用户头像

TiDB 社区官网:https://tidb.net/ 2021-12-15 加入

TiDB 社区干货传送门是由 TiDB 社区中布道师组委会自发组织的 TiDB 社区优质内容对外宣布的栏目,旨在加深 TiDBer 之间的交流和学习。一起构建有爱、互助、共创共建的 TiDB 社区 https://tidb.net/

评论

发布
暂无评论
TiDB误删数据恢复_管理与运维_TiDB 社区干货传送门_InfoQ写作社区