對于Delta Table類型的表,MaxCompute支持查詢回溯到源表某個歷史時間或者版本進行歷史Snapshot查詢(Time travel查詢),也支持指定源表某個歷史時間區間或者版本區間進行歷史增量查詢(Incremental查詢)。本文為您介紹Delta Table的查詢使用說明和使用限制。
命令格式
[WITH <cte>[, ...] ]
SELECT [ALL | DISTINCT] <select_expr>[, <except_expr>)][, <replace_expr>] ...
FROM <table_reference>
[TIMESTAMP | VERSION AS OF expr]
[TIMESTAMP | VERSION BETWEEN start_expr AND end_expr]
[WHERE <where_condition>]
[GROUP BY {<col_list> | ROLLUP(<col_list>)}]
[HAVING <having_condition>]
[ORDER BY <order_condition>]
[DISTRIBUTE BY <distribute_condition> [SORT BY <sort_condition>]|[ CLUSTER BY <cluster_condition>] ]
[LIMIT <number>]
[WINDOW <window_clause>]
SQL DQL語法基本支持了查詢Delta Table的所有場景,并基本遵循MaxCompute DQL語法以及對應的約束。只增加了From Table子句的語法增強,可以通過固定格式的表達式指定源表某個歷史時間或者版本進行歷史Snapshot查詢,也可以指定源表某個歷史時間區間或者版本區間進行歷史增量查詢。
Time travel查詢參數與使用限制
Time travel查詢Delta Table,回溯到源表某個歷史時間或者版本進行歷史Snapshot查詢。您可通過[TIMESTAMP | VERSION AS OF expr]
來配置具體的查詢方式。
TIMESTAMP AS OF expr
參數說明
TIMESTAMP AS OF
為固定語法格式,代表根據歷史時間查詢歷史snapshot數據 。expr
的取值類型可為MaxCompute標準的TIMESTAMP、DATETIME或DATE類型,目前可支持的形式有:日期字符串常量:
TIMESTAMP
、DATETIME
和DATE
類型的字符串常量,示例如下。數據類型
示例
TIMESTAMP
'2023-01-01 00:00:00.123'
DATETIME
'2023-01-01 00:00:00'
DATE
'2023-01-01'
MaxCompute內置時間函數:
current_timestamp()
、getDate() + N: current_timestamp()
和getDate()
。其中N的單位是秒,N為負數,表示當前時間往前N秒。N為正數,表示當前時間往后N秒。
Delta Table特殊語法:
get_latest_timestamp(string tablename [, bigint <number>])
。如果是跨Project訪問,
tablename
需寫為ProjectName.TableName
。如果是三層模型,
tablename
需寫為ProjectName.SchemaName.TableName
。number
可不填,默認值為1,表示時間從后往前序列中第number次數據操作的Commit時間,比如1表示最后一次操作,其中數據操作包括用戶側主動發送的數據修改操作和系統內部發起的數據排布操作。不同的number參數返回的TIMESTAMP可能相同。
使用限制
查詢的歷史快照數據范圍為
[CreateTableTimestamp, expr]
,比較對象為每次DML操作生成的Commit時間,CreateTableTimestamp為表創建操作生成的Commit時間。expr
返回的時間早于Time travel時間周期(即創建Delta Table時配置的acid.data.retain.hours
),或早于Delta Table表創建時間,會直接報錯,因為對應的歷史數據狀態可能不存在了,比如acid.data.retain.hours=72
小時,expr為72小時之前的時間,就會報錯。expr
返回的時間如果正好處于Time travel時間周期(即創建Delta Table時配置的acid.data.retain.hours
)的下限,由于內部系統之間交互也有延時,所以有概率出現秒級的誤差,導致報錯,所以盡量不要使用類似于 (TIMESTAMP AS OF current_timestamp() - time travel時間周期
) 的語法,容易觸發報錯。
VERSION AS OF expr
參數說明
VERSION AS OF
為固定語法格式,代表根據歷史數據操作的版本號(version)查詢歷史Snapshot數據。expr
返回類型為MaxCompute的bigint整型,目前可支持的形式有:整型常量:
比如常量
3
。Delta Table特殊語法:
get_latest_version(string tablename [, bigint <number>])
如果是跨Project訪問,
tablename
需寫為ProjectName.TableName
。如果是三層模型,
tablename
需寫為ProjectName.SchemaName.TableName
。number
可不填,默認值為1,表示時間從后往前序列中第number次數據操作的版本號,比如1表示最后一次操作,其中數據操作包括用戶側主動發送的數據修改操作和系統內部發起的數據排布操作。不同的number參數返回的VERSION
不相同。
使用限制
每次DML操作會產生嚴格遞增的version,您可通過
SHOW HISTORY FOR TABLE/PARTITION
顯示所有DML操作信息,從中獲取對應操作的version。查詢的歷史快照數據范圍為
[CreateTableVersion, expr]
,比較對象為每次DML操作對應的version。CreateTableVersion
為表創建操作產生的version,默認為1。expr
返回的version,系統會獲取它對應的DML Commit時間,如果早于配置的Time travel時間周期(即創建Delta Table時配置的acid.data.retain.hours
),或者version值小于1,會直接報錯。expr
返回的version大于最近一次DML操作的version,直接報錯,推薦通過get_latest_version
函數來獲取所需的版本號。
Incremental查詢參數與使用限制
Incremental查詢Delta Table,指定源表某個歷史時間區間或者版本區間進行歷史增量查詢。您可通過[TIMESTAMP | VERSION BETWEEN start_expr AND end_expr]
來配置具體的查詢方式。
TIMESTAMP BETWEEN start_expr AND end_expr
參數說明
TIMESTAMP BETWEEN AND
:為固定語法格式,代表根據歷史時間區間查詢歷史增量數據。start_expr
和end_expr
用法以及約束同TIMESTAMP AS OF
語法的EXPR
保持一致。
使用限制
查詢的歷史增量數據范圍為
(start_expr,end_expr]
,即左開右閉區間,比較對象為每次DML操作生成的Commit時間。start_expr
早于配置的Time travel時間周期(acid.data.retain.hours
),或者早于表創建時間,會直接報錯。end_expr
晚于最近一次DML操作的Commit時間時,查詢行為結果根據表屬性(acid.incremental.query.out.of.time.range.enabled
)的取值來決定:設置為false(默認值)時,會直接報錯。
設置為true時,會查詢包含
(start_expr,end_expr]
范圍內的所有增量歷史數據。您可通過
ALTER TABLE
修改此參數的取值,例如:ALTER TABLE mf_tt2 SET tblproperties("acid.incremental.query.out.of.time.range.enabled"="true");
VERSION BETWEEN start_expr AND end_expr
參數說明
VERSION BETWEEN AND
為固定語法格式,代表根據歷史DML操作的version區間查詢歷史增量數據。start_expr
和end_expr
用法以及約束同VERSION AS OF
語法的expr
保持一致,參考上面描述。
使用限制
查詢的歷史增量數據范圍是(start_expr,end_expr],即左開右閉區間,比較對象為每次DML操作生成的version。
start_expr
返回的version,系統會獲取它對應的DML Commit時間,如果早于配置的Time travel時間周期(acid.data.retain.hours
)或者version值小于1,會直接報錯。end_expr
返回的version晚于最近一次DML操作的version的行為通過表屬性(acid.incremental.query.out.of.time.range.enabled
)來決定,默認值為false,會直接報錯。如果設置為true,會查詢包含(start_expr,end_expr]范圍內的所有增量歷史數據。
其他使用說明
相同Key的多行記錄,只返回最近的一行記錄,如果最后一行是Delete狀態,直接過濾掉。后續版本考慮支持類似CDC格式的數據更新狀態查詢。
不支持表對象不存在的表的歷史數據查詢,例如對表進行Drop、Rename等刪除操作。
此種情況下您可先通過Restore操作恢復表對象,然后再繼續查詢。
目前只支持Delta Table的Time travel/Incremental查詢,其他表不支持。
同一個SQL中的同一張表,對于Time travel和Incremental查詢,
timestamp
或者version
必須相同。分區表查詢最好指定partition,避免查詢所有partition的歷史操作日志導致耗時不穩定。
讀寫并發事務采用MVCC模型,可保障讀寫隔離,相互不影響,支持ReadCommited級別。
Compaction操作生成數據不認為是新增數據,因此增量查詢出來的數據不會包含。
使用示例
示例數據。
--創建表操作,產生的version為1,執行show history for table mf_tt2, 可查詢version; CREATE TABLE mf_tt2 ( pk bigint NOT NULL PRIMARY KEY, val bigint NOT NULL) PARTITIONED BY (dd string, hh string) tblproperties ("transactional"="true"); --DML操作,產生的version為2 INSERT OVERWRITE TABLE mf_tt2 PARTITION (dd='01', hh='01') VALUES (1, 1), (2, 2), (3, 3); --DML操作,產生的version為3 INSERT INTO TABLE mf_tt2 PARTITION (dd='01', hh='01') VALUES (3, 30), (4, 4), (5, 5);
表相關數據查詢。
查詢表創建時間,作為后續設置查詢歷史時間的參考。
DESC EXTENDED mf_tt2;
返回結果如下。
+------------------------------------------------------------------------------------+ | Owner: ALIYUN$****_doctest@test.aliyunid.com | Project: doc_test_prod | | TableComment: | +------------------------------------------------------------------------------------+ | CreateTime: 2023-06-26 09:31:38 | | LastDDLTime: 2023-06-26 09:31:38 | | LastModifiedTime: 2023-06-26 09:32:31 | +------------------------------------------------------------------------------------+ | InternalTable: YES | Size: 8541 | +------------------------------------------------------------------------------------+ | Native Columns: | +------------------------------------------------------------------------------------+ | Field | Type | Label | ExtendedLabel | Nullable | DefaultValue | Comment | +------------------------------------------------------------------------------------+ | pk | bigint | | | false | NULL | | | val | bigint | | | false | NULL | | +------------------------------------------------------------------------------------+ | Partition Columns: | +------------------------------------------------------------------------------------+ | dd | string | | | hh | string | | +------------------------------------------------------------------------------------+ | Extended Info: | +------------------------------------------------------------------------------------+ | TableID: bec515a56cc9492c8f906a224c62**** | | IsArchived: false | | PhysicalSize: 25623 | | FileNum: 9 | | StoredAs: AliOrc | | CompressionStrategy: normal | | ClusterType: hash | | BucketNum: 16 | | ClusterColumns: [pk] | | SortColumns: [pk ASC] | +------------------------------------------------------------------------------------+
查詢歷史數據操作的版本號。
SHOW HISTORY FOR TABLE mf_tt2 PARTITION (dd='01',hh='01');
返回結果如下。
ID = 20230626021756157ghict5k**** ObjectType ObjectId ObjectName VERSION(LSN) Time Operation PARTITION 4764c8e1cb634a4fb9c21f3fc850**** dd=01/hh=01 0000000000000002 2023-06-26 09:31:56 CREATE PARTITION 4764c8e1cb634a4fb9c21f3fc850**** dd=01/hh=01 0000000000000003 2023-06-26 09:32:32 APPEND
Time travel查詢示例。
查詢截止到指定時間(例如datetime格式的字符串常量)的所有歷史數據。
SELECT * FROM mf_tt2 TIMESTAMP AS OF '2023-06-26 09:33:00' WHERE dd = '01' AND hh = '01';
返回結果如下。
+------------+------------+----+----+ | pk | val | dd | hh | +------------+------------+----+----+ | 1 | 1 | 01 | 01 | | 3 | 30 | 01 | 01 | | 4 | 4 | 01 | 01 | | 5 | 5 | 01 | 01 | | 2 | 2 | 01 | 01 | +------------+------------+----+----+
查詢截止到指定version常量的所有歷史數據。
SELECT * FROM mf_tt2 VERSION AS OF 2 WHERE dd = '01' AND hh = '01';
返回結果如下。
+------------+------------+----+----+ | pk | val | dd | hh | +------------+------------+----+----+ | 1 | 1 | 01 | 01 | | 3 | 3 | 01 | 01 | | 2 | 2 | 01 | 01 | +------------+------------+----+----+
查詢截止到當前時間的所有歷史數據,即全量查詢。
SELECT * FROM mf_tt2 TIMESTAMP AS OF current_timestamp() WHERE dd = '01' AND hh = '01';
返回結果如下。
+------------+------------+----+----+ | pk | val | dd | hh | +------------+------------+----+----+ | 1 | 1 | 01 | 01 | | 3 | 30 | 01 | 01 | | 4 | 4 | 01 | 01 | | 5 | 5 | 01 | 01 | | 2 | 2 | 01 | 01 | +------------+------------+----+----+
查詢截止到10s前的所有歷史數據。
SELECT * FROM mf_tt2 TIMESTAMP AS OF current_timestamp() - 10 WHERE dd = '01' AND hh = '01';
返回結果如下。
+------------+------------+----+----+ | pk | val | dd | hh | +------------+------------+----+----+ | 1 | 1 | 01 | 01 | | 3 | 30 | 01 | 01 | | 4 | 4 | 01 | 01 | | 5 | 5 | 01 | 01 | | 2 | 2 | 01 | 01 | +------------+------------+----+----+
查詢截止到最近第二次Commit時間的所有歷史數據。
SELECT * FROM mf_tt2 TIMESTAMP AS OF get_latest_timestamp('mf_tt2', 2) WHERE dd = '01' AND hh = '01';
返回結果如下。
+------------+------------+------------+------------+ | pk | val | dd | hh | +------------+------------+------------+------------+ | 1 | 1 | 01 | 01 | | 3 | 3 | 01 | 01 | | 2 | 2 | 01 | 01 | +------------+------------+------------+------------+
查詢截止到最近第二次操作的版本的所有歷史數據。
SELECT * FROM mf_tt2 VERSION AS OF get_latest_version('mf_tt2', 2) WHERE dd = '01' AND hh = '01';
返回結果如下。
+------------+------------+----+----+ | pk | val | dd | hh | +------------+------------+----+----+ | 1 | 1 | 01 | 01 | | 3 | 3 | 01 | 01 | | 2 | 2 | 01 | 01 | +------------+------------+----+----+
Incremental查詢示例。
查詢指定時間(例如datetime格式的字符串常量)區間的歷史增量數據,常量值需要根據具體操作的時間來配置。
SELECT * FROM mf_tt2 TIMESTAMP BETWEEN '2023-06-26 09:31:40' AND '2023-06-26 09:32:00' WHERE dd = '01' AND hh = '01';
返回結果如下。
+------------+------------+----+----+ | pk | val | dd | hh | +------------+------------+----+----+ | 1 | 1 | 01 | 01 | | 3 | 3 | 01 | 01 | | 2 | 2 | 01 | 01 | +------------+------------+----+----+
查詢指定version區間的歷史增量數據。
SELECT * FROM mf_tt2 version BETWEEN 2 AND 3 WHERE dd = '01' AND hh = '01';
返回結果如下。
+------------+------------+----+----+ | pk | val | dd | hh | +------------+------------+----+----+ | 3 | 30 | 01 | 01 | | 4 | 4 | 01 | 01 | | 5 | 5 | 01 | 01 | +------------+------------+----+----+
查詢最近300s內的歷史增量數據。
示例:當
mf_tt2
表acid.incremental.query.out.of.time.range.enabled
屬性的默認值為false。SELECT * FROM mf_tt2 TIMESTAMP BETWEEN current_timestamp() - 301 AND current_timestamp() WHERE dd = '01' AND hh='01';
返回值結果報錯。
FAILED: ODPS-0130071:[0,0] Semantic analysis exception - physical plan generation failed: com.aliyun.odps.meta.exception.MetaException: com.aliyun.odps.meta.exception.MetaException: com.aliyun.odps.metadata.common.MetastoreServerException: Incremental query can't exceed current version. Current version timestamp: 2023-06-26 09:32:32, input timestamp is: 2023-06-26 10:47:55
示例:修改表
acid.incremental.query.out.of.time.range.enabled
屬性值為true。ALTER TABLE mf_tt2 SET tblproperties("acid.incremental.query.out.of.time.range.enabled"="true");
示例:再次進行查詢。
SELECT * FROM mf_tt2 TIMESTAMP BETWEEN current_timestamp() - 301 AND current_timestamp() WHERE dd = '01' AND hh='01';
返回值為:
+------------+------------+----+----+ | pk | val | dd | hh | +------------+------------+----+----+ +------------+------------+----+----+
查詢最近第三次Commit和最近第一次Commit時間范圍內的所有歷史數據。
SELECT * FROM mf_tt2 TIMESTAMP BETWEEN get_latest_timestamp('mf_tt2', 3) AND get_latest_timestamp('mf_tt2') WHERE dd = '01' AND hh = '01';
返回結果如下。
+------------+------------+----+----+ | pk | val | dd | hh | +------------+------------+----+----+ | 1 | 1 | 01 | 01 | | 3 | 30 | 01 | 01 | | 4 | 4 | 01 | 01 | | 5 | 5 | 01 | 01 | | 2 | 2 | 01 | 01 | +------------+------------+----+----+
查詢最近第三次和最近第一次操作版本范圍內的所有歷史數據。
SELECT * FROM mf_tt2 VERSION BETWEEN get_latest_version('mf_tt2', 3) AND get_latest_version('mf_tt2') WHERE dd = '01' AND hh = '01';
返回結果如下。
+------------+------------+----+----+ | pk | val | dd | hh | +------------+------------+----+----+ | 1 | 1 | 01 | 01 | | 3 | 30 | 01 | 01 | | 4 | 4 | 01 | 01 | | 5 | 5 | 01 | 01 | | 2 | 2 | 01 | 01 | +------------+------------+----+----+