Tous les produits
Search
Centre de documentation

Hologres:Create dynamic table

Dernière mise à jour :Oct 10, 2026

Créez une Dynamic Table qui actualise automatiquement les résultats de requête à partir des tables de base, en utilisant une actualisation incrémentielle ou complète.

Remarques importantes

  • Limites d'utilisation des Dynamic Tables : Prise en charge et limites des Dynamic Tables.

  • Hologres V3.1 et versions ultérieures imposent l'utilisation de la nouvelle syntaxe pour créer des Dynamic Tables. Vous pouvez toujours effectuer des opérations ALTER sur les tables créées avec la syntaxe V3.0, mais vous ne pouvez pas en créer de nouvelles. Pour les tables non partitionnées, utilisez la commande de conversion de syntaxe afin de migrer l'ancienne syntaxe vers la nouvelle. Pour les tables partitionnées, recréez-les manuellement.

  • La mise à niveau vers Hologres V3.1 ou version ultérieure nécessite la recréation des Incremental Dynamic Tables existantes. Utilisez la commande de conversion de syntaxe pour procéder à cette opération.

  • Dans Hologres V3.1 et versions ultérieures, le moteur optimise de manière adaptative le processus d'actualisation. La présence d'ID de requête négatifs lors des opérations d'actualisation est un comportement attendu.

Instructions

Syntaxe

V3.1+ (nouvelle syntaxe)

Remarque

La version V3.1+ prend uniquement en charge la nouvelle syntaxe.

Syntaxe de création d'une table dynamique

Syntaxe permettant de créer une table dynamique dans la version V3.1+ :

CREATE DYNAMIC TABLE [ IF NOT EXISTS ] [<schema_name>.]<table_name>
[ (<col_name> [, ...] ) ]
[LOGICAL PARTITION BY LIST(<partition_key>)]
WITH (
  -- Dynamic Table properties
  freshness = {'<num> {minutes | hours}' | 'upstream'}, -- Required
  [auto_refresh_enable = {true | false},] -- Optional
  [auto_refresh_mode = {'full' | 'incremental' | 'auto'},] -- Optional
  
  [base_table_cdc_format = {'stream' | 'binlog'},] -- Optional

  [auto_refresh_partition_active_time = '<num> {minutes | hours | days}',] -- Optional
  [partition_key_time_format = {'YYYYMMDDHH24' | 'YYYY-MM-DD-HH24' | 'YYYY-MM-DD_HH24' | 'YYYYMMDD' | 'YYYY-MM-DD' | 'YYYYMM' | 'YYYY-MM' | 'YYYY'},] --Optional
  
  [computing_resource = {'local' | 'serverless' | '<warehouse_name>'},] -- Optional. The warehouse_name value is supported only in Hologres V4.0.7 and later.
  [refresh_guc_hg_experimental_serverless_computing_required_cores=xxx,] --Optional. Specifies the required computing cores for Serverless.
  
  [refresh_guc_<guc_name> = '<guc_value>',] -- Optional

  -- General properties
  [orientation = {'column' | 'row' | 'row,column'},]
  [table_group = '<tableGroupName>',]
  [distribution_key = '<columnName>[,...]]',]
  [clustering_key = '<columnName>[:asc] [,...]',]
  [event_time_column = '<columnName> [,...]',]
  [bitmap_columns = '<columnName> [,...]',]
  [dictionary_encoding_columns = '<columnName> [,...]',]
  [time_to_live_in_seconds = '<non_negative_literal>',]
  [storage_mode = {'hot' | 'cold'},]
)
AS
<query>; -- Query definition.

Paramètres

Mode d'actualisation et ressources

Parameter

Description

Required

Default

freshness

Fraîcheur cible des données, exprimée en minutes ou en heures. Minimum : 1 minute. Le moteur planifie les actualisations en fonction de l'heure de la dernière actualisation et de cette valeur freshness. Contrairement à un intervalle fixe, freshness s'adapte automatiquement pour maintenir les données aussi actuelles que possible. Valeurs valides :

  • '<num> {minutes | hours}' : les actualisations sont planifiées automatiquement en fonction de la fraîcheur spécifiée.

  • 'upstream' : mode d'actualisation en cascade, pris en charge à partir de Hologres V5.0. La table ne possède pas son propre planning d'actualisation. Elle est déclenchée une fois que la table dynamique en amont a terminé son actualisation, ce qui permet aux données de circuler couche par couche à travers un entrepôt multicouche (ODS vers DWD vers DWS vers ADS) sans intervalle d'actualisation distinct pour chaque couche. Lorsque vous utilisez cette valeur, au moins l'une des tables de base doit être une table dynamique. Sinon, la création de la table échoue. Pour le comportement du déclencheur, consultez Actualisation en cascade.

Yes

None

auto_refresh_mode

Mode d'actualisation. Valeurs valides :

  • auto : Mode automatique. Le moteur utilise automatiquement l'actualisation incrémentielle si la requête le permet ; sinon, il revient à l'actualisation complète.

  • incremental : Actualisation incrémentielle. Seules les données incrémentielles sont actualisées à chaque fois. Pour plus d'informations, consultez Actualisation incrémentielle.

  • full : Actualisation complète. L'intégralité de la table est actualisée à chaque fois. Pour plus d'informations, consultez Actualisation complète.

No

auto

auto_refresh_enable

Active ou désactive l'actualisation automatique. Valeurs valides :

  • true : Active l'actualisation automatique.

  • false : Désactive l'actualisation automatique. Tous les travaux d'actualisation ultérieurs pour la table sont arrêtés.

No

true

base_table_cdc_format

Méthode de consommation des modifications des données de la table de base lors de l'actualisation incrémentielle.

  • stream (par défaut) : Lit les modifications des données au niveau des fichiers. Aucune surcharge de stockage supplémentaire et des performances supérieures à celles de binlog. Pour plus d'informations, consultez Tables dynamiques.

  • binlog : Consomme les modifications des données de la table de base via binlog. Nécessite l'activation manuelle du binlog sur la table de base (S'abonner au Binlog Hologres).

    begin;
        call set_table_property('<table_name>', 'binlog.level', 'replica');
        call set_table_property('<table_name>', 'binlog.ttl', '2592000');
        commit;
Remarque
  • À partir de la version V3.1, toutes les tables utilisent par défaut le mode stream. Désactivez le binlog s'il est activé afin d'éviter des coûts de stockage inutiles.

  • La méthode stream n'est pas prise en charge pour les tables de base orientées ligne ; seule la méthode binlog l'est.

  • Ce paramètre ne peut pas être modifié après la création de la table. Pour le modifier, recréez la table.

No

stream

computing_resource

Ressource de calcul utilisée pour l'actualisation. Valeurs valides :

  • serverless (par défaut) : Utilise les ressources de calcul Serverless, isolant ainsi les charges de travail d'actualisation du trafic de requêtes.

  • <warehouse_name> : Utilise l'entrepôt de calcul spécifié pour l'actualisation.

    Remarque

    Pris en charge uniquement dans Hologres V4.0.7 et versions ultérieures.

  • local : Utilise les ressources de calcul locales de l'instance actuelle pour l'actualisation.

Paramètres.

No

serverless

refresh_guc_<guc_name>

Définissez les paramètres GUC pour l'actualisation. Pour connaître les GUC pris en charge, consultez Paramètres GUC.

No

None

Tables partitionnées

Table partitionnée logique

Parameter

Description

Required

Default

LOGICAL PARTITION BY LIST(<partition_key>)

Crée une table dynamique partitionnée logiquement. Requiert auto_refresh_partition_active_time et partition_key_time_format.

No

None

auto_refresh_partition_active_time

Plage d'actualisation des partitions, exprimée en minutes, heures ou jours. Hologres remonte le temps à partir de l'heure actuelle et actualise les partitions situées dans cette fenêtre.

Les partitions actives sont celles dont le temps écoulé depuis le début (déduit du nom de la partition) est inférieur à la valeur auto_refresh_partition_active_time.

Remarque
  • Le paramètre auto_refresh_partition_active_time doit spécifier une durée supérieure à un intervalle de partition. Par exemple, si les données sont partitionnées quotidiennement, auto_refresh_partition_active_time doit être défini sur une période supérieure à 24 heures.

  • Ce paramètre est modifiable. Les modifications n'affectent que les futures partitions.

  • À partir de Hologres V4.2, l'actualisation des partitions actives d'une table dynamique utilise des verrous au niveau de la partition plutôt qu'au niveau de la table. Cela signifie que différentes partitions peuvent être actualisées simultanément sans s'attendre mutuellement.

Yes

Par défaut sur Intervalle de partitionnement + 1 heure.

Cela fournit une marge d'une heure pour tenir compte des retards potentiels des données provenant de la table de base. Par exemple, avec un partitionnement quotidien, la valeur par défaut devient 25 heures (1 jour + 1 heure).

partition_key_time_format

Format du nom de la partition. Valeurs valides :

  • Pour les clés de partition TEXT/VARCHAR :

    YYYYMMDDHH24, YYYY-MM-DD-HH24, YYYY-MM-DD_HH24, YYYYMMDD, YYYY-MM-DD, YYYYMM, YYYY-MM, YYYY.

  • Pour les clés de partition INT :

    YYYYMMDDHH24, YYYYMMDD, YYYYMM, YYYY.

  • Pour les clés de partition DATE :

    YYYY-MM-DD

Yes

None

Tables partitionnées physiques

Parameter

Description

Required

Default

PARTITION BY LIST(<partition_key>)

Crée une table dynamique partitionnée physiquement.

Les tables dynamiques partitionnées physiquement ne disposent pas de partitionnement dynamique et présentent des limitations d'utilisation. Les partitions logiques sont recommandées. Pour connaître les différences, consultez CREATE LOGICAL PARTITION TABLE.

Important

Hologres V3.1+ ne prend pas en charge la création d'une table dynamique en tant que table partitionnée physiquement.

No

None

Propriétés de la table

Parameter

Description

Required

Default value

Full refresh mode

Incremental refresh mode

col_name

Noms des colonnes.

Spécifiez les noms, mais pas les attributs ni les types de données ; le moteur les déduit.

Remarque

La spécification des attributs et des types de données des colonnes peut entraîner une inférence incorrecte par le moteur.

No

Nom de la colonne de la requête

Nom de la colonne de la requête

orientation

Format de stockage. column indique un stockage orienté colonne.

No

column

column

table_group

Groupe de tables. Par défaut, il s'agit du groupe par défaut de la base de données actuelle. Pour plus d'informations, consultez Gérer les groupes de tables et les shards.

No

Nom du groupe de tables par défaut

Nom du groupe de tables par défaut

distribution_key

Clé de distribution. Pour plus d'informations, consultez Clé de distribution.

No

(none)

(none)

clustering_key

Clé de clustering. Pour plus d'informations, consultez Clé de clustering.

No

Autorisé, avec une valeur par défaut déduite.

Autorisé, avec une valeur par défaut déduite.

event_time_column

Consultez Colonne d'heure de l'événement (clé de segment).

No

(none)

(none)

bitmap_columns

Colonnes bitmap. Pour plus d'informations, consultez Index bitmap.

No

Champs de type TEXT

Champs de type TEXT

dictionary_encoding_columns

Consultez Encodage par dictionnaire.

No

Champs de type TEXT

Champs de type TEXT

time_to_live_in_seconds

TTL des données.

No

Aucune expiration

Aucune expiration

storage_mode

Niveau de stockage. Valeurs valides :

  • hot : Stockage chaud.

  • cold : Stockage froid.

Remarque

Pour plus de détails, consultez Configurer la hiérarchisation du stockage.

No

hot

hot

binlog_level

Active le binlog pour la table dynamique. S'abonner au Binlog Hologres.

Remarque
  • Ce paramètre nécessite la version V3.1.18 ou ultérieure.

  • Pour une table dynamique utilisant l'actualisation complète, le processus d'actualisation peut générer un volume important de données binlog et entraîner une surcharge de stockage élevée. Par conséquent, nous vous déconseillons d'activer le binlog.

No

none

none

binlog_ttl

TTL du binlog.

No

2592000

2592000

Actualisation en cascade

Hologres V5.0 et versions ultérieures prennent en charge l'actualisation en cascade. Lorsque les tables de base d'une table dynamique incluent d'autres tables dynamiques, vous pouvez définir sa freshness sur 'upstream' afin que la table soit actualisée automatiquement après la fin de l'actualisation de sa table dynamique en amont, formant ainsi une chaîne d'actualisation en cascade. Cette approche convient aux scénarios d'entrepôt multicouche : définissez une valeur de fraîcheur explicite uniquement à la racine de la chaîne et définissez chaque couche en aval sur 'upstream'. Les données circulent alors couche par couche sans intervalle d'actualisation pour chaque couche et sans ordonnanceur externe pour orchestrer les dépendances.

Exemple
-- Root: refreshed on a fixed freshness.
CREATE DYNAMIC TABLE dwd_orders
WITH (
  auto_refresh_mode = 'incremental',
  freshness = '5 minutes'
)
AS SELECT order_id, user_id, ds, amount FROM ods_orders;

-- Second layer: triggered after dwd_orders is refreshed.
CREATE DYNAMIC TABLE dws_user_amount
WITH (
  auto_refresh_mode = 'incremental',
  freshness = 'upstream'
)
AS SELECT user_id, ds, SUM(amount) AS amt FROM dwd_orders GROUP BY user_id, ds;

-- Third layer: triggered after dws_user_amount is refreshed.
CREATE DYNAMIC TABLE ads_daily_amount
WITH (
  auto_refresh_mode = 'incremental',
  freshness = 'upstream'
)
AS SELECT ds, SUM(amt) AS amt FROM dws_user_amount GROUP BY ds;

Pour surveiller une chaîne en cascade, interrogez hologres.hg_dynamic_table_refresh_history. Les actualisations déclenchées par une table en amont sont enregistrées avec le type de déclencheur cascade.

SELECT dynamic_table_name, refresh_type, status, refresh_start
FROM hologres.hg_dynamic_table_refresh_history
WHERE schema_name = '<SCHEMA_NAME>'
ORDER BY refresh_start;
Comportement du déclencheur
  • Les déclencheurs se propagent un niveau à la fois : lorsqu'une table dynamique en amont termine son actualisation, elle déclenche ses tables en aval directes, et chacune d'elles déclenche le niveau suivant une fois terminée. Une table en amont ne déclenche jamais directement un petit-enfant. Dans une chaîne A vers B vers C, C est déclenché par B, et non par A.

  • Une table en amont retourne dès que sa propre actualisation est terminée et n'attend pas les actualisations en aval. Il en va de même pour une commande REFRESH DYNAMIC TABLE manuelle : l'instruction retourne lorsque la table actuelle est actualisée, et les actualisations en aval s'exécutent ensuite de manière asynchrone. Pour contrôler si une actualisation manuelle déclenche les tables en aval, utilisez le paramètre cascading. Pour plus d'informations, consultez Actualiser une table dynamique.

  • Lorsqu'une table dynamique possède plusieurs tables dynamiques en amont, l'actualisation réussie de n'importe quelle table en amont déclenche une actualisation de cette table sans attendre les autres tables en amont. Par conséquent, la table peut combiner les dernières données de certaines tables en amont avec des données plus anciennes d'autres tables. Il s'agit d'un comportement attendu pour l'actualisation en cascade. Si votre activité exige que toutes les données en amont soient alignées, ne vous fiez pas aux déclencheurs en cascade. Actualisez la table manuellement une fois que toutes les données en amont sont prêtes.

Requête

Requête qui définit les données de la table dynamique. Les requêtes et les tables de base prises en charge varient selon le mode d'actualisation. Pour plus d'informations, consultez Prise en charge et limites des tables dynamiques.

V3.0 (ancienne syntaxe)

Syntaxe de création d'une table dynamique

CREATE DYNAMIC TABLE [IF NOT EXISTS] <schema.tablename>(
[col_name],
[col_name]
  ) [PARTITION BY LIST (col_name)]
WITH (
    [refresh_mode='[full|incremental]',]
    [auto_refresh_enable='[true|false',]

  --Incremental refresh parameters:
    [incremental_auto_refresh_schd_start_time='[immediate|<timestamptz>]',]
    [incremental_auto_refresh_interval='[<num> {minute|minutes|hour|hours]',]  
    [incremental_guc_hg_computing_resource='[ local | serverless]',]
    [incremental_guc_hg_experimental_serverless_computing_required_cores='<num>',]

   --Full refresh parameters:
    [full_auto_refresh_schd_start_time='[immediate|<timestamptz>]',]
    [full_auto_refresh_interval='[<num> {minute|minutes|hour|hours]',] 
    [full_guc_hg_computing_resource='[ local | serverless]',]--hg_full_refresh_computing_resource defaults to serverless, can be set at the DB level, and is optional for users.
    [full_guc_hg_experimental_serverless_computing_required_cores='<num>',]
    
   --Shared parameters, GUCs are allowed:
   [refresh_guc_<guc>='xxx]',] 
   
  -- General Dynamic Table properties:
    [orientation = '[column]',]
    [table_group = '[tableGroupName]',]
    [distribution_key = 'columnName[,...]]',]
    [clustering_key = '[columnName{:asc]} [,...]]',]
    [event_time_column = '[columnName [,...]]',]
    [bitmap_columns = '[columnName [,...]]',]
    [dictionary_encoding_columns = '[columnName [,...]]',]
    [time_to_live_in_seconds = '<non_negative_literal>',]
    [storage_mode = '[hot | cold]']
    ) 
AS
<query> --Query definition

Paramètres

Mode d'actualisation et ressources

Catégorie

Paramètre

Description

Obligatoire

Valeur par défaut

Paramètres d'actualisation partagés

refresh_mode

Mode d'actualisation. Valeurs valides : full et incremental.

Si ce paramètre n'est pas défini, aucune actualisation n'est effectuée.

Non

(aucune)

auto_refresh_enable

Active ou désactive l'actualisation automatique. Valeurs valides :

  • true

  • false

Non

false

refresh_guc_<guc>

Définit les paramètres GUC pour l'actualisation. Pour obtenir la liste des GUC pris en charge, consultez la section Paramètres GUC.

Remarque

Par exemple, pour définir le fuseau horaire via un paramètre GUC, utilisez refresh_guc_timezone = 'GMT-8:00'.

Non

(aucune)

Actualisation incrémentielle

incremental_auto_refresh_schd_start_time

Heure de début de l'actualisation incrémentielle. Valeurs valides :

  • immediate : valeur par défaut. L'actualisation incrémentielle démarre immédiatement après la création de la table.

  • <timestamptz> : heure de début personnalisée, par exemple « 2024-08-24 1:00 », pour lancer la tâche d'actualisation à ce moment précis.

Non

immediate

incremental_auto_refresh_interval

Intervalle d'actualisation incrémentielle, exprimé en minutes ou en heures.

  • Plage de valeurs : [1min, 48hours].

  • Si ce paramètre n'est pas défini, la table dynamique est actualisée une seule fois, à l'heure de début spécifiée.

Non

(aucune)

incremental_guc_hg_computing_resource

Ressources de calcul pour l'actualisation incrémentielle. Valeurs valides :

  • local : utilise les ressources propres de l'instance.

  • serverless : utilise les ressources Serverless Computing. Pour vérifier si l'instance répond aux exigences de Serverless Computing, consultez la section Utiliser le calcul serverless.

Remarque

Pour définir les ressources de calcul au niveau de la base de données, exécutez ALTER DATABASE xxx SET incremental_guc_hg_computing_resource=xx.

Non

local

incremental_guc_hg_experimental_serverless_computing_required_cores

Nombre de cœurs Serverless Computing pour l'actualisation.

Remarque

Les quotas de ressources Serverless Computing varient selon les spécifications de l'instance. Pour plus d'informations, consultez la section Gérer les ressources de calcul serverless.

Non

(aucune)

Actualisation complète

full_auto_refresh_schd_start_time

Heure de début de l'actualisation complète. Valeurs valides :

  • immediate : valeur par défaut. L'actualisation complète démarre immédiatement après la création de la table.

  • <timestamptz> : heure de début personnalisée, par exemple « 2024-08-24 1:00 », pour lancer la tâche d'actualisation à ce moment précis.

Non

immediate

full_auto_refresh_interval

Intervalle d'actualisation complète, exprimé en minutes ou en heures.

  • Plage de valeurs : [1min, 48hours].

  • Si ce paramètre n'est pas défini, la table dynamique est actualisée une seule fois, à l'heure de début spécifiée.

Non

(aucune)

full_guc_hg_computing_resource

Ressources de calcul pour l'actualisation complète. Valeurs valides :

  • local : ressources propres de l'instance.

  • serverless : utilise les ressources Serverless Computing. Pour vérifier si l'instance répond aux exigences de Serverless Computing, consultez la section Utiliser le calcul serverless.

Remarque

Pour définir les ressources de calcul au niveau de la base de données, exécutez ALTER DATABASE xxx SET full_guc_hg_computing_resource=xx.

Non

local

full_guc_hg_experimental_serverless_computing_required_cores

Nombre de cœurs Serverless Computing pour l'actualisation.

Remarque

Les quotas de ressources Serverless Computing varient selon les spécifications de l'instance. Pour plus d'informations, consultez la section Gérer les ressources de calcul serverless.

Non

(aucune)

Propriétés de la table

Paramètre

Description

Obligatoire

Valeur par défaut

full

incremental

col_name

Noms des colonnes.

Spécifiez uniquement les noms, sans attributs ni types de données ; le moteur les déduit automatiquement.

Remarque

La spécification explicite des attributs et des types de données des colonnes peut entraîner une inférence incorrecte par le moteur.

Non

Nom de la colonne de la requête

Nom de la colonne de la requête

orientation

Format de stockage de la table dynamique. La valeur column indique un stockage orienté colonnes.

Non

column

column

table_group

Groupe de tables. Par défaut, le groupe de tables par défaut de la base de données actuelle est utilisé. Pour plus d'informations, consultez la section Gérer les groupes de tables et les shards.

Non

Nom du groupe de tables par défaut

Nom du groupe de tables par défaut

distribution_key

Clé de distribution. Pour plus d'informations, consultez la section Clé de distribution.

Non

(aucune)

(aucune)

clustering_key

Clé de clustering. Pour plus d'informations, consultez la section Clé de clustering.

Non

Autorisé, avec une valeur par défaut déduite.

Autorisé, avec une valeur par défaut déduite.

event_time_column

Clé de segmentation. Pour plus d'informations, consultez la section Colonne d'heure d'événement (clé de segmentation).

Non

(aucune)

(aucune)

bitmap_columns

Colonnes bitmap. Pour plus d'informations, consultez la section Index bitmap.

Non

Champs de type TEXT

Champs de type TEXT

dictionary_encoding_columns

Consultez la section Encodage par dictionnaire.

Non

Champs de type TEXT

Champs de type TEXT

time_to_live_in_seconds

Durée de vie (TTL) des données.

Non

Aucune expiration

Aucune expiration

storage_mode

Niveau de stockage. Valeurs valides :

  • hot : stockage chaud.

  • cold : stockage froid.

Remarque

Consultez la section Configurer la hiérarchisation du stockage.

Non

hot

hot

PARTITION BY LIST

Crée une table dynamique partitionnée. Les partitions peuvent utiliser différents modes d'actualisation pour répondre à des besoins variables en matière de fraîcheur des données.

Non

Table non partitionnée

Table non partitionnée

Requête

La requête qui génère les données de la table dynamique. Les requêtes prises en charge et les types de tables de base varient selon le mode d'actualisation. Prise en charge et limites des tables dynamiques.

Actualisation incrémentielle

L'actualisation incrémentielle détecte les modifications apportées à la table de base et écrit uniquement les deltas dans la table dynamique. Cette approche est idéale pour les requêtes en quasi temps réel (à l'échelle de la minute).

  • Limitations relatives à la table de base :

    • La version V3.1 utilise par défaut le mode stream. Si votre table de base avait le binlog activé dans la version V3.0, désactivez-le pour éviter des coûts de stockage supplémentaires.

    • Dans la version V3.0, vous devez activer le binlog pour la table de base, sauf s'il s'agit d'une table de dimension impliquée dans une jointure. L'activation du binlog pour une table de base entraîne une surcharge de stockage. Consultez l'utilisation du stockage du binlog en vous référant à la section Afficher les détails du stockage des tables.

  • En mode d'actualisation incrémentielle, Hologres génère en arrière-plan une table d'état pour enregistrer les résultats d'agrégation intermédiaires (consultez la section Tables dynamiques pour plus de détails). La table d'état consomme également de l'espace pour le stockage de l'état. Pour afficher l'utilisation du stockage, consultez la section Afficher le schéma et la lignée des tables dynamiques.

  • Requêtes et opérateurs pris en charge pour l'actualisation incrémentielle : Prise en charge et limites des tables dynamiques.

  • Lorsque vous exécutez une actualisation incrémentielle pour la première fois, le système effectue un chargement complet des données et initialise la table d'état utilisée pour le suivi de l'état. Étant donné que toutes les données historiques doivent être traitées en une seule fois et que les structures d'état doivent être initialisées, la consommation de mémoire et de ressources de calcul est nettement plus élevée que lors des cycles incrémentiels suivants. Si le volume de données de la table de base est important ou si les ressources sont insuffisantes, une erreur d'épuisement de la mémoire (OOM) peut se produire.

  • Pour éviter les goulots d'étranglement liés aux ressources, évaluez le volume de données de votre table de base avant la première exécution et utilisez les ressources Serverless Computing pour effectuer la première actualisation. Pour plus d'informations, consultez la section Utiliser Serverless Computing pour la lecture et l'écriture des données.

Jointures stream-stream

Les jointures stream-stream ont la même sémantique que les requêtes OLAP, utilisant HASH JOIN et prenant en charge INNER JOIN, LEFT/RIGHT/FULL OUTER JOIN.

V3.1

Remarque

À partir de Hologres V3.1, le paramètre GUC pour les jointures stream-stream est activé par défaut.

Exemple :

CREATE TABLE users (
  user_id INT,
  user_name TEXT,
  PRIMARY KEY (user_id)
);
INSERT INTO users VALUES(1, 'hologres');

CREATE TABLE orders (
  order_id INT,
  user_id INT,
  PRIMARY KEY (order_id)
);
INSERT INTO orders VALUES(1, 1);

CREATE DYNAMIC TABLE dt WITH (
  auto_refresh_mode = 'incremental',
  freshness='10 minutes'
) 
AS 
SELECT order_id, orders.user_id, user_name 
FROM orders LEFT JOIN users ON orders.user_id = users.user_id;

-- After refresh, one joined record is visible
REFRESH TABLE dt;
SELECT * FROM dt;
 order_id | user_id | user_name 
----------+---------+-----------
        1 |       1 | hologres
(1 row)

UPDATE users SET user_name = 'dynamic table' WHERE user_id = 1;
INSERT INTO orders VALUES(4, 1);

-- After refresh, two joined records are visible. Dimension table updates affect all data and can correct previously joined records.
REFRESH TABLE dt;
SELECT * FROM dt;

Résultat :

order_id | user_id |   user_name   
----------+---------+---------------
        1 |       1 | dynamic table
        4 |       1 | dynamic table
(2 rows)

V3.0

Les jointures stream-stream sont prises en charge depuis la version V3.0.26. Pour activer cette fonctionnalité, mettez à jour votre instance et activez le paramètre GUC :

-- Enable at session level
SET hg_experimental_incremental_dynamic_table_enable_hash_join TO ON;

-- Enable at DB level (takes effect for new connections)
ALTER database <db_name> SET hg_experimental_incremental_dynamic_table_enable_hash_join TO ON;

Exemple :

CREATE TABLE users (
  user_id INT,
  user_name TEXT,
  PRIMARY KEY (user_id)
) WITH (binlog_level = 'replica');
INSERT INTO users VALUES(1, 'hologres');

CREATE TABLE orders (
  order_id INT,
  user_id INT,
  PRIMARY KEY (order_id)
)  WITH (binlog_level = 'replica');
INSERT INTO orders VALUES(1, 1);

CREATE DYNAMIC TABLE dt WITH (refresh_mode = 'incremental') 
AS 
SELECT order_id, orders.user_id, user_name 
FROM orders LEFT JOIN users ON orders.user_id = users.user_id;

-- After refresh, one joined record is visible
REFRESH TABLE dt;
SELECT * FROM dt;
 order_id | user_id | user_name 
----------+---------+-----------
        1 |       1 | hologres
(1 row)

UPDATE users SET user_name = 'dynamic table' WHERE user_id = 1;
INSERT INTO orders VALUES(4, 1);

-- After refresh, two joined records are visible. Dimension table updates affect all data and can correct previously joined records.
REFRESH TABLE dt;
SELECT * FROM dt;

Résultat :

order_id | user_id |   user_name   
----------+---------+---------------
        1 |       1 | dynamic table
        4 |       1 | dynamic table
(2 rows)

Jointures avec table de dimension

Chaque enregistrement du flux est joint avec le dernier instantané de la table de dimension au moment du traitement. Les modifications apportées à la table de dimension après une jointure n'affectent pas les données déjà traitées.

Remarque

Le comportement des jointures avec table de dimension est indépendant de la taille de la table ; il est déterminé par l'instruction JOIN.

V3.1

CREATE TABLE users (
  user_id INT,
  user_name TEXT,
  PRIMARY KEY (user_id)
);
INSERT INTO users VALUES(1, 'hologres');

CREATE TABLE orders (
  order_id INT,
  user_id INT,
  PRIMARY KEY (order_id)
)  WITH (binlog_level = 'replica');

INSERT INTO orders VALUES(1, 1);
CREATE DYNAMIC TABLE dt_join_2 WITH (
    auto_refresh_mode = 'incremental',
    freshness='10 minutes') 
AS 
SELECT order_id, orders.user_id, user_name 
-- FOR SYSTEM_TIME AS OF PROCTIME() identifies 'users' as a dimension table
FROM orders LEFT JOIN users FOR SYSTEM_TIME AS OF PROCTIME()
ON orders.user_id = users.user_id;

-- After refresh, one joined record is visible
REFRESH TABLE dt_join_2;
SELECT * FROM dt_join_2;
 order_id | user_id | user_name 
----------+---------+-----------
        1 |       1 | hologres
(1 row)

UPDATE users SET user_name = 'dynamic table' WHERE user_id = 1;
INSERT INTO orders VALUES(4, 1);

-- After refresh, two joined records are visible. Dimension table updates only affect new data and cannot correct previously joined data.
REFRESH TABLE dt_join_2;
SELECT * FROM dt_join_2;

Résultat :

order_id | user_id |   user_name   
----------+---------+---------------
        1 |       1 | hologres
        4 |       1 | dynamic table
(2 rows)

V3.0

CREATE TABLE users (
  user_id INT,
  user_name TEXT,
  PRIMARY KEY (user_id)
);
INSERT INTO users VALUES(1, 'hologres');

CREATE TABLE orders (
  order_id INT,
  user_id INT,
  PRIMARY KEY (order_id)
)  WITH (binlog_level = 'replica');
INSERT INTO orders VALUES(1, 1);

CREATE DYNAMIC TABLE dt_join_2 WITH (refresh_mode = 'incremental') 
AS 
SELECT order_id, orders.user_id, user_name 
-- FOR SYSTEM_TIME AS OF PROCTIME() identifies 'users' as a dimension table
FROM orders LEFT JOIN users FOR SYSTEM_TIME AS OF PROCTIME()
ON orders.user_id = users.user_id;

-- After refresh, one joined record is visible
REFRESH TABLE dt_join_2;
SELECT * FROM dt_join_2;

order_id | user_id | user_name 
----------+---------+-----------
        1 |       1 | hologres
(1 row)
 
UPDATE users SET user_name = 'dynamic table' WHERE user_id = 1;
INSERT INTO orders VALUES(4, 1);

-- After refresh, two joined records are visible. Dimension table updates only affect new data and cannot correct previously joined data.
REFRESH TABLE dt_join_2;
SELECT * FROM dt_join_2;

Résultat :

order_id | user_id |   user_name   
----------+---------+---------------
        1 |       1 | hologres
        4 |       1 | dynamic table
(2 rows)

Limites

Une colonne obtenue à partir d'une jointure avec une table de dimension est non déterministe : sa valeur dépend à la fois de la ligne actuelle de la table de faits et du contenu de la table de dimension au moment du traitement. À cet égard, elle se comporte comme les fonctions non déterministes NOW() et RAND(). Nous vous recommandons d'utiliser une telle colonne uniquement dans la liste de projection SELECT. Son utilisation ailleurs peut provoquer des erreurs d'actualisation ou des résultats inattendus.

Emplacement d'utilisation

Autorisé

Liste de projection SELECT

Oui

Argument de fonction d'agrégation, tel que SUM(p.price)

Oui, mais non recommandé. Lorsqu'une rétractation déclenche un recalcul, la valeur issue de la table de dimension peut avoir déjà changé, ce qui peut produire des résultats inattendus.

Clé GROUP BY

Non

Prédicat WHERE

Non

Condition ON d'une jointure en aval

Non

Clause PARTITION BY d'une fonction de fenêtrage

Non

Si votre logique métier nécessite un regroupement ou un filtrage par une colonne de table de dimension, utilisez plutôt une jointure stream-stream. Une modification de la table de dimension déclenche alors une rétractation et un recalcul des données historiques, ce qui garantit l'exactitude des résultats.

Cependant, une jointure stream-stream doit maintenir l'état de la jointure, ce qui consomme davantage de ressources lorsque la table de dimension est volumineuse. Des modifications massives apportées à la table de dimension peuvent également déclencher un recalcul étendu en aval.

Consommation incrémentielle des tables lac Paimon

  • L'actualisation incrémentielle prend en charge la consommation des tables Paimon pour les scénarios de lakehouse.

  • Les tables dynamiques externes prennent en charge les lectures incrémentielles et la réécriture, réduisant ainsi le coût de traitement et la latence des requêtes. Présentation des tables dynamiques externes.

Consommation hybride

Les tables dynamiques incrémentielles prennent en charge un modèle hybride : un chargement initial complet de toutes les données existantes de la table de base, suivi d'un traitement incrémentiel continu.

V3.1

La version V3.1 active par défaut le modèle d'actualisation hybride. Exemple :

--Prepare the base table and insert data
CREATE TABLE base_sales(
  day TEXT NOT NULL,
  hour INT,
  user_id BIGINT,
  ts TIMESTAMPTZ,
  amount FLOAT,
  pk text NOT NULL PRIMARY KEY
);

-- Import data into the base table
INSERT INTO base_sales values ('2024-08-29',1,222222,'2024-08-29 16:41:19.141528+08',5,'ddd');

-- Import more data
INSERT INTO base_sales VALUES ('2024-08-29',2,3333,'2024-08-29 17:44:19.141528+08',100,'aaaaa');

-- Create an incremental Dynamic Table
CREATE DYNAMIC TABLE sales_incremental
  WITH (
    auto_refresh_mode='incremental',
    freshness='10 minutes'
  ) 
AS 
  SELECT day, hour, SUM(amount), COUNT(1) 
    FROM base_sales 
  GROUP BY day, hour;

Vérifiez la cohérence des données :

  • Interrogez la table de base

    SELECT day, hour, SUM(amount), COUNT(1) 
        FROM base_sales 
      GROUP BY day, hour;

    Résultat :

    day	    hour	sum	count
    2024-08-29	2	100	1
    2024-08-29	1	5	1
  • Interrogez la table dynamique

    SELECT * FROM sales_incremental;

    Résultat :

    day	    hour	sum	count
    2024-08-29	1	5	1
    2024-08-29	2	100	1

V3.0

Dans la version V3.0, pour utiliser la consommation hybride, activez manuellement le paramètre GUC incremental_guc_hg_experimental_enable_hybrid_incremental_mode. Exemple :

--Prepare the base table, enable Binlog, and insert data
CREATE TABLE base_sales(
  day TEXT NOT NULL,
  hour INT,
  user_id BIGINT,
  ts TIMESTAMPTZ,
  amount FLOAT,
  pk text NOT NULL PRIMARY KEY
);

-- Import data into the base table
INSERT INTO base_sales values ('2024-08-29',1,222222,'2024-08-29 16:41:19.141528+08',5,'ddd');

-- Enable Binlog for the base table
ALTER TABLE base_sales SET (binlog_level = replica);

-- Import incremental data into the base table
INSERT INTO base_sales VALUES ('2024-08-29',2,3333,'2024-08-29 17:44:19.141528+08',100,'aaaaa');

-- Create an auto-refreshing incremental Dynamic Table and enable the GUC for hybrid consumption
CREATE DYNAMIC TABLE sales_incremental
  WITH (
    refresh_mode='incremental',
    incremental_auto_refresh_schd_start_time = 'immediate',
    incremental_auto_refresh_interval = '3 minutes',
    incremental_guc_hg_experimental_enable_hybrid_incremental_mode= 'true'
  ) 
AS 
  SELECT day, hour, SUM(amount), COUNT(1) 
    FROM base_sales 
  GROUP BY day, hour;

Vérifiez la cohérence des données :

  • Interrogez la table de base

    SELECT day, hour, SUM(amount), COUNT(1) 
        FROM base_sales 
      GROUP BY day, hour;

    Résultat :

    day	    hour	sum	count
    2024-08-29	2	100	1
    2024-08-29	1	5	1
  • Interrogez la table dynamique

    SELECT * FROM sales_incremental;

    Résultat :

    day	    hour	sum	count
    2024-08-29	1	5	1
    2024-08-29	2	100	1

Actualisation complète

L'actualisation complète réécrit l'intégralité du jeu de données issu de la requête. Par rapport à l'actualisation incrémentielle :

  • Elle prend en charge davantage de types de tables de base.

  • Elle offre un éventail plus large de types de requêtes et d'opérateurs.

L'actualisation complète utilise davantage de ressources. Elle est idéale pour les rapports périodiques et les remplissages rétroactifs de données.

Remarque

Pour plus d'informations, consultez la section Actualisation complète.

Exemples

V3.1

Exemple 1 : Créer une table dynamique incrémentielle standard

Avant de commencer, importez le jeu de données public tpch_10g dans Hologres en suivant le guide disponible à la rubrique Importer des jeux de données publics en quelques clics.

Remarque

Avant de créer une table dynamique incrémentielle, activez le journal binaire (Binlog) pour la table de base (cette étape n'est pas requise pour les tables de dimension).

-- Create an Incremental Dynamic Table that refreshes every 3 minutes.
CREATE DYNAMIC TABLE public.tpch_q1_incremental 
WITH (
auto_refresh_mode='incremental',
freshness='3 minutes'
) AS SELECT
        l_returnflag,
        l_linestatus,
        COUNT(*) AS count_order
FROM
        hologres_dataset_tpch_10g.lineitem
WHERE
        l_shipdate <= DATE '1998-12-01' - INTERVAL '120' DAY
GROUP BY
        l_returnflag,
        l_linestatus;

Exemple 2 : Créer une table dynamique incrémentielle à partir de jointures flux-flux

Avant de commencer, importez le jeu de données public tpch_10g dans Hologres en suivant le guide disponible à la rubrique Importer des jeux de données publics en quelques clics.

Remarque

Avant de créer une table dynamique incrémentielle, activez le journal binaire (Binlog) pour la table de base (cette étape n'est pas requise pour la table de dimension).

-- Create an Incremental Dynamic Table from stream-stream joins.
CREATE DYNAMIC TABLE dt_join
  WITH (
    auto_refresh_mode='incremental',
    freshness='30 minutes'
  ) 
AS 
SELECT
        l_shipmode,
        SUM(CASE
                WHEN o_orderpriority = '1-URGENT'
                        OR o_orderpriority = '2-HIGH'
                        THEN 1
                ELSE 0
        END) AS high_line_count,
        SUM(CASE
                WHEN o_orderpriority <> '1-URGENT'
                        AND o_orderpriority <> '2-HIGH'
                        THEN 1
                ELSE 0
        END) AS low_line_count
FROM
        hologres_dataset_tpch_10g.orders,
        hologres_dataset_tpch_10g.lineitem
WHERE
        o_orderkey = l_orderkey
        AND l_shipmode IN ('FOB', 'AIR')
        AND l_commitdate < l_receiptdate
        AND l_shipdate < l_commitdate
        AND l_receiptdate >= DATE '1997-01-01'
        AND l_receiptdate < DATE '1997-01-01' + INTERVAL '1' YEAR
GROUP BY
        l_shipmode;

Exemple 3 : Créer une table dynamique avec actualisation automatique

Définissez le mode d'actualisation sur auto. Le moteur privilégie l'actualisation incrémentielle et bascule vers une actualisation complète si celle-ci n'est pas prise en charge.

Avant de commencer, importez le jeu de données public tpch_10g dans Hologres en suivant le guide disponible à la rubrique Importer des jeux de données publics en quelques clics.

-- Create an Auto-refresh Dynamic Table that intelligent decides the refresh mode. In this example, incremental refresh is the result.
CREATE DYNAMIC TABLE thch_q6_auto
  WITH (
    auto_refresh_mode='auto',
    freshness='1 hours'
       ) 
AS
SELECT
        SUM(l_extendedprice * l_discount) AS revenue
FROM
        hologres_dataset_tpch_100g.lineitem
WHERE
        l_shipdate >= DATE '1996-01-01'
        AND l_shipdate < DATE '1996-01-01' + INTERVAL '1' YEAR
        AND l_discount BETWEEN 0.02 - 0.01 AND 0.02 + 0.01
        AND l_quantity < 24;

Exemple 4 : Créer une table dynamique avec partitionnement logique

Pour un tableau de bord transactionnel en temps réel, il est souvent nécessaire de consulter les données actuelles en quasi-temps réel tout en corrigeant les données historiques. Cela requiert une solution intégrée d'analyse en temps réel et hors ligne (Connaissance métier et des données). Nous utilisons généralement des partitions logiques de Dynamic Table pour ce scénario. La démarche est la suivante :

  • La table de base est partitionnée par jour. La dernière partition est alimentée par Flink en temps réel ou en quasi-temps réel, tandis que les partitions historiques sont écrites depuis MaxCompute.

  • La table dynamique est créée sous forme de table à partitions logiques. Les deux dernières partitions sont actives et actualisées de manière incrémentielle pour l'analyse des données en quasi-temps réel.

  • Les partitions historiques sont inactives et utilisent une actualisation complète. Si les partitions historiques de la table de base ont été corrigées ou réinjectées, elles peuvent être actualisées via une actualisation complète.

Cet exemple utilise un jeu de données public provenant de GitHub.

  1. Préparez la table de base.

    Utilisez Flink pour écrire les dernières données dans la table de base. Pour obtenir la procédure détaillée, consultez la rubrique Analyse unifiée par lots et en temps réel des événements GitHub.

    DROP TABLE IF EXISTS gh_realtime_data;
    
    BEGIN;
    CREATE TABLE gh_realtime_data (
        id BIGINT,
        actor_id BIGINT,
        actor_login TEXT,
        repo_id BIGINT,
        repo_name TEXT,
        org_id BIGINT,
        org_login TEXT,
        type TEXT,
        created_at timestamp with time zone NOT NULL,
        action TEXT,
        iss_or_pr_id BIGINT,
        number BIGINT,
        comment_id BIGINT,
        commit_id TEXT,
        member_id BIGINT,
        rev_or_push_or_rel_id BIGINT,
        ref TEXT,
        ref_type TEXT,
        state TEXT,
        author_association TEXT,
        language TEXT,
        merged BOOLEAN,
        merged_at TIMESTAMP WITH TIME ZONE,
        additions BIGINT,
        deletions BIGINT,
        changed_files BIGINT,
        push_size BIGINT,
        push_distinct_size BIGINT,
        hr TEXT,
        month TEXT,
        year TEXT,
        ds TEXT,
        PRIMARY KEY (id,ds)
    )
    PARTITION BY LIST (ds);
    CALL set_table_property('public.gh_realtime_data', 'distribution_key', 'id');
    CALL set_table_property('public.gh_realtime_data', 'event_time_column', 'created_at');
    CALL set_table_property('public.gh_realtime_data', 'clustering_key', 'created_at');
    
    COMMENT ON COLUMN public.gh_realtime_data.id IS 'Event ID';
    COMMENT ON COLUMN public.gh_realtime_data.actor_id IS 'Event actor ID';
    COMMENT ON COLUMN public.gh_realtime_data.actor_login IS 'Event actor login name';
    COMMENT ON COLUMN public.gh_realtime_data.repo_id IS 'Repo ID';
    COMMENT ON COLUMN public.gh_realtime_data.repo_name IS 'Repo name';
    COMMENT ON COLUMN public.gh_realtime_data.org_id IS 'Repo organization ID';
    COMMENT ON COLUMN public.gh_realtime_data.org_login IS 'Repo organization name';
    COMMENT ON COLUMN public.gh_realtime_data.type IS 'Event type';
    COMMENT ON COLUMN public.gh_realtime_data.created_at IS 'Event time';
    COMMENT ON COLUMN public.gh_realtime_data.action IS 'Event action';
    COMMENT ON COLUMN public.gh_realtime_data.iss_or_pr_id IS 'Issue/pull_request ID';
    COMMENT ON COLUMN public.gh_realtime_data.number IS 'Issue/pull_request number';
    COMMENT ON COLUMN public.gh_realtime_data.comment_id IS 'Comment ID';
    COMMENT ON COLUMN public.gh_realtime_data.commit_id IS 'Commit ID';
    COMMENT ON COLUMN public.gh_realtime_data.member_id IS 'Member ID';
    COMMENT ON COLUMN public.gh_realtime_data.rev_or_push_or_rel_id IS 'Review/push/release ID';
    COMMENT ON COLUMN public.gh_realtime_data.ref IS 'Name of created/deleted resource';
    COMMENT ON COLUMN public.gh_realtime_data.ref_type IS 'Type of created/deleted resource';
    COMMENT ON COLUMN public.gh_realtime_data.state IS 'State of issue/pull_request/pull_request_review';
    COMMENT ON COLUMN public.gh_realtime_data.author_association IS 'Relationship between actor and repo';
    COMMENT ON COLUMN public.gh_realtime_data.language IS 'Programming language';
    COMMENT ON COLUMN public.gh_realtime_data.merged IS 'Whether merged';
    COMMENT ON COLUMN public.gh_realtime_data.merged_at IS 'Merge time';
    COMMENT ON COLUMN public.gh_realtime_data.additions IS 'Number of added lines';
    COMMENT ON COLUMN public.gh_realtime_data.deletions IS 'Number of deleted lines';
    COMMENT ON COLUMN public.gh_realtime_data.changed_files IS 'Number of changed files in pull request';
    COMMENT ON COLUMN public.gh_realtime_data.push_size IS 'Number of pushes';
    COMMENT ON COLUMN public.gh_realtime_data.push_distinct_size IS 'Number of distinct pushes';
    COMMENT ON COLUMN public.gh_realtime_data.hr IS 'Hour of event, e.g., 00 for 00:23';
    COMMENT ON COLUMN public.gh_realtime_data.month IS 'Month of event, e.g., 2015-10 for Oct 2015';
    COMMENT ON COLUMN public.gh_realtime_data.year IS 'Year of event, e.g., 2015';
    COMMENT ON COLUMN public.gh_realtime_data.ds IS 'Date of event, ds=yyyy-mm-dd';
    
    COMMIT;
  2. Créez une table dynamique avec partitionnement logique.

    CREATE  DYNAMIC TABLE ads_dt_github_event
    LOGICAL PARTITION BY LIST(ds)
    WITH (
      -- Dynamic table properties
      freshness = '5 minutes', 
      auto_refresh_mode = 'auto', 
      auto_refresh_partition_active_time = '2 days' ,
      partition_key_time_format = 'YYYY-MM-DD'
    )
    AS
    SELECT
        repo_name,
        COUNT(*) AS events,
        ds
    FROM
        gh_realtime_data
    GROUP BY repo_name,ds
  3. Interrogez la table dynamique.

    SELECT * FROM ads_dt_github_event ;
  4. Réinjectez une partition historique.

    Si les données historiques de la table de base changent (par exemple, les données du « 2025-04-01 ») et que la table dynamique doit être mise à jour, définissez la partition historique sur le mode d'actualisation complète et déclenchez une actualisation, de préférence avec des ressources Serverless Computing.

    REFRESH OVERWRITE DYNAMIC TABLE ads_dt_github_event
    PARTITION (ds = '2025-04-01') 
    WITH (
      refresh_mode = 'full'
    );

Exemple 5 : Calculer les UV avec une table dynamique incrémentielle

À partir de Hologres V3.1, une table dynamique incrémentielle prend en charge la fonction RB_BUILD_AGG pour des calculs tels que le nombre d'utilisateurs uniques (UV). Par rapport à la pré-agrégation, cette approche offre :

  • De meilleures performances : seules les données incrémentielles sont traitées.

  • Un coût réduit : le volume de données et l'utilisation des ressources sont diminués, permettant des calculs sur des périodes plus longues.

Exemple :

  1. Préparez une table de détails utilisateur.

    BEGIN;
    CREATE TABLE IF NOT EXISTS ods_app_detail (
         uid INT,
         country TEXT,
         prov TEXT,
         city TEXT,
         channel TEXT,
         operator TEXT,
         brand TEXT,
         ip TEXT,
         click_time TEXT,
         year TEXT,
         month TEXT,
         day TEXT,
         ymd TEXT NOT NULL
    );
    CALL set_table_property('ods_app_detail', 'orientation', 'column');
    CALL set_table_property('ods_app_detail', 'bitmap_columns', 'country,prov,city,channel,operator,brand,ip,click_time, year, month, day, ymd');
    -- Set distribution_key based on query needs for optimal sharding effect.
    CALL set_table_property('ods_app_detail', 'distribution_key', 'uid');
    -- For a field with full date-time used in WHERE filters, setting it as clustering_key and event_time_column is recommended.
    CALL set_table_property('ods_app_detail', 'clustering_key', 'ymd');
    CALL set_table_property('ods_app_detail', 'event_time_column', 'ymd');
    COMMIT;
  2. Calculez les UV à l'aide d'une table dynamique incrémentielle.

    CREATE DYNAMIC TABLE ads_uv_dt
      WITH (
        freshness = '5 minutes', 
        auto_refresh_mode = 'incremental') 
      AS 
    SELECT  
     RB_BUILD_AGG(uid),
     country,
     prov,
     city,
     ymd,
    COUNT(1)
    FROM    ods_app_detail
    WHERE ymd >= '20231201' AND ymd <='20240502'
    GROUP BY country,prov,city,ymd;
  3. Consultez les UV pour une journée spécifique.

    SELECT  
    RB_CARDINALITY(RB_OR_AGG(rb_uid)) AS uv,
      country,
      prov,
      city,
      SUM(pv) AS pv
    FROM    ads_uv_dt
    WHERE   ymd = '20240329'
    GROUP BY country,prov,city;

V3.0

Exemple 1 : Créer une table dynamique à actualisation complète avec démarrage automatique

Avant de commencer, importez le jeu de données public tpch_10g dans Hologres en suivant le guide disponible à la rubrique Importer des jeux de données publics en quelques clics.

--Create "test" Schema
CREATE SCHEMA test;

--Create a single-table full refresh dynamic table, starting immediately and refreshing every hour.
CREATE DYNAMIC TABLE test.thch_q1_full
  WITH (
    refresh_mode='full',
    auto_refresh_enable='true',
    full_auto_refresh_interval='1 hours',
    full_guc_hg_computing_resource='serverless',
    full_guc_hg_experimental_serverless_computing_required_cores='32'
       ) 
AS
  SELECT
        l_returnflag,
        l_linestatus,
        SUM(l_quantity) AS sum_qty,
        SUM(l_extendedprice) AS sum_base_price,
        SUM(l_extendedprice * (1 - l_discount)) AS sum_disc_price,
        SUM(l_extendedprice * (1 - l_discount) * (1 + l_tax)) AS sum_charge,
        AVG(l_quantity) AS avg_qty,
        AVG(l_extendedprice) AS avg_price,
        AVG(l_discount) AS avg_disc,
        COUNT(*) AS count_order
FROM
        hologres_dataset_tpch_10g.lineitem
WHERE
        l_shipdate <= DATE '1998-12-01' - INTERVAL '120' DAY
GROUP BY
        l_returnflag,
        l_linestatus;

Exemple 2 : Créer une table dynamique incrémentielle avec une heure de début

Avant de commencer, importez le jeu de données public tpch_10g dans Hologres en suivant le guide disponible à la rubrique Importer des jeux de données publics en quelques clics.

Exemple :

Remarque

Avant de créer une Dynamic Table incrémentielle, vous devez activer le journal binaire (Binlog) pour la table de base (cette étape n'est pas requise pour les tables de dimension).

--Enable binlog for the base table:
BEGIN;
CALL set_table_property('hologres_dataset_tpch_10g.lineitem', 'binlog.level', 'replica');
COMMIT;

--Create a single-table incremental refresh dynamic table, specifying a start time and a 3-minute refresh interval.
CREATE DYNAMIC TABLE public.tpch_q1_incremental 
WITH (
refresh_mode='incremental',
auto_refresh_enable='true',
incremental_auto_refresh_schd_start_time='2024-09-15 23:50:0',
incremental_auto_refresh_interval='3 minutes',
incremental_guc_hg_computing_resource='serverless',
incremental_guc_hg_experimental_serverless_computing_required_cores='30'
) AS SELECT
        l_returnflag,
        l_linestatus,
        COUNT(*) AS count_order
FROM
        hologres_dataset_tpch_10g.lineitem
WHERE
        l_shipdate <= DATE '1998-12-01' - INTERVAL '120' DAY
GROUP BY
        l_returnflag,
        l_linestatus
;

Exemple 3 : Créer une table dynamique à actualisation complète avec jointures multiples

--Create a dynamic table with a multi-table join query, using full refresh mode every 3 hours.
CREATE DYNAMIC TABLE dt_q_full
  WITH (
    refresh_mode='full',
    auto_refresh_enable='true',
    full_auto_refresh_schd_start_time='immediate',
    full_auto_refresh_interval='3 hours',
    full_guc_hg_computing_resource='serverless',
    full_guc_hg_experimental_serverless_computing_required_cores='64'
  ) 
AS 
SELECT
        o_orderpriority,
        COUNT(*) AS order_count
FROM
        hologres_dataset_tpch_10g.orders
WHERE
        o_orderdate >= DATE '1996-07-01'
        AND o_orderdate < DATE '1996-07-01' + INTERVAL '3' MONTH
        AND EXISTS (
                SELECT
                        *
                FROM
                        hologres_dataset_tpch_10g.lineitem
                WHERE
                        l_orderkey = o_orderkey
                        AND l_commitdate < l_receiptdate
        )
GROUP BY
        o_orderpriority;

Exemple 4 : Créer une table dynamique incrémentielle avec jointure de dimension

Exemple :

Remarque

Avant de créer une Dynamic Table incrémentielle, vous devez activer le journal binaire (Binlog) pour la table de base (cette étape n'est pas requise pour les tables de dimension).

La sémantique d'une jointure avec une table de dimension implique que chaque enregistrement est joint uniquement avec la dernière version des données de la table de dimension à cet instant, c'est-à-dire que la jointure s'effectue au moment du traitement. Si les données de la table de dimension changent (ajout, mise à jour ou suppression) après la jointure, les données déjà jointes ne sont pas mises à jour. Exemple SQL :

--Detail table
BEGIN;
CREATE TABLE public.sale_detail(
        app_id TEXT,
        uid TEXT,
        product TEXT,
        gmv BIGINT,
        order_time TIMESTAMPTZ
);
--Enable binlog for the base table; dimension tables do not require it.
CALL set_table_property('public.sale_detail', 'binlog.level', 'replica');
COMMIT;

--Property table
CREATE TABLE public.user_info(
        uid TEXT,
        province TEXT,
        city TEXT
);

CREATE DYNAMIC TABLE public.dt_sales_incremental
  WITH (
    refresh_mode='incremental',
    auto_refresh_enable='true',
    incremental_auto_refresh_schd_start_time='2024-09-15 00:00:00',
    incremental_auto_refresh_interval='5 minutes',
    incremental_guc_hg_computing_resource='serverless',
    incremental_guc_hg_experimental_serverless_computing_required_cores='128') 
AS 
SELECT 
    sale_detail.app_id,
    sale_detail.uid,
    product,
    SUM(sale_detail.gmv) AS sum_gmv,
    sale_detail.order_time,
    user_info.province,
    user_info.city 
FROM public.sale_detail 
INNER JOIN public.user_info  FOR SYSTEM_TIME AS OF PROCTIME()
ON sale_detail.uid =user_info.uid
GROUP BY sale_detail.app_id,sale_detail.uid,sale_detail.product,sale_detail.order_time,user_info.province,user_info.city;

Exemple 5 : Créer une table dynamique partitionnée

Pour un tableau de bord transactionnel en temps réel, il est souvent nécessaire de consulter les données actuelles en quasi-temps réel tout en corrigeant les données historiques. Cela peut être réalisé en combinant l'actualisation incrémentielle et complète de Dynamic Table. La démarche est la suivante :

  1. Créez une table de base partitionnée où la dernière partition est écrite en temps réel ou en quasi-temps réel, et les partitions historiques sont occasionnellement corrigées.

  2. Créez une Dynamic Table en tant que table parente partitionnée. Utilisez l'actualisation incrémentielle pour la dernière partition afin de répondre aux besoins d'analyse en quasi-temps réel.

  3. Basculez les partitions historiques en mode d'actualisation complète. Si les partitions historiques de la table source ont été corrigées, les partitions de la Dynamic Table peuvent également être réinjectées via une actualisation complète, de préférence avec Serverless pour accélérer le processus.

Exemple :

  1. Préparez la table de base et les données.

    La table de base est une table partitionnée, la dernière partition recevant les données en temps réel.

    -- Create a partitioned source table
    CREATE TABLE base_sales(
      uid INT,
      opreate_time TIMESTAMPTZ,
      amount FLOAT,
      tt TEXT NOT NULL,
      ds TEXT,
      PRIMARY KEY(ds)
    ) PARTITION BY LIST (ds) ;
    
    --Historical partition
    CREATE TABLE base_sales_20240615 PARTITION OF base_sales FOR VALUES IN ('20240615');
    INSERT INTO base_sales_20240615 VALUES (2,'2024-06-15 16:18:25.387466+08','111','2','20240615');
    
    --Latest partition, typically for real-time writes
    CREATE TABLE base_sales_20240616 PARTITION OF base_sales FOR VALUES IN ('20240616');
    INSERT INTO base_sales_20240616 VALUES (1,'2024-06-16 16:08:25.387466+08','2','1','20240616');
  2. Créez la table parente Dynamic Table partitionnée, en définissant uniquement la requête sans mode d'actualisation.

    --Create extension
    CREATE EXTENSION roaringbitmap;
    
    CREATE DYNAMIC TABLE partition_dt_base_sales
    PARTITION BY LIST (ds)
    as
    SELECT  
     public.RB_BUILD_AGG(uid),
     opreate_time,
     amount,
     tt,
     ds,
    COUNT(1)
    FROM    base_sales
    GROUP BY opreate_time ,amount,tt,ds;
  3. Créez les sous-tables et définissez leurs modes d'actualisation.

    Vous pouvez créer manuellement les sous-partitions de Dynamic Table ou les générer dynamiquement à l'aide de DataWorks. Définissez la dernière partition sur l'actualisation incrémentielle et les partitions historiques sur l'actualisation complète.

    -- Enable Binlog for the base table
    ALTER TABLE base_sales SET (binlog_level = replica);
    
    -- Assume the historical Dynamic Table sub-partition is as follows:
    CREATE DYNAMIC TABLE partition_dt_base_sales_20240615 PARTITION OF partition_dt_base_sales FOR VALUES IN ('20240615')
      WITH (
        refresh_mode='incremental',
        auto_refresh_enable='true',
        incremental_auto_refresh_schd_start_time='immediate',
        incremental_auto_refresh_interval='30 minutes'
           );
    
    -- Create a new Dynamic Table sub-partition, set its refresh mode to incremental, start immediately, refresh every 30 minutes, and use instance resources.
    CREATE DYNAMIC TABLE partition_dt_base_sales_20240616 PARTITION OF partition_dt_base_sales FOR VALUES IN ('20240616')
      WITH (
        refresh_mode='incremental',
        auto_refresh_enable='true',
        incremental_auto_refresh_schd_start_time='immediate',
        incremental_auto_refresh_interval='30 minutes'
           );
    
    --Switch the historical partition to full refresh mode
    ALTER DYNAMIC TABLE partition_dt_base_sales_20240615 SET (refresh_mode = 'full');
    --If historical partition data needs correction, execute a refresh, preferably with serverless.
    SET hg_computing_resource = 'serverless';
    REFRESH DYNAMIC TABLE partition_dt_base_sales_20240615;

Convertir l'ancienne syntaxe vers la nouvelle syntaxe

Hologres V3.1 a modifié la syntaxe de création des tables dynamiques. Après la mise à niveau depuis la V3.0, recréez les tables dynamiques avec la nouvelle syntaxe. Un outil de conversion simplifie ce processus.

Scénarios

  • Les tables dynamiques incrémentielles doivent être recréées avec la nouvelle syntaxe.

  • Incompatibilités de syntaxe détectées lors de la vérification de la mise à niveau. Consultez votre rapport de vérification de mise à niveau pour plus de détails.

Remarque

À l'exception des scénarios ci-dessus, les tables dynamiques de la V3.0 ne nécessitent pas de recréation dans Hologres V3.1. Toutefois, seule l'instruction ALTER DYNAMIC TABLE peut être exécutée sur celles-ci. L'instruction CREATE DYNAMIC TABLE (ancienne syntaxe) n'est pas prise en charge dans les versions V3.1 et ultérieures.

Limitations

La commande de conversion de syntaxe est limitée aux tables non partitionnées (incrémentielles et à actualisation complète). Pour les tables dynamiques partitionnées de la V3.0, recréez-les manuellement.

Afficher les tables dynamiques nécessitant une conversion de syntaxe

Identifiez les tables de votre instance qui nécessitent une conversion après une mise à niveau :

Tables non partitionnées

SELECT DISTINCT 
    p.dynamic_table_namespace as table_namespace, 
    p.dynamic_table_name as table_name
FROM hologres.hg_dynamic_table_properties p
JOIN pg_class c ON c.relname = p.dynamic_table_name
JOIN pg_namespace n ON n.oid = c.relnamespace AND n.nspname = p.dynamic_table_namespace
WHERE p.property_key = 'refresh_mode' 
    AND p.property_value = 'incremental'
    AND c.relispartition = false 
    AND c.relkind != 'p';

Tables partitionnées

SELECT DISTINCT 
    pn.nspname as parent_schema,
    pc.relname as parent_name
FROM hologres.hg_dynamic_table_properties p
JOIN pg_class c ON c.relname = p.dynamic_table_name
JOIN pg_namespace n ON n.oid = c.relnamespace AND n.nspname = p.dynamic_table_namespace
JOIN pg_inherits i ON c.oid = i.inhrelid
JOIN pg_class pc ON pc.oid = i.inhparent
JOIN pg_namespace pn ON pn.oid = pc.relnamespace
WHERE p.property_key = 'refresh_mode' 
    AND p.property_value = 'incremental'
    AND c.relispartition = true 
    AND c.relkind != 'p';

Effectuer la conversion de syntaxe

Remarques :

  • Version requise : V3.1.11 et ultérieures.

  • Rôle requis : Superutilisateur.

  • Modifications du comportement après conversion :

    • L'actualisation automatique démarre immédiatement si le mode d'actualisation est auto. Assurez-vous que l'opération s'effectue pendant les heures creuses pour éviter toute contention des ressources. Pour une meilleure isolation, utilisez des ressources Serverless Computing.

    • Modifications de l'utilisation des ressources pour les instances de virtual warehouse :

      • V3.1/V3.2 (nouvelle syntaxe) : L'actualisation des tables dynamiques utilise les ressources des virtual warehouses principaux des groupes de tables des tables de base et des tables dynamiques.

      • V3.0 (ancienne syntaxe) et V4.1 (nouvelle syntaxe) : L'actualisation des tables dynamiques utilise les ressources du virtual warehouse principal du groupe de tables de la table dynamique.

    • La nouvelle syntaxe ajoute une connexion par table dynamique pour la planification. Si votre instance utilise un nombre élevé de connexions, libérez d'abord les connexions inactives.

Commandes :

-- Only for non-partitioned tables (full and incremental).
-- Convert a single Dynamic Table
call hg_dynamic_table_config_upgrade('<table_name>');

-- Convert all Dynamic Tables. Use with caution.
call hg_upgrade_all_normal_dynamic_tables();
Remarque

Ces commandes convertissent les tables dynamiques (ancienne syntaxe) de la base de données actuelle vers la nouvelle syntaxe.

Correspondances des paramètres de syntaxe

La commande mappe les paramètres et valeurs de la V3.0 et de la V3.1 comme suit :

Ancienne syntaxe (V3.0)

Nouvelle syntaxe (V3.1+)

Description

refresh_mode

auto_refresh_mode

La valeur du paramètre est conservée après la conversion. Par exemple, refresh_mode='incremental' devient auto_refresh_mode='incremental'.

auto_refresh_enable

auto_refresh_enable

La valeur du paramètre est conservée après la conversion.

{refresh_mode}_auto_refresh_schd_start_time

freshness

La valeur auto_refresh_interval devient la valeur freshness.

Par exemple, full_auto_refresh_interval='30 minutes' devient freshness='30 minutes'.

{refresh_mode}_auto_refresh_interval

{refresh_mode}_guc_hg_computing_resource

computing_resource

La valeur du paramètre est conservée après la conversion. Par exemple, full_guc_hg_computing_resource='serverless' devient computing_resource='serverless'.

{refresh_mode}guc_hg_experimental_serverless_computing_required_cores

refresh_guc_hg_experimental_serverless_computing_required_cores

La valeur du paramètre est conservée après la conversion.

{refresh_mode}guc<guc>

refresh_guc<guc_name>

La valeur du paramètre est conservée après la conversion. Par exemple, incremental_guc_hg_experimental_max_consumed_rows_per_refresh='1000000' devient refresh_guc_hg_experimental_max_consumed_rows_per_refresh='1000000'.

Propriétés de table (par exemple, orientation)

Propriétés de table (par exemple, orientation)

Les propriétés de base de la table restent inchangées.

Références

FAQ

  • Q : Comment corriger l'erreur liée à une clé de segment ou de clustering null ? Exemple :

    ERROR: commit ddl phase1 failed: the index partition key "xxx" should not be nullable
  • Cause : La clé de segment ou de clustering d'une table dynamique ne peut pas être null. Pour connaître les règles de définition de ces clés, consultez la rubrique Colonne d'heure d'événement (clé de segment).

  • Solution :

    1. Erreur de clé de clustering : Pour les versions de Hologres antérieures à la V3.1.26, V3.2.9 et V4.0.0, mettez à niveau votre instance et modifiez le paramètre GUC suivant pour autoriser une clé de clustering pouvant être null :

      -- For V3.1 and later
      ALTER DYNAMIC TABLE [ IF EXISTS ] [<schema>.]<table_name> SET
      (refresh_guc_hg_experimental_enable_nullable_segment_key=true);
    2. Erreur de clé de segment : Exécutez la commande suivante pour autoriser une clé de segment pouvant être null. À partir de Hologres V4.1, les clés de segment peuvent être null par défaut. Nous vous recommandons donc de mettre à niveau votre instance pour corriger l'erreur.

      --For V3.1 and later, allows a nullable clustering key
      ALTER DYNAMIC TABLE [ IF EXISTS ] [<schema>.]<table_name> SET
      (refresh_guc_hg_experimental_enable_nullable_clustering_key=true);