数据误操作恢复:用 Time Travel 找回删除和改错的数据
业务背景
数据误操作是每个数据团队都会遇到的事故:运营同学手滑删了一批订单、开发同学 UPDATE 时 WHERE 条件写宽了改错了金额、DBA 误执行了 DROP TABLE。传统数据库遇到这类问题,要么从备份恢复(慢,且会丢失备份后的数据),要么靠 binlog 重放(复杂,需要 DBA 介入)。
Lakehouse 的 Time Travel 功能让数据恢复变成一条 SQL 的事:每次写操作都会生成一个新版本,历史版本默认保留 1 天(可配置最长 90 天),你可以随时查询任意历史时间点的数据,也可以一键回滚整张表。
三种恢复手段,对应三种事故类型:
事故类型 恢复手段 适用场景 误删部分行(DELETE) INSERT INTO ... SELECT ... TIMESTAMP AS OFINSERT INTO ... SELECT ... TIMESTAMP AS OF
只补回被删的行,不影响误删后写入的新数据 误改数据(UPDATE) RESTORE TABLE ... TO TIMESTAMP AS OFRESTORE TABLE ... TO TIMESTAMP AS OF
整张表回滚到指定时间点 误删整张表(DROP) UNDROP TABLEUNDROP TABLE
恢复被删除的表及其全部数据
涉及的 SQL 命令
命令 用途 DESC HISTORYDESC HISTORY
查看表的版本历史,找到误操作前的时间点 SELECT ... TIMESTAMP AS OFSELECT ... TIMESTAMP AS OF
查询指定时间点的历史数据 INSERT INTO ... SELECT ... TIMESTAMP AS OFINSERT INTO ... SELECT ... TIMESTAMP AS OF
从历史版本补回被删的行 RESTORE TABLE ... TO TIMESTAMP AS OFRESTORE TABLE ... TO TIMESTAMP AS OF
整张表回滚到指定时间点 UNDROP TABLEUNDROP 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 HISTORYDESC 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:272026-05-28 19:45:27
,后续恢复时会用到。
⚠️ 注意 :
TIMESTAMP AS OFTIMESTAMP AS OF
只接受常量字面量,不支持
NOW() - INTERVAL 1 HOURNOW() - INTERVAL 1 HOUR
这类表达式。需要查询"N 分钟前"的数据,必须先通过
DESC HISTORYDESC HISTORY
查到具体时间戳,再用字面量查询。
场景一:误删部分行,精准补回
运营同学执行了一条 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:2719: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 INNOT 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 条数据。这种方式的优势是:如果误删后有新数据写入,新数据不会被覆盖。
💡 提示 :时间戳要选在误操作发生后、目标版本写入完成后的时间点。
DESC HISTORYDESC HISTORY
返回的
timetime
字段是版本写入完成的时间,查询时用该时间戳加 1 秒可以确保命中该版本。
场景二:误改数据,整表回滚
开发同学执行 UPDATE 时 WHERE 条件写得太宽,把所有订单金额都乘以了 10:
UPDATE doc_orders SET amount = amount * 10
WHERE order_time > CAST('2026-01-01' AS TIMESTAMP);
💡 提示 :Lakehouse 对不带 WHERE 的 DELETE/UPDATE 有安全保护,会直接报错拒绝执行。但 WHERE 条件过于宽泛(如覆盖全表)的误操作仍然会执行成功,需要人工判断。
第一步:确认误操作版本
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:2119: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 的状态,金额恢复正常。
⚠️ 注意 :
RESTORE TABLERESTORE TABLE
会覆盖表的当前状态,回滚后在误操作之后写入的新数据也会丢失。如果误操作后有合法的新数据写入,应使用场景一的精准补回方式,而不是整表回滚。
场景三:误删整张表,UNDROP 恢复
DBA 误执行了 DROP TABLE:
DROP TABLE doc_orders;
表消失,查询报错
table or view not foundtable or view not found
。
一条命令恢复 :
UNDROP TABLE doc_orders;
执行后表及其全部数据立即恢复,版本历史也完整保留。
⚠️ 注意 :
UNDROP TABLEUNDROP TABLE
在保留周期内(默认 1 天)有效。超过保留周期后,历史版本被清理,无法恢复。对于重要的表,建议提前设置更长的保留周期:
ALTER TABLE doc_orders SET PROPERTIES ('data_retention_days' = '7');
💡 提示 :无论删除的是普通表、Dynamic Table、物化视图还是 Table Stream,恢复时统一使用
UNDROP TABLEUNDROP TABLE
语法。
清理资源
DROP TABLE IF EXISTS doc_orders;
关键点总结
先查 DESC HISTORYDESC HISTORY
,再操作 :恢复前必须确认目标版本的时间戳,不要凭记忆估算时间
时间戳只接受字面量 :TIMESTAMP AS OFTIMESTAMP AS OF
不支持 NOW() - INTERVAL 1 HOURNOW() - INTERVAL 1 HOUR
,必须写具体时间字符串
三种手段各有适用场景 :误删部分行用精准补回(不影响新数据);误改全表用 RESTORE(简单但会覆盖新数据);误删整表用 UNDROP(最快)
保留周期决定可恢复窗口 :默认 1 天,重要表提前用 data_retention_daysdata_retention_days
延长,最长 90 天
Lakehouse 有写操作安全保护 :不带 WHERE 的 DELETE/UPDATE 会被拒绝,但 WHERE 条件过宽的误操作仍会执行,Time Travel 是最后一道防线
相关文档