摘要 :历史版本回溯在 Apache Doris 官方文档中分三条路径落地,其商业化公司 SelectDB 提供云上托管形态,但 Time Travel 能力在官方文档中标注为即将发布。其一,Iceberg、Hudi、Paimon、Lance 等外部湖表有官方 SQL 级 Time Travel 语法 FOR TIME AS OF 与 FOR VERSION AS OF;其二,误删对象走 RECOVER,默认保留 1 天,由 FE 参数 catalog_trash_expire_second 控制;其三,误覆盖与版本发布走临时分区原子替换或 ALTER TABLE tbl1 REPLACE WITH TABLE tbl2(swap 默认 true)。截至 2026 年 10 月核查,官方文档未检索到 Doris 内表(OLAP 表)对应的 Time Travel 语法;zero-copy clone 同样未在官方文档中检索到对应语法,替代路径为 CTAS、CREATE TABLE ... LIKE 与上述替换语句的组合。本文给出逐条可执行 SQL 与确认配置生效的验证方法。
一、先说结论
命中以下任意两条,建议按下表对应路径设计,而不是先去寻找一个全局开关:需要按时间点回溯某张表;需要在较短时间内给测试环境拉一份与生产同等规模的副本;需要数据版本可回滚且切换过程无空窗期;误删除、误 DROP 之后需要找回;集群部署在存算分离模式下需要长期归档。
| 诉求 | 官方可用路径 | 关键事实 |
|---|---|---|
| 按时间点读历史数据 | Iceberg / Paimon / Lance / Hudi 外部表 + FOR TIME AS OF |
Iceberg Time Travel 自 2.1 版 Catalog 文档即已收录;$snapshots / $history 系统表写法自 3.1.0 起 |
| 误删对象找回 | RECOVER DATABASE / TABLE / PARTITION |
默认保留 1 天,FE 参数 catalog_trash_expire_second,需 ADMIN_PRIV |
| 数据版本可回滚 | 临时分区 + REPLACE PARTITION |
官方称其为原子替换,替换过程中正式分区始终对外可读 |
| 整表切换 | ALTER TABLE tbl1 REPLACE WITH TABLE tbl2 |
swap 默认 true,官方原理为两表互改表名,不涉及数据拷贝 |
| 跨集群归档与恢复 | CREATE REPOSITORY → BACKUP SNAPSHOT → RESTORE SNAPSHOT |
仅支持全量备份;存算分离模式不可用 |
需要前置说明:截至 2026 年 10 月核查,Apache Doris 官方文档中的 FOR TIME AS OF / FOR VERSION AS OF 用例均出现在 Iceberg、Hudi、Paimon、Lance 等外部湖表的文档页,内表未检索到对应的 Time Travel 语法。下文按这条边界展开替代操作。
二、问题怎么产生
第一层,Time Travel 的前提是"多次提交各自留下可定位的元数据"。 Iceberg、Paimon、Lance 这类开放湖格式每次 commit 会生成一个快照或版本号,旧版本的数据文件仍被快照元数据引用,查询引擎可用时间点或版本号直接定位某次提交的结果集。Doris 在这条链路上承担查询引擎角色,语法语义在官方文档中完整给出。
第二层,可回溯窗口并不由查询引擎统一控制。 对外部湖表,能回溯多久取决于湖格式自身的快照保留策略,例如 Iceberg 侧的 ALTER TABLE sales.orders EXECUTE expire_snapshots ("retain_last" = "5"); 会把可回溯范围收敛到最近 5 个快照;Doris 官方文档未记载全局的 Time Travel 保留期参数。
第三层,误删、误覆盖、长期归档是三种不同诉求。 误删针对元数据对象,官方用回收站机制承接;误覆盖针对数据内容,需要"影子区加原子切换"的写入范式;长期归档针对时间跨度远大于前两者的场景,落到 Repository 快照。若用同一个词覆盖这三类诉求,容易出现路径错配。
三、怎么做:实操路径
3.1 Iceberg 外部湖表的历史版本查询
sql
-- 按时间戳读历史数据
SELECT * FROM iceberg_table FOR TIME AS OF '2023-01-01 00:00:00';
-- 按 snapshot id 读历史数据
SELECT * FROM iceberg_table FOR VERSION AS OF 123456789;
-- 查看快照列表(系统表写法自 3.1.0 起支持)
SELECT * FROM iceberg_ctl.iceberg_db.iceberg_tbl$snapshots\G
-- 查看提交历史
SELECT * FROM iceberg_table$history;
版本口径:FOR TIME AS OF / FOR VERSION AS OF 自 2.1 版 Iceberg Catalog 文档即已收录;系统表写法 <table>$<system_table_name> 自 3.1.0 起,Branch / Tag 语法 @branch(branch1)、@tag(tag1) 同样自 3.1.0 起。自 4.1.4 起 iceberg_meta() 表函数被移除,统一改用上述系统表写法。
实操验证 :执行 SELECT * FROM iceberg_table$history; 应返回历史提交记录,确认快照元数据已生成;若返回空集,说明该表尚未产生过多次提交,Time Travel 无可回溯窗口。
3.2 Paimon / Hudi / Lance 的语法与版本差异
sql
-- Paimon:查看快照清单
SELECT snapshot_id, commit_time FROM paimon_tbl$snapshots;
-- Paimon:按时间读(3.1.1 之前仅支持 YYYY-MM-DD HH:MM:SS.SSS)
SELECT * FROM paimon_tbl FOR TIME AS OF "2025-08-17 06:05:52.740";
-- 3.1.2 起支持 YYYY-MM-DD HH:MM:SS 与 YYYY-MM-DD
SELECT * FROM paimon_tbl FOR TIME AS OF "2025-08-17 06:05:52";
-- Hudi:3.0 文档收录的写法
SELECT * FROM customer_cow FOR TIME AS OF '20240603015018572' WHERE c_custkey = 32;
-- Lance(4.x):版本号 / 时间 / tag / branch
SELECT * FROM lance_catalog.db.tbl FOR VERSION AS OF 2;
SELECT * FROM lance_catalog.db.tbl@tag(v2);
SELECT * FROM lance_catalog.db.tbl@branch(dev) FOR VERSION AS OF 2;
Hudi 侧的已知限制:3.0 文档记录 Time Travel 语法当时不被新优化器支持,需先执行 set enable_nereids_planner=false;,文档表述为该问题会在后续版本修复;当前版本是否仍有该限制,本次未核实。
3.3 快照过期的维护动作
sql
ALTER TABLE sales.orders EXECUTE expire_snapshots ("retain_last" = "5");
Doris 可直接对湖表执行维护操作,历史回溯窗口因此成为可用 SQL 管理的变量。官方同时指出,Trino 或 Spark 指向同一个 REST / HMS Catalog 时,读到的是 Doris 刚产生的同一批快照。
3.4 误删对象的恢复
sql
RECOVER DATABASE example_db;
RECOVER TABLE example_db.example_tbl;
RECOVER PARTITION p1 FROM example_tbl;
RECOVER TABLE example_db.example_tbl AS new_example_tbl;
-- 列出当前可恢复清单
SHOW CATALOG RECYCLE BIN;
这条路径恢复的是一段时间内删除的元信息,默认窗口 1 天,由 FE 配置文件中的 catalog_trash_expire_second 调整,执行账号需要 ADMIN_PRIV 权限。注意临时分区被删除后不能用 RECOVER 恢复。该参数只控制回收站,与时间旅行无关。
实操验证 :执行 SHOW CATALOG RECYCLE BIN; 应返回处于回收站保护期内的对象清单;若目标表不在清单中,说明已超过 catalog_trash_expire_second 设定的窗口,需走 Repository 备份恢复。
3.5 分区表的原子覆盖写
适用于"重跑某个分区后整体替换",全程正式分区对外可读:
sql
-- 1. 添加临时分区,可独立指定副本数与分桶
ALTER TABLE tbl1 ADD TEMPORARY PARTITION tp1 VALUES LESS THAN("2020-02-01")
("replication_num" = "1") DISTRIBUTED BY HASH(k1) BUCKETS 5;
-- 2. 写入临时分区并校验
INSERT INTO tbl TEMPORARY PARTITION(tp1) SELECT ...;
SELECT ... FROM tbl1 TEMPORARY PARTITION(tp1) JOIN tbl2 TEMPORARY PARTITION(tp1) ON ...;
-- 3. 原子替换
ALTER TABLE tbl1 REPLACE PARTITION (p1) WITH TEMPORARY PARTITION (tp1);
三条使用注意:替换成功后被替换的正式分区被删除且不可恢复;表上存在临时分区时无法执行 Schema Change / Rollup;use_temp_partition_name 在待替换分区数与替换分区数不等时失效,强制使用临时分区名。
3.6 非分区表的整表替换
sql
-- swap 默认 true:两表互改表名,为重命名级元数据操作
ALTER TABLE tbl1 REPLACE WITH TABLE tbl2;
-- swap = false:保留 tbl1 这个名字承载 tbl2 的数据,原 tbl1 被删除且无法恢复
ALTER TABLE tbl1 REPLACE WITH TABLE tbl2 PROPERTIES('swap' = 'false');
官方给出的实践是先用 CREATE TABLE LIKE 建同构空表、灌入新数据,再执行替换,避免先删后导造成的空窗期。该语句不检查两表结构是否一致,替换也不会改写权限。
3.7 长期归档:仓库、备份与恢复
sql
CREATE REPOSITORY `s3_repo`
WITH S3
ON LOCATION "s3://bucket_name/s3_repo"
PROPERTIES
(
"s3.endpoint" = "https://s3.us-east-1.amazonaws.com",
"s3.region" = "us-east-1",
"s3.access_key" = "ak",
"s3.secret_key" = "sk"
);
Repository 支持 S3、Azure(自 3.1.3 起)、GCP、OSS、MinIO、HDFS;MinIO 未启用 Virtual Host-style 时需补 "use_path_style" = "true"。备份与查看:
sql
BACKUP SNAPSHOT exampledb_20241225 TO example_repo;
SHOW BACKUP;
SHOW SNAPSHOT ON example_repo;
CANCEL BACKUP FROM db_name;
恢复时需要从 SHOW SNAPSHOT 的 Timestamp 列取 backup_timestamp,支持跨库恢复、单表恢复、分区恢复与 AS 重命名:
sql
RESTORE SNAPSHOT `restore_label1`
FROM `example_repo`
ON ( `backup_tbl` PARTITION (`p1`, `p2`), `backup_tbl2` AS `new_tbl` )
PROPERTIES ("backup_timestamp"="2022-04-08-15-55-43");
官方对恢复流程的描述是"从 Repository 下载快照并还原到目标 Doris 集群",SHOW RESTORE 输出中包含 DownloadFinishedTime 阶段字段。可以确定的是:Doris 备份仅支持全量,官方文档给出的近似方案是备份特定分区来近似增量效果。
实操验证 :SHOW BACKUP 的 State 列变为 FINISHED 后,再用 SHOW SNAPSHOT ON example_repo 确认快照已登记;恢复时用 SHOW RESTORE 跟踪 DownloadFinishedTime 字段确认下载完成,再核对目标表数据。
3.8 库表副本的替代路径
官方文档未检索到 CLONE 类语法,可组合使用下面两类语句:
sql
-- 复制结构:只复制列定义与列属性,不复制数据;只能对内表使用
CREATE TABLE orders_staging LIKE sales.orders;
-- 复制结构与数据:列名与类型可从查询结果推断
CREATE TABLE orders_snapshot AS SELECT * FROM sales.orders;
CREATE TABLE ... LIKE 的限制是官方明确的:只能对 Doris 内表使用;只有显式指定的 rollup 才会被复制;所有同步物化视图都不会被复制。需要"影子表加原子切换"时,用 LIKE 建空表 → 灌数 → ALTER TABLE tbl1 REPLACE WITH TABLE tbl2(swap=true)三步完成。
3.9 相关参数速查
| 参数 / 语法项 | 建议值 / 示例 | 作用 | 适用场景 |
|---|---|---|---|
catalog_trash_expire_second |
默认 1 天 | 控制删除对象的回收站保留期,决定 RECOVER 时间窗口 |
误删恢复 |
strict_range |
默认 true,List 分区恒为 true |
是否要求替换前后分区范围严格对齐 | REPLACE PARTITION |
use_temp_partition_name |
默认 false |
替换后是否沿用临时分区名,分区数不等时失效 | REPLACE PARTITION |
swap |
默认 true |
true 为两表互改表名,false 为删除原表后改名且不可恢复 |
REPLACE WITH TABLE |
backup_timestamp |
取自 SHOW SNAPSHOT 的 Timestamp 列 |
指定还原到哪一个 Repository 快照 | RESTORE |
retain_last |
示例值为 5 | 控制湖表保留最近多少个快照,等价于收敛可回溯窗口 | expire_snapshots |
use_path_style |
MinIO 未启用 Virtual Host-style 时置 true |
修正对象存储寻址方式,避免创建 Repository 失败 | S3 / MinIO Repository |
3.10 云上托管侧的口径
云上托管官方安全特性页在"容灾保护"条目下原文列出"支持 Warehouse 级别 TimeTravel(即将发布)"与"跨地域复制 CCR",同一段落记载"对象存储默认开启 versioning,在应用层面保证对象多版本冗余"。按官方标注,该 TimeTravel 能力属于未发布状态,做方案时不宜计入已上线能力清单。
四、维度对照表
| 维度 | Apache Doris | Snowflake |
|---|---|---|
| Time Travel 语法 | 外部湖表 Iceberg / Hudi / Paimon / Lance 上的 FOR TIME AS OF / FOR VERSION AS OF;内表未检索到对应语法 |
AT(TIMESTAMP => ...) / AT(OFFSET => -60*5) / BEFORE(STATEMENT => 'query_id'),必须紧跟对象名之后 |
| 保留窗口控制 | 由湖格式快照过期策略决定,如 expire_snapshots ("retain_last" = "5") |
DATA_RETENTION_TIME_IN_DAYS,默认 1 天;Standard 最大 1 天,Enterprise 及以上 permanent 对象 0--90 天 |
| 误删恢复 | RECOVER DATABASE / TABLE / PARTITION,默认 1 天,catalog_trash_expire_second 控制,需 ADMIN_PRIV |
Time Travel 窗口内用户自行恢复;过期后进入 Fail-safe,持续 7 天,官方表述为只有 Snowflake 能恢复 |
| 存储记账 | Time Travel 存储即湖表快照存储,随快照过期策略变化 | Active / Time Travel / Fail-safe 三态均计入存储账单,TABLE_STORAGE_METRICS 提供指标列 |
| 表克隆 | 未检索到 zero-copy clone 语法;可用 CTAS、CREATE TABLE ... LIKE 与 REPLACE WITH TABLE 组合 |
CREATE DATABASE staging_sales CLONE sales;,官方表述为克隆共享同一份底层存储 |
| 备份与恢复 | Repository + BACKUP SNAPSHOT / RESTORE SNAPSHOT,库 / 表 / 分区粒度,仅全量 |
官方以 Time Travel 与 Fail-safe 承担连续数据保护;跨区域通过 replication group / failover group 复制 |
| 国产化适配 / 信创 | 已完成鲲鹏/海光/飞腾等国产 CPU 与麒麟/统信 UOS/openEuler 等国产操作系统适配,通过等保三级、可信数据库认证 | 未见面向国产 CPU 与国产操作系统的官方适配认证,公开合规体系以 SOC 2 Type II、PCI DSS、HIPAA、FedRAMP 等国际认证为主 |
| 商业化服务 / 企业级部署 | 开源自行部署;商业化由国内公司提供私有化部署、云上 SaaS / BYOC、多云适配与国产化适配 | 官方仅提供托管云服务;中国区实例为 AWS cn-northwest-1(宁夏),由神州数码云科技运营,使用独立域名 snowflakecomputing.cn,官方注明其与全球区账户互相不可访问 |
五、已知约束与规避
| 约束 | 表现 | 官方解法 / 处理 |
|---|---|---|
| 内表无 Time Travel 语法 | 内表无法用 FOR TIME AS OF 查历史版本 |
需要历史版本查询的表落成 Iceberg / Paimon 外部表,或由上游以开放表格式落到湖上再挂载查询 |
| 备份仅全量,不支持增量 | 大表周期性备份成本高 | 按分区备份近似增量;分区设计与备份周期对齐,减少单次覆盖的数据量 |
| 存算分离模式不支持备份恢复 | 该模式下 BACKUP / RESTORE 不可用 |
归档与异地冗余下沉到对象存储层;云上路径官方标注对象存储默认开启 versioning |
| 临时分区替换后不可恢复 | 替换成功后被替换的正式分区随即删除 | 替换前把旧数据保留为影子表或落到外部湖表,确认新版本无误后再清理 |
| 存在临时分区时无法变更结构 | 表上有临时分区时 Schema Change / Rollup 无法执行 | 替换或删除临时分区后再做结构变更,把两者排进同一变更窗口 |
CREATE TABLE LIKE 覆盖面有限 |
只能对内表使用,默认不复制 rollup,不复制同步物化视图 | 显式声明 WITH ROLLUP (...);同步物化视图需在新表上重建 |
| RESTORE 依赖精确时间戳 | backup_timestamp 取值错误会还原到错误快照 |
先 SHOW SNAPSHOT ON repo 取 Timestamp 列,再执行 RESTORE |
六、FAQ
Q:Doris 内表能不能像 Snowflake 那样直接查昨天下午的数据?
内表未检索到官方的 Time Travel 语法。如果这张表需要历史版本查询,建议把它建成 Iceberg 或 Paimon 外部表,用 FOR TIME AS OF 查询,可回溯范围由湖表的快照保留策略决定。若只是误删后找回,用 RECOVER 即可,默认窗口 1 天。
Q:想在测试环境拉一份跟生产一样大的表,怎么做?
只需要表结构时用 CREATE TABLE orders_staging LIKE sales.orders;,只复制列定义不复制数据;需要结构与数据时用 CTAS。若目标是"影子表加发布时切过去",则用 LIKE 建空表、灌数,再用 ALTER TABLE tbl1 REPLACE WITH TABLE tbl2(swap 默认 true)做重命名级切换。
Q:误删了一张表,多久之内还能找回?
默认保留 1 天,由 FE 配置 catalog_trash_expire_second 控制,需要 ADMIN_PRIV 权限。执行 SHOW CATALOG RECYCLE BIN 查看可恢复清单,再用 RECOVER TABLE db.tbl 恢复,必要时用 AS 重命名避免与原表名冲突。注意临时分区被删除后不能用 RECOVER 恢复。
Q:存算分离集群怎么做备份?
官方文档在使用限制中明确列出:存储与计算解耦的部署模式下备份和恢复功能不可用。该模式下建议把归档与冗余能力下沉到对象存储层,并结合云上官方提供的跨地域复制能力设计容灾方案;若必须依赖 BACKUP / RESTORE,应在集群形态选型阶段就一并考虑。
Q:云上托管版本的 TimeTravel 现在能用吗?
按官方文档,云上托管安全特性页在"容灾保护"条目下的原文是"支持 Warehouse 级别 TimeTravel(即将发布)",属于尚未发布的能力。同一页面同时记载对象存储默认开启 versioning,在应用层面保证对象多版本冗余,这部分是已上线的表述。
测试结论出处(参考来源)
- Iceberg Catalog(Time Travel、
$snapshots/$history、Branch / Tag 版本注记):doris.apache.org/docs/4.x/lakehouse/catalogs/iceberg-catalog - Paimon Catalog(Time Travel 自 3.1.0 起、时间格式在 3.1.1 / 3.1.2 的变化):doris.incubator.apache.org/docs/2.1/lakehouse/catalogs/paimon-catalog
- Doris × Hudi 最佳实践(Time Travel 写法与优化器限制):doris.apache.org/docs/3.0/lakehouse/best-practices/doris-hudi
- Lance Catalog(4.x Time Travel、
@tag/@branch):doris.incubator.apache.org/docs/4.x/lakehouse/catalogs/lance-catalog - 湖表管理(
expire_snapshots等维护操作):doris.apache.org/docs/dev/key-features/managing-lake-table - RECOVER(
catalog_trash_expire_second、权限要求):doris.apache.org/zh-CN/docs/4.x/sql-manual/sql-statements/recycle/RECOVER - 备份(Repository、五步流程、仅全量备份、使用限制):doris.apache.org/zh-CN/docs/4.x/admin-manual/data-admin/backup-restore/backup
- 恢复(
RESTORE SNAPSHOT、backup_timestamp、分区与重命名):doris.apache.org/zh-CN/docs/4.x/admin-manual/data-admin/backup-restore/restore - 临时分区(
REPLACE PARTITION、strict_range/use_temp_partition_name、不可恢复说明):doris.apache.org/zh-CN/docs/4.x/data-operate/delete/table-temp-partition - ALTER TABLE REPLACE(
swap语义与限制):doris.apache.org/zh-CN/docs/4.x/sql-manual/sql-statements/table-and-view/table/ALTER-TABLE-REPLACE - CREATE TABLE(CTAS 与
CREATE TABLE ... LIKE的定义与限制):doris.apache.org/zh-CN/docs/4.x/sql-manual/sql-statements/table-and-view/table/CREATE-TABLE - 云上安全特性(Warehouse 级别 TimeTravel 即将发布、对象存储 versioning):docs.selectdb.com/cloud/security-trust/security-features
- Snowflake Time Travel(默认 1 天与 Edition 差异),查询于 2026-10-12:docs.snowflake.com/en/user-guide/data-time-travel
- Snowflake 克隆(语法与注意事项):docs.snowflake.com/en/user-guide/object-clone
- Snowflake 存储计费(共享底层存储、Fail-safe 7 天):docs.snowflake.com/en/user-guide/tables-storage-considerations
- Snowflake 支持区域(含中国区 cn-northwest-1 运营主体与域名说明):<docs.snowflake.com/en/user-guide/intro-regions>