数据误操作恢复:用 Time Travel 找回删除和改错的数据

业务背景

数据误操作是每个数据团队都会遇到的事故:运营同学手滑删了一批订单、开发同学 UPDATE 时 WHERE 条件写宽了改错了金额、DBA 误执行了 DROP TABLE。传统数据库遇到这类问题,要么从备份恢复(慢,且会丢失备份后的数据),要么靠 binlog 重放(复杂,需要 DBA 介入)。

Lakehouse 的 Time Travel 功能让数据恢复变成一条 SQL 的事:每次写操作都会生成一个新版本,历史版本默认保留 1 天(可配置最长 90 天),你可以随时查询任意历史时间点的数据,也可以一键回滚整张表。

三种恢复手段,对应三种事故类型:

事故类型恢复手段适用场景
误删部分行(DELETE)
INSERT INTO ... SELECT ... TIMESTAMP AS OF
INSERT INTO ... SELECT ... TIMESTAMP AS OF
只补回被删的行,不影响误删后写入的新数据
误改数据(UPDATE)
RESTORE TABLE ... TO TIMESTAMP AS OF
RESTORE TABLE ... TO TIMESTAMP AS OF
整张表回滚到指定时间点
误删整张表(DROP)
UNDROP TABLE
UNDROP TABLE
恢复被删除的表及其全部数据

涉及的 SQL 命令

命令用途
DESC HISTORY
DESC HISTORY
查看表的版本历史,找到误操作前的时间点
SELECT ... TIMESTAMP AS OF
SELECT ... TIMESTAMP AS OF
查询指定时间点的历史数据
INSERT INTO ... SELECT ... TIMESTAMP AS OF
INSERT INTO ... SELECT ... TIMESTAMP AS OF
从历史版本补回被删的行
RESTORE TABLE ... TO TIMESTAMP AS OF
RESTORE TABLE ... TO TIMESTAMP AS OF
整张表回滚到指定时间点
UNDROP TABLE
UNDROP TABLE
恢复被 DROP 的表

前置准备

建订单表并写入初始数据

CREATE TABLE IF NOT EXISTS doc_orders ( order_id STRING, user_id STRING, product_id STRING, amount DECIMAL(10,2), status STRING, order_time TIMESTAMP ); INSERT INTO doc_orders VALUES ('O001','U101','P001', 598.00,'completed', CAST('2026-05-28 09:00:00' AS TIMESTAMP)), ('O002','U102','P002', 459.00,'completed', CAST('2026-05-28 09:10:00' AS TIMESTAMP)), ('O003','U103','P003', 389.00,'completed', CAST('2026-05-28 09:20:00' AS TIMESTAMP)), ('O004','U104','P001', 299.00,'completed', CAST('2026-05-28 09:30:00' AS TIMESTAMP)), ('O005','U105','P004', 256.00,'completed', CAST('2026-05-28 09:40:00' AS TIMESTAMP));

查看版本历史,记录安全版本的时间戳

每次写操作都会生成一个新版本。用

DESC HISTORY
DESC HISTORY
查看版本列表:

DESC HISTORY doc_orders;

+---------+-------------------------+----------+------+----------+ |version |time |total_rows|user |operation | +---------+-------------------------+----------+------+----------+ |2 |2026-05-28T19:45:27.356 |5 |qiliang|INSERT_INTO| |1 |2026-05-28T19:45:07.582 |0 |qiliang|CREATE | +---------+-------------------------+----------+------+----------+

version 2 是 5 条完整数据写入后的状态,记下时间戳

2026-05-28 19:45:27
2026-05-28 19:45:27
,后续恢复时会用到。

场景一:误删部分行,精准补回

运营同学执行了一条 DELETE,WHERE 条件写错,误删了 3 条订单:

DELETE FROM doc_orders WHERE user_id IN ('U103','U104','U105');

表里只剩 2 条数据。

第一步:确认误删前的时间点

DESC HISTORY doc_orders;

+---------+-------------------------+----------+------+----------+ |version |time |total_rows|user |operation | +---------+-------------------------+----------+------+----------+ |3 |2026-05-28T19:45:43.564 |2 |qiliang|DELETE | |2 |2026-05-28T19:45:27.356 |5 |qiliang|INSERT_INTO| |1 |2026-05-28T19:45:07.582 |0 |qiliang|CREATE | +---------+-------------------------+----------+------+----------+

version 2(

19:45:27
19:45:27
)是误删前的完整状态,version 3 是误删后只剩 2 行。

第二步:预览要恢复的数据

SELECT * FROM doc_orders TIMESTAMP AS OF '2026-05-28 19:45:28' ORDER BY order_id;

+--------+------+----------+-------+---------+---------------------+ |order_id|user_id|product_id|amount |status |order_time | +--------+------+----------+-------+---------+---------------------+ |O001 |U101 |P001 |598.00 |completed|2026-05-28T09:00:00 | |O002 |U102 |P002 |459.00 |completed|2026-05-28T09:10:00 | |O003 |U103 |P003 |389.00 |completed|2026-05-28T09:20:00 | |O004 |U104 |P001 |299.00 |completed|2026-05-28T09:30:00 | |O005 |U105 |P004 |256.00 |completed|2026-05-28T09:40:00 | +--------+------+----------+-------+---------+---------------------+

5 条数据完整可见。

第三步:只补回被删的行

NOT IN
NOT IN
过滤掉当前表中已有的行,只插入缺失的部分:

INSERT INTO doc_orders SELECT * FROM doc_orders TIMESTAMP AS OF '2026-05-28 19:45:28' WHERE order_id NOT IN (SELECT order_id FROM doc_orders);

执行后表恢复为 5 条数据。这种方式的优势是:如果误删后有新数据写入,新数据不会被覆盖。

场景二:误改数据,整表回滚

开发同学执行 UPDATE 时 WHERE 条件写得太宽,把所有订单金额都乘以了 10:

UPDATE doc_orders SET amount = amount * 10 WHERE order_time > CAST('2026-01-01' AS TIMESTAMP);

第一步:确认误操作版本

DESC HISTORY doc_orders;

+---------+-------------------------+----------+------+----------+ |version |time |total_rows|user |operation | +---------+-------------------------+----------+------+----------+ |5 |2026-05-28T19:46:57.926 |5 |qiliang|UPDATE | |4 |2026-05-28T19:46:21.359 |5 |qiliang|INSERT_INTO| ... +---------+-------------------------+----------+------+----------+

version 5 是误 UPDATE,version 4(

19:46:21
19:46:21
)是正确状态。

第二步:对比误操作前后的差异(可选)

在回滚前,先确认影响范围:

SELECT cur.order_id, cur.amount AS amount_current, bad.amount AS amount_bad_update, bad.amount - cur.amount AS diff FROM doc_orders AS cur JOIN (SELECT * FROM doc_orders TIMESTAMP AS OF '2026-05-28 19:46:58') AS bad ON cur.order_id = bad.order_id ORDER BY cur.order_id;

+--------+---------------+------------------+---------+ |order_id|amount_current |amount_bad_update |diff | +--------+---------------+------------------+---------+ |O001 |598.00 |5980.00 |5382.00 | |O002 |459.00 |4590.00 |4131.00 | |O003 |389.00 |3890.00 |3501.00 | |O004 |299.00 |2990.00 |2691.00 | |O005 |256.00 |2560.00 |2304.00 | +--------+---------------+------------------+---------+

5 条订单全部受影响,金额均被放大 10 倍。

第三步:整表回滚

RESTORE TABLE doc_orders TO TIMESTAMP AS OF '2026-05-28 19:46:22';

执行后表回滚到 version 4 的状态,金额恢复正常。

场景三:误删整张表,UNDROP 恢复

DBA 误执行了 DROP TABLE:

DROP TABLE doc_orders;

表消失,查询报错

table or view not found
table or view not found

一条命令恢复

UNDROP TABLE doc_orders;

执行后表及其全部数据立即恢复,版本历史也完整保留。

清理资源

DROP TABLE IF EXISTS doc_orders;

关键点总结

  • 先查
    DESC HISTORY
    DESC HISTORY
    ,再操作
    :恢复前必须确认目标版本的时间戳,不要凭记忆估算时间
  • 时间戳只接受字面量
    TIMESTAMP AS OF
    TIMESTAMP AS OF
    不支持
    NOW() - INTERVAL 1 HOUR
    NOW() - INTERVAL 1 HOUR
    ,必须写具体时间字符串
  • 三种手段各有适用场景:误删部分行用精准补回(不影响新数据);误改全表用 RESTORE(简单但会覆盖新数据);误删整表用 UNDROP(最快)
  • 保留周期决定可恢复窗口:默认 1 天,重要表提前用
    data_retention_days
    data_retention_days
    延长,最长 90 天
  • Lakehouse 有写操作安全保护:不带 WHERE 的 DELETE/UPDATE 会被拒绝,但 WHERE 条件过宽的误操作仍会执行,Time Travel 是最后一道防线

相关文档

联系我们
预约咨询
微信咨询
电话咨询