MaxComputeでは、デルタテーブルに対してタイムトラベルクエリと増分クエリを実行できます。 タイムトラベルのクエリを実行する場合は、過去の時点または過去のバージョンのソーステーブルのスナップショットに基づいて、履歴データをクエリできます。 増分クエリを実行すると、履歴期間内、またはソーステーブルの2つのバージョン間の履歴増分データをクエリできます。 このトピックでは、デルタテーブルに対するクエリの使用方法と制限について説明します。
構文
[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>]
ほとんどの場合、すべてのシナリオでデータクエリ言語 (DQL) ステートメントを実行してDeltaテーブルにクエリを実行できます。 DQL文の構文と制限は、基本的にMaxCompute DQLの構文と制限に準拠しています。 唯一の違いは、FROM TABLE句の構文がDQLステートメントで最適化されていることです。 最適化されたFROM TABLE句は、タイムトラベルクエリの履歴時点または履歴バージョンを指定したり、増分クエリの時間範囲またはバージョン範囲を指定したりできる固定形式の式を提供します。
パラメータとタイムトラベルクエリの制限
デルタテーブルでタイムトラベルクエリを実行する場合、履歴時点または履歴バージョンのソーステーブルのスナップショットに基づいて履歴データをクエリできます。 [timestamp | version as of expr]
構文を使用して、タイムトラベルクエリを設定できます。
exprの時点でのタイムスタンプ
パラメーター
timestamp as of: 固定構文形式で、その後に履歴時点が続きます。 履歴時点より前に保存された履歴データは、スナップショットに基づいて照会されます。
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秒後の時刻が指定されます。
デルタテーブルの構文:
get_latest_timestamp(string tablename [, bigint <number>])
クロスプロジェクトアクセスの場合、tablenameパラメーターの値は
projectName.tableName
形式である必要があります。3層モデルの場合、tablenameパラメーターの値は
projectName.schemaName.tableName
形式である必要があります。numberパラメーターはオプションです。 デフォルト値は 1 です。 このパラメータは、データ操作のシーケンス番号を逆時系列で指定します。 たとえば、最後のデータ操作がコミットされた時刻を取得するには、このパラメーターを1に設定します。 データ操作には、ユーザによって開始されるデータ修正と、システムによって開始されるデータのソートおよび配布とが含まれる。 返されるタイムスタンプは、数値パラメータが異なる値に設定されていても同じである可能性があります。
制限事項
タイムトラベルクエリの履歴時間範囲は
[CreateTableTimestamp, expr]
です。 exprパラメーターはDML操作がコミットされる時刻を指定し、CreateTableTimestampパラメーターはテーブル作成操作がコミットされる時刻を指定します。exprパラメーターで指定された時刻がN時間以上前、またはDeltaテーブルが作成された時刻より前の場合、特定の履歴データが存在しない可能性があるため、エラーが返されます。 Nは、テーブルの作成時に設定されるacid.data.retain.hoursパラメーターで指定します。 たとえば、acid.data.retain.hoursパラメーターが72に設定され、exprパラメーターが72時間以上前に設定されている場合、エラーが返されます。
exprパラメーターで指定された時間がN時間前の場合、エラーが返される可能性があります。 Nは、テーブルの作成時に設定されるacid.data.retain.hoursパラメーターで指定します。 これは、内部システムが相互作用するときに第2レベルのレイテンシが発生する可能性があるためです。 したがって、
timestamp as of current_timestamp() - time travel period
に似たエラーが発生しやすい構文を使用しないことをお勧めします。
exprのバージョン
パラメーター
version as of: 固定構文形式で、その後に履歴データ操作のバージョンが続きます。 履歴データ操作バージョンがスナップショットに基づいて照会される前のバージョンに格納された履歴データ。
expr: MaxComputeでサポートされているBIGINT型の値。 この値は、次の形式をサポートします。
BIGINT型の定数
例:
3
。デルタテーブルの構文:
get_latest_version(string tablename [, bigint <number>])
クロスプロジェクトアクセスの場合、tablenameパラメーターの値は
projectName.tableName
形式である必要があります。3層モデルの場合、tablenameパラメーターの値は
projectName.schemaName.tableName
形式である必要があります。numberパラメーターはオプションです。 デフォルト値は 1 です。 このパラメータは、データ操作のシーケンス番号を逆時系列で指定します。 たとえば、最後のデータ操作のバージョンを取得するには、このパラメーターを1に設定します。 データ操作には、ユーザによって開始されるデータ修正と、システムによって開始されるデータのソートおよび配布とが含まれる。 返されるバージョンは、numberパラメーターの値によって異なります。
制限事項
各DMLオペレーションは、厳密にインクリメントされるバージョンを生成する。
show history for table/partition
構文を使用して、すべてのDML操作に関する情報を表示できます。 出力から操作バージョンを取得できます。タイムトラベルクエリの履歴時間範囲は
[CreateTableVersion, expr]
です。 exprパラメーターは、DML操作のバージョンを指定します。 CreateTableVersionパラメーターは、テーブル作成操作のバージョンを指定します。 デフォルト値は 1 です。システムは、exprパラメーターで指定されたバージョンに基づいて、DML操作がコミットされた時刻を取得します。 時刻がN時間以上前の場合、またはバージョンが1未満の場合は、エラーが返されます。 Nは、テーブルの作成時に設定されるacid.data.retain.hoursパラメーターで指定します。
exprパラメーターで指定されたバージョンが最後のDML操作のバージョンよりも新しい場合は、エラーが返されます。
get_latest_version
関数を使用してバージョンを取得することを推奨します。
増分クエリのパラメータと制限
増分クエリをサポートするのはDeltaテーブルのみです。 増分クエリを実行すると、履歴期間内、またはソーステーブルの2つのバージョン間の履歴増分データをクエリできます。 [timestamp | version between start_expr and end_expr]
構文を使用して、増分クエリを設定できます。
start_exprとend_exprの間のタイムスタンプ
パラメーター
timestamp between and: 履歴時間範囲を指定する固定構文形式。 時間範囲内に生成された履歴増分データが照会されます。
start_exprとend_expr: 2つのパラメーターの使用方法と制限は、timestamp以降の構文のexprパラメーターの使用方法と一致しています。
制限事項
(start_expr, end_expr]
で指定される時間範囲は、左オープン、右クローズの間隔です。 start_exprおよびend_exprパラメーターは、DML操作がコミットされる時刻を指定します。start_exprパラメーターで指定された時間がN時間以上前の場合、またはテーブルの作成時間より前の場合は、エラーが返されます。 Nは、acid.data.retain.hoursパラメーターによって指定されます。
end_exprパラメーターで指定された時刻が、最後のDML操作がコミットされた時刻よりも遅い場合、クエリ結果は、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");
start_exprとend_exprの間のバージョン
パラメーター
version betweenと: 履歴DML操作のバージョン範囲を指定する固定構文形式。 バージョン範囲内で生成された履歴の増分データが返されます。
start_exprとend_expr: 2つのパラメーターの使用法と制限は、構文のバージョンのexprパラメーターの使用法と制限と一致しています。
制限事項
(start_expr, end_expr) で指定されたバージョン範囲は、左オープン、右クローズの間隔です。 start_exprおよびend_exprパラメーターは、DML操作のバージョンを指定します。
システムは、start_exprパラメーターで指定されたバージョンに基づいて、DML操作がコミットされた時刻を取得します。 時刻がN時間以上前の場合、またはバージョンが1未満の場合は、エラーが返されます。 Nは、タイムトラベルクエリ用に設定されたacid.data.retain.hoursパラメーターによって指定されます。
end_exprパラメーターで指定されたバージョンが最後のDML操作のバージョンよりも新しい場合、クエリ結果はacid.incremental.query.out.of.time.range.enabledパラメーターの値によって異なります。 このパラメーターがデフォルト値falseに設定されている場合、エラーが返されます。 このパラメーターをtrueに設定すると、(start_expr, end_expr) で指定されたバージョン範囲内で生成されたすべての履歴増分データが返されます。
その他
同じキーを持つレコードの複数の行が照会された場合、最新の行のみが返されます。 最新の行がDELETE状態にある場合、この行は除外されます。 変更データキャプチャ (CDC) と同様の形式でデータの更新ステータスを照会する機能は、将来提供される予定です。
存在しない履歴テーブルを照会することはできません。 たとえば、テーブルに対してドロップまたは名前変更操作を実行した後は、元のテーブルの履歴データを照会することはできません。
このタイプのテーブルの履歴データをクエリする場合は、テーブルを復元してからクエリを実行できます。
デルタテーブルのみがタイムトラベルクエリと増分クエリをサポートしています。
SQL文の同じテーブルに対してタイムトラベルクエリまたは増分クエリを実行する場合は、クエリのタイムスタンプまたはバージョンを同じ値に設定する必要があります。
パーティションテーブルでクエリを実行する場合は、クエリにパーティションを指定することを推奨します。 このようにして、指定されたパーティションのみがクエリされ、消費時間が短縮されます。
マルチバージョン同時実行制御 (MVCC) モデルは、同時読み取りおよび書き込みトランザクションに使用されます。 これにより、読み取り操作と書き込み操作が分離され、互いに影響しないようになります。 ReadCommittedレベルがサポートされています。
コンパクション操作によって生成されたデータは、新しいデータとは見なされません。 したがって、増分クエリを実行しても、このタイプのデータは返されません。
例
テストテーブル
-- Create a table. The version of this operation is 1. You can execute the show history for table mf_tt2 statement to query the version. create table mf_tt2 (pk bigint not null primary key, val bigint not null) partitioned by (dd string, hh string) tblproperties ("transactional"="true"); -- The version of the following DML operation is 2. insert overwrite table mf_tt2 partition(dd='01', hh='01') values (1, 1), (2, 2), (3, 3); -- The version of the following DML operation is 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 | +------------+------------+----+----+
定数で指定されたバージョンより前に格納されたすべての履歴データを照会します。
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 | +------------+------------+----+----+
10秒前までに保存されたすべての履歴データを照会します。
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 | +------------+------------+----+----+
最後の2番目の操作がコミットされた時刻までに保存されたすべての履歴データを照会します。
サンプル文1
select * from mf_tt2 timestamp as of get_latest_timestamp('mf_tt2', 2) where dd = '01' and hh = '01';
サンプル文2
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 | +------------+------------+----+----+
増分クエリの例
指定された期間内の履歴増分データを照会します。 たとえば、操作がコミットされた時刻に基づいて、開始時刻と終了時刻を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 | +------------+------------+----+----+
指定した2つのバージョン間の履歴増分データを照会します。
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 | +------------+------------+----+----+
直近の300秒以内の履歴増分データを照会します。
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 | +------------+------------+----+----+ +------------+------------+----+----+
最後の2つの操作がコミットされた時点間の履歴増分データを照会します。
サンプル文
select * from mf_tt2 timestamp between get_latest_timestamp('mf_tt2', 3) and get_latest_timestamp('mf_tt2') where dd = '01' and hh = '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 | +------------+------------+----+----+