Les tables Delta prennent en charge deux modes de requête historique : les requêtes de voyage dans le temps et les requêtes incrémentielles. Une requête de voyage dans le temps lit un instantané de la table à un moment ou une version spécifique. Une requête incrémentielle renvoie uniquement les lignes qui ont changé entre deux moments ou entre deux versions.
Ces deux types de requête étendent la syntaxe standard du langage de requête de données (DQL) MaxCompute. La syntaxe DQL complète et ses limites s'appliquent, avec une exception : la clause FROM accepte un qualificateur temporel ou de version.
Syntaxe
[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>]
Utilisez TIMESTAMP | VERSION AS OF expr pour les requêtes de voyage dans le temps et TIMESTAMP | VERSION BETWEEN start_expr AND end_expr pour les requêtes incrémentielles.
Requêtes de voyage dans le temps
Une requête de voyage dans le temps renvoie un instantané historique de la table, c'est-à-dire l'état des données au moment spécifié ou avant celui-ci.
TIMESTAMP AS OF
SELECT * FROM <table> TIMESTAMP AS OF <expr>
expr accepte l'un des formats suivants :
| Format | Exemple | Description |
|---|---|---|
| Chaîne TIMESTAMP | '2023-01-01 00:00:00.123' |
Horodatage précis avec millisecondes |
| Chaîne DATETIME | '2023-01-01 00:00:00' |
Horodatage sans millisecondes |
| Chaîne DATE | '2023-01-01' |
Date uniquement ; l'heure est définie par défaut à minuit |
current_timestamp() |
current_timestamp() |
Heure actuelle |
getDate() + N |
getDate() - 3600 |
N secondes par rapport à maintenant ; négatif = passé, positif = futur |
get_latest_timestamp(tablename [, number]) |
get_latest_timestamp('mf_tt2', 2) |
Horodatage de la Nième opération DML la plus récente (par défaut : 1 = dernière). L'horodatage renvoyé peut être identique pour différentes valeurs de number. |
Pour un accès inter-projets, formatez tablename sous la forme ProjectName.TableName. Pour le modèle à trois couches, utilisez ProjectName.SchemaName.TableName.
Limites :
La plage de requête valide est
[CreateTableTimestamp, expr], oùCreateTableTimestampcorrespond à l'heure de validation de la création de la table.Si
exprest antérieur à l'heure de création de la table ou remonte à plus de N heures, une erreur est renvoyée. N est défini par la propriétéacid.data.retain.hourslors de la création de la table. Par exemple, siacid.data.retain.hoursest72et queexprremonte à 80 heures, la requête échoue.Si
exprremonte exactement à N heures, une erreur peut également être renvoyée en raison de la latence au niveau de la seconde dans les systèmes internes.
Évitez d'utiliser TIMESTAMP AS OF current_timestamp() - <seconds> pour les requêtes proches de la limite de rétention. Utilisez get_latest_timestamp() pour référencer en toute sécurité les validations récentes.
VERSION AS OF
SELECT * FROM <table> VERSION AS OF <expr>
expr accepte :
| Format | Exemple | Description |
|---|---|---|
| Constante BIGINT | 3 |
Un numéro de version spécifique |
get_latest_version(tablename [, number]) |
get_latest_version('mf_tt2', 2) |
Version de la Nième opération DML la plus récente (par défaut : 1 = dernière). Contrairement à get_latest_timestamp, la version renvoyée varie avec chaque valeur de number. |
Pour le formatage de tablename , suivez les mêmes règles que pour get_latest_timestamp().
Limites :
Chaque opération DML génère un numéro de version strictement croissant. Exécutez
SHOW HISTORY FOR TABLE/PARTITIONpour afficher toutes les versions.La plage de versions valides est
[CreateTableVersion, expr]. La valeur par défaut deCreateTableVersionest1.Si la version correspond à une heure de validation antérieure à N heures (où N =
acid.data.retain.hours), ou si la version est inférieure à1, une erreur est renvoyée.Si
exprdépasse la dernière version DML, une erreur est renvoyée.
Utilisez get_latest_version() pour récupérer un numéro de version valide et éviter les erreurs de plage hors limites.
Requêtes incrémentielles
Une requête incrémentielle renvoie uniquement les lignes qui ont été ajoutées ou modifiées dans une plage de temps ou de versions, ce qui équivaut au delta entre deux instantanés.
Les données générées par la compaction ne sont pas considérées comme de nouvelles données et sont exclues des résultats des requêtes incrémentielles.
TIMESTAMP BETWEEN
SELECT * FROM <table> TIMESTAMP BETWEEN <start_expr> AND <end_expr>
La plage temporelle est (start_expr, end_expr] — ouverte à gauche, fermée à droite. Les deux expressions suivent les mêmes formats pris en charge par TIMESTAMP AS OF.
Limites :
Si
start_exprest antérieur à l'heure de création de la table ou remonte à plus de N heures, une erreur est renvoyée. N =acid.data.retain.hours.-
Si
end_exprest postérieur à la dernière heure de validation DML, le comportement dépend deacid.incremental.query.out.of.time.range.enabled:Par défaut (
false) : une erreur est renvoyée.Défini sur
true: la requête renvoie toutes les données incrémentielles dans la plage(start_expr, end_expr].
Pour autoriser les requêtes qui s'étendent au-delà de la dernière validation, définissez la propriété sur true :
ALTER TABLE <table> SET tblproperties("acid.incremental.query.out.of.time.range.enabled"="true");
VERSION BETWEEN
SELECT * FROM <table> VERSION BETWEEN <start_expr> AND <end_expr>
La plage de versions est (start_expr, end_expr] — ouverte à gauche, fermée à droite. Les deux expressions suivent les mêmes formats pris en charge par VERSION AS OF.
Limites :
Le système résout
start_expren une heure de validation. Si cette heure remonte à plus de N heures ou si la version est inférieure à1, une erreur est renvoyée. N =acid.data.retain.hours.-
Si
end_exprdépasse la dernière version DML, le comportement dépend deacid.incremental.query.out.of.time.range.enabled:Par défaut (
false) : une erreur est renvoyée.Défini sur
true: la requête renvoie toutes les données incrémentielles dans la plage(start_expr, end_expr].
Remarques d'utilisation
Seules les tables Delta prennent en charge les requêtes de voyage dans le temps et les requêtes incrémentielles.
Clés dupliquées : Lorsque plusieurs lignes partagent la même clé primaire, seule la dernière ligne est renvoyée. Les lignes à l'état
DELETEsont exclues.Capture des données modifiées (CDC) : L'interrogation de l'état de mise à jour des données dans des formats similaires à la capture des données modifiées (CDC) n'est pas encore prise en charge et est prévue pour une prochaine version.
Tables supprimées ou renommées : Vous ne pouvez pas interroger les données historiques d'une table après sa suppression ou son renommage. Restaurez d'abord la table, puis exécutez la requête.
Même table, plusieurs qualificateurs : Si vous souhaitez effectuer une requête de voyage dans le temps ou une requête incrémentielle sur la même table dans une instruction SQL, vous devez définir les horodatages ou les versions des requêtes sur les mêmes valeurs.
Tables partitionnées : Spécifiez une partition dans la clause
WHEREpour limiter l'analyse à cette partition et réduire le temps de requête.Concurrence : Les tables Delta utilisent le contrôle de concurrence multiversion (MVCC) pour isoler les lectures et écritures simultanées. Le niveau d'isolation Read Committed est pris en charge.
Exemples
Les exemples suivants utilisent une table Delta partitionnée mf_tt2.
Configuration des données d'exemple
-- Table creation. Version = 1.
-- Run "SHOW HISTORY FOR TABLE mf_tt2" to confirm.
CREATE TABLE mf_tt2 (
pk bigint NOT NULL PRIMARY KEY,
val bigint NOT NULL)
PARTITIONED BY (dd string, hh string)
tblproperties ("transactional"="true");
-- INSERT OVERWRITE. Version = 2.
INSERT OVERWRITE TABLE mf_tt2 PARTITION (dd='01', hh='01') VALUES (1, 1), (2, 2), (3, 3);
-- INSERT INTO. Version = 3.
INSERT INTO TABLE mf_tt2 PARTITION (dd='01', hh='01') VALUES (3, 30), (4, 4), (5, 5);
Pour vérifier l'heure de création de la table et l'historique des versions avant d'exécuter les requêtes :
-- Get the table creation timestamp
DESC EXTENDED mf_tt2;
Le résultat suivant est renvoyé.
+------------------------------------------------------------------------------------+
| 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] |
+------------------------------------------------------------------------------------+
-- Get all DML version numbers and commit times
SHOW HISTORY FOR TABLE mf_tt2 PARTITION (dd='01', hh='01');
Le résultat suivant est renvoyé.
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
La sortie de SHOW HISTORY affiche chaque opération, son numéro de version, son heure de validation et son type d'opération (CREATE, APPEND, etc.).
Exemples de requêtes de voyage dans le temps
Instantané à une date et heure spécifiques — toutes les données à partir de 09:33:00 :
SELECT * FROM mf_tt2 TIMESTAMP AS OF '2023-06-26 09:33:00' WHERE dd = '01' AND hh = '01';
Renvoie les 5 lignes écrites par les versions 2 et 3 (pk 1–5, avec pk=3 affichant val=30 depuis la dernière écriture).
Instantané à la version 2 — avant l'instruction INSERT INTO :
SELECT * FROM mf_tt2 VERSION AS OF 2 WHERE dd = '01' AND hh = '01';
Renvoie les 3 lignes de l'instruction INSERT OVERWRITE : pk=1, pk=2, pk=3 (val=3).
Instantané à l'heure actuelle :
SELECT * FROM mf_tt2 TIMESTAMP AS OF current_timestamp() WHERE dd = '01' AND hh = '01';
Instantané il y a 10 secondes :
SELECT * FROM mf_tt2 TIMESTAMP AS OF current_timestamp() - 10 WHERE dd = '01' AND hh = '01';
Instantané à la deuxième validation la plus récente (utilisation de get_latest_timestamp) :
SELECT * FROM mf_tt2 TIMESTAMP AS OF get_latest_timestamp('mf_tt2', 2) WHERE dd = '01' AND hh = '01';
Renvoie les 3 lignes de la version 2.
Instantané à la deuxième version la plus récente (utilisation de get_latest_version) :
SELECT * FROM mf_tt2 VERSION AS OF get_latest_version('mf_tt2', 2) WHERE dd = '01' AND hh = '01';
Renvoie les 3 lignes de la version 2.
Exemples de requêtes incrémentielles
Modifications entre deux horodatages de validation :
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';
Renvoie les 3 lignes écrites par la version 2.
Modifications entre la version 2 et la version 3 :
SELECT * FROM mf_tt2 VERSION BETWEEN 2 AND 3 WHERE dd = '01' AND hh = '01';
Renvoie les 3 lignes écrites par la version 3 : pk=3 (val=30), pk=4, pk=5.
Dernières 300 secondes avec acid.incremental.query.out.of.time.range.enabled défini sur false (par défaut) :
SELECT * FROM mf_tt2 TIMESTAMP BETWEEN current_timestamp() - 301 AND current_timestamp() WHERE dd = '01' AND hh='01';
Renvoie une erreur car end_expr dépasse l'horodatage de la dernière validation :
FAILED: ODPS-0130071:[0,0] Semantic analysis exception - physical plan generation failed:
com.aliyun.odps.meta.exception.MetaException: ...
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
Pour permettre à la requête de s'étendre au-delà de la dernière validation, activez la propriété :
ALTER TABLE mf_tt2 SET tblproperties("acid.incremental.query.out.of.time.range.enabled"="true");
Réexécutez ensuite la requête. Le résultat est vide (aucune nouvelle donnée n'a été écrite au cours des 300 dernières secondes) :
+------------+------------+----+----+
| pk | val | dd | hh |
+------------+------------+----+----+
+------------+------------+----+----+
Modifications de la troisième validation la plus récente à la plus récente :
SELECT * FROM mf_tt2 TIMESTAMP BETWEEN get_latest_timestamp('mf_tt2', 3) AND get_latest_timestamp('mf_tt2') WHERE dd = '01' AND hh = '01';
Renvoie les 5 lignes (couvre les validations des versions 2 et 3).
Modifications de la troisième version la plus récente à la plus récente :
SELECT * FROM mf_tt2 VERSION BETWEEN get_latest_version('mf_tt2', 3) AND get_latest_version('mf_tt2') WHERE dd = '01' AND hh = '01';
Renvoie les 5 lignes.