Utilisez l'instruction CREATE TABLE pour définir la disposition de stockage d'une table dans Hologres. Il est essentiel de configurer correctement le mode de stockage, la clé de distribution et les index dès la création, car la plupart de ces propriétés ne peuvent pas être modifiées ultérieurement.
Prérequis
Avant de commencer, assurez-vous de disposer des éléments suivants :
Une connexion à la base de données cible — HoloWeb est l'outil recommandé pour exécuter les requêtes
Démarrage rapide
Cet exemple crée une table de détails de transaction en utilisant la syntaxe CREATE TABLE WITH (disponible à partir de Hologres V2.1). Il applique une convention de nommage hiérarchique, définit plusieurs champs et inclut des commentaires de métadonnées.
BEGIN;
-- Create a transaction details fact table.
-- Use the public schema and follow the hierarchical naming convention (dwd_xxx).
CREATE TABLE IF NOT EXISTS public.dwd_trade_orders (
order_id BIGINT NOT NULL,
shop_id INT NOT NULL,
user_id TEXT NOT NULL,
order_amount NUMERIC(12, 2) DEFAULT 0.00,
payment NUMERIC(12, 2) DEFAULT 0.00,
payment_type INT DEFAULT 0, -- 0: Unpaid, 1: Alipay, 2: WeChat Pay, 3: Credit Card
is_delivered BOOLEAN DEFAULT false,
dt TEXT NOT NULL, -- Data timestamp, in YYYYMMDD format
order_time TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (order_id)
)
WITH (
orientation = 'column', -- Column-oriented: best for OLAP aggregation on large datasets
distribution_key = 'order_id', -- Shard data by order_id for even distribution
clustering_key = 'order_time:asc', -- Sort data by time within files to accelerate range queries
event_time_column = 'order_time', -- Enable file-level clipping for time range filters
bitmap_columns = 'shop_id,payment_type,is_delivered', -- Accelerate equality filters on low-cardinality columns
dictionary_encoding_columns = 'user_id:auto' -- Accelerate GROUP BY and FILTER on string columns
);
-- Add metadata comments.
COMMENT ON TABLE public.dwd_trade_orders IS 'Base fact table for transaction order details.';
COMMENT ON COLUMN public.dwd_trade_orders.order_id IS 'The unique identifier of the order.';
COMMENT ON COLUMN public.dwd_trade_orders.shop_id IS 'The unique ID of the shop.';
COMMENT ON COLUMN public.dwd_trade_orders.user_id IS 'The ID of the buyer.';
COMMENT ON COLUMN public.dwd_trade_orders.dt IS 'The data timestamp, in YYYYMMDD format.';
COMMENT ON COLUMN public.dwd_trade_orders.order_time IS 'The precise timestamp when the order was created.';
COMMIT;
Consulter le schéma de la table
Exécutez la requête suivante pour récupérer l'instruction LDD (Langage de Définition de Données) de la table :
SELECT hg_dump_script('public.dwd_trade_orders');
Insérer des données
Hologres est compatible avec la syntaxe standard du langage de manipulation de données (DML). L'instruction suivante insère 10 lignes de données d'exemple :
INSERT INTO public.dwd_trade_orders
(order_id, shop_id, user_id, order_amount, payment, payment_type, is_delivered, dt, order_time)
VALUES
(50001, 101, 'U678', 299.00, 280.00, 1, true, '20231101', '2023-11-01 10:00:01+08'),
(50002, 102, 'U992', 59.00, 59.00, 2, false, '20231101', '2023-11-01 10:05:12+08'),
(50003, 101, 'U441', 150.00, 145.00, 1, true, '20231101', '2023-11-01 10:10:45+08'),
(50004, 105, 'U219', 888.00, 888.00, 3, true, '20231101', '2023-11-01 10:20:11+08'),
(50005, 102, 'U883', 35.00, 30.00, 1, false, '20231101', '2023-11-01 10:32:00+08'),
(50006, 110, 'U007', 120.50, 120.50, 2, true, '20231101', '2023-11-01 10:45:33+08'),
(50007, 101, 'U321', 210.00, 210.00, 1, true, '20231101', '2023-11-01 11:02:19+08'),
(50008, 108, 'U556', 45.00, 45.00, 2, false, '20231101', '2023-11-01 11:15:04+08'),
(50009, 101, 'U112', 300.00, 290.00, 3, true, '20231101', '2023-11-01 11:25:55+08'),
(50010, 105, 'U449', 99.90, 99.90, 1, true, '20231101', '2023-11-01 11:40:22+08');
Interroger les données
-- Calculate the total transaction amount per shop, sorted in descending order.
SELECT
shop_id,
COUNT(1) AS total_orders,
SUM(payment) AS total_payment
FROM public.dwd_trade_orders
GROUP BY shop_id
ORDER BY total_payment DESC;
Résultat attendu :
shop_id total_orders total_payment
105 2 987.90
101 4 925.00
110 1 120.50
102 1 59.00
108 1 45.00
Syntaxe
Syntaxe CREATE TABLE
Hologres prend en charge deux syntaxes pour définir les propriétés de table et les commentaires :
Syntaxe standard (recommandée pour Hologres V2.1 et versions ultérieures)
Utilisez le mot-clé WITH pour définir les propriétés directement. Cette syntaxe est plus concise et offre de meilleures performances.
BEGIN;
CREATE TABLE [IF NOT EXISTS] [schema_name.]table_name (
{
column_name column_type [column_constraints, [...]]
| table_constraints
[,...]
}
)
[WITH (
property = 'value'
[, ...]
)];
[COMMENT ON COLUMN <[schema_name.]tablename.column> IS '<value>';]
[COMMENT ON TABLE <[schema_name.]tablename> IS '<value>';]
COMMIT;
Syntaxe compatible (prise en charge dans toutes les versions)
Utilisez CALL set_table_property pour définir les propriétés et COMMENT pour ajouter des commentaires. Toutes les instructions doivent figurer dans le même bloc de transaction BEGIN...COMMIT que l'instruction CREATE TABLE.
BEGIN;
CREATE TABLE [IF NOT EXISTS] [schema_name.]table_name (
{
column_name column_type [column_constraints, [...]]
| table_constraints
[,...]
}
);
CALL set_table_property('[schema_name.]<table_name>', '<property>', '<value>');
COMMENT ON COLUMN <[schema_name.]tablename.column> IS '<value>';
COMMENT ON TABLE <[schema_name.]tablename> IS '<value>';
COMMIT;
Propriétés de la table
Les propriétés sont réparties en trois groupes selon leur fonction. Les propriétés marquées non modifiables ne peuvent pas être changées après la création de la table ; vous devez recréer la table.
Organisation des données (non modifiable après création)
| Propriété | Description | Orienté colonne | Orienté ligne | Hybride ligne-colonne | Par défaut |
|---|---|---|---|---|---|
orientation |
Définit le format de stockage. Consultez les Modes de stockage. | column |
row |
row,column |
column |
distribution_key |
Définit la politique de partitionnement des données. Consultez la Clé de distribution. | Clé primaire par défaut ; choisissez une colonne de la clé primaire pour des performances optimales. | Clé primaire par défaut. | Clé primaire par défaut. | Clé primaire |
clustering_key |
Trie physiquement les données au sein des fichiers pour accélérer les requêtes par plage. Consultez la Clé de clustering. | Vide par défaut. Utilisez au maximum une colonne ; seul l'ordre croissant est pris en charge. | Clé primaire par défaut. | Vide par défaut. | — |
event_time_column |
Divise les données en segments de fichier par heure, permettant un filtrage rapide par plage temporelle. Consultez la Colonne d'heure d'événement. | Premier champ d'horodatage non nul par défaut. | Non pris en charge. | Premier champ d'horodatage non nul par défaut. | Premier horodatage non nul |
table_group |
Contrôle le nombre de shards pour la distribution des données. Consultez les Groupes de tables et nombres de shards. | Groupe de tables par défaut. | Groupe de tables par défaut. | Groupe de tables par défaut. | Groupe de tables par défaut |
Les propriétés orientation, distribution_key, clustering_key et event_time_column ne peuvent pas être modifiées après la création de la table. Planifiez-les soigneusement avant de créer la table. La propriété table_group ne peut pas non plus être modifiée sans recréer la table ou effectuer un resharding.
Accélération par index (modifiable après création)
| Propriété | Description | Orienté colonne | Orienté ligne | Hybride ligne-colonne |
|---|---|---|---|---|
bitmap_columns |
Construit un index bitmap pour un filtrage rapide par égalité sur les colonnes à faible cardinalité. Consultez l'Index bitmap. À utiliser pour les colonnes faisant l'objet de comparaisons d'égalité ; évitez de définir plus de 10 colonnes. | Pris en charge | Non pris en charge | Pris en charge |
dictionary_encoding_columns |
Construit un mappage de dictionnaire qui convertit les comparaisons de chaînes en comparaisons numériques, accélérant ainsi les opérations GROUP BY et FILTER. Toutes les colonnes TEXT des tables orientées colonne sont activées par défaut. À partir de la version V0.9, Hologres détermine automatiquement s'il faut appliquer l'encodage par dictionnaire en fonction des caractéristiques des données. | Pris en charge | Non pris en charge | Pris en charge |
Les propriétés bitmap_columns et dictionary_encoding_columns peuvent être modifiées après la création de la table via l'instruction ALTER TABLE.
Syntaxe de dictionary_encoding_columns :
CALL set_table_property('table_name', 'dictionary_encoding_columns', '[columnName{:[on|off|auto]}[,...]]');
Cycle de vie des données
| Propriété | Description | Orienté colonne | Orienté ligne | Hybride ligne-colonne |
|---|---|---|---|---|
time_to_live_in_seconds |
Définit la durée de conservation (TTL) des données de la table en secondes. Le TTL commence à partir de l'écriture, et non de la mise à jour. À partir de la version V1.3.24, la valeur minimale autorisée est de 86 400 (un jour). | Pris en charge | Non recommandé — utilisez la valeur par défaut | Non recommandé |
storage_mode |
Spécifie si les données sont stockées dans le stockage chaud ou froid. Pris en charge à partir de la version V1.3. Consultez le Stockage des données par niveaux. | À utiliser selon les besoins | À utiliser selon les besoins | — |
Notes concernant time_to_live_in_seconds :
Le TTL n'est pas appliqué à un instant précis. Après l'expiration du TTL, les données sont supprimées dans une fenêtre de temps, et non à un moment exact.
Seules les données sont supprimées ; la table elle-même reste intacte.
Le TTL peut entraîner des clés primaires en double ou des résultats de requête incohérents après la suppression.
Pour la gestion du cycle de vie des données de production, utilisez plutôt des tables partitionnées. Consultez l'instruction CREATE PARTITION TABLE.
À partir de Hologres V4.2, pour les tables dotées d'une clé primaire, le paramètre TTL est contraint par le paramètre GUC
hg_time_to_live_in_days_min_value. Ce paramètre est exprimé en jours, avec une valeur par défaut de 36 500 (100 ans), et ne peut être modifié que par un Superuser. Lorsque vous définissez le TTL d'une table avec clé primaire via CREATE TABLE, ALTER TABLE, SET_TABLE_PROPERTY ou REBUILD, le système vérifie que la valeur respecte l'exigence minimale (elle doit être supérieure ou égale au nombre de jours correspondant àhg_time_to_live_in_days_min_value). Les tables sans clé primaire ne sont pas affectées par cette contrainte.
S'il n'est pas défini, le TTL par défaut est de 100 ans (aucune expiration effective).
Syntaxe de time_to_live_in_seconds :
CALL set_table_property('table_name', 'time_to_live_in_seconds', '<non_negative_literal>');
Syntaxe de storage_mode :
-- Set storage mode at table creation:
CREATE TABLE <table_name> (...) WITH (storage_mode = 'hot');
CREATE TABLE <table_name> (...) WITH (storage_mode = 'cold');
-- Set storage mode after table creation:
CALL set_table_property('table_name', 'storage_mode', 'hot');
CALL set_table_property('table_name', 'storage_mode', 'cold');
Exemples
Exemple : Table partitionnée pour les données de séries chronologiques à grande échelle
À mesure que les volumes de données augmentent, la maintenance d'une table plate unique devient coûteuse : la purge des données historiques nécessite l'analyse de toutes les lignes, et les requêtes basées sur le temps effectuent des analyses complètes de la table. Une table partitionnée isole physiquement les données par jour, permettant des suppressions de partitions instantanées pour le nettoyage et une élimination automatique des partitions lors des requêtes.
Cet exemple met à niveau la table dwd_trade_orders de la section Démarrage rapide vers une structure partitionnée. Les définitions de champ et les paramètres d'index sont hérités, mais la clé primaire doit inclure la clé de partition dt.
BEGIN;
-- Create the partitioned parent table.
-- The primary key includes both the business key (order_id) and the partition key (dt).
CREATE TABLE IF NOT EXISTS public.dwd_trade_orders_partitioned (
order_id BIGINT NOT NULL,
shop_id INT NOT NULL,
user_id TEXT NOT NULL,
order_amount NUMERIC(12, 2) DEFAULT 0.00,
payment NUMERIC(12, 2) DEFAULT 0.00,
payment_type INT DEFAULT 0,
is_delivered BOOLEAN DEFAULT false,
dt TEXT NOT NULL,
order_time TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (order_id, dt)
)
PARTITION BY LIST (dt)
WITH (
orientation = 'column',
distribution_key = 'order_id',
event_time_column = 'order_time',
clustering_key = 'order_time:asc'
);
COMMIT;
-- Create a child table to provide physical storage for a specific date.
CREATE TABLE IF NOT EXISTS public.dwd_trade_orders_20231101
PARTITION OF public.dwd_trade_orders_partitioned FOR VALUES IN ('20231101');
-- Insert data. The application logic is identical to the flat table.
-- Data is automatically routed to the correct child table.
INSERT INTO public.dwd_trade_orders_partitioned
(order_id, shop_id, user_id, order_amount, payment, payment_type, is_delivered, dt, order_time)
VALUES
(50001, 101, 'U678', 299.00, 280.00, 1, true, '20231101', '2023-11-01 10:00:01+08'),
(50002, 102, 'U992', 59.00, 59.00, 2, false, '20231101', '2023-11-01 10:05:12+08'),
(50003, 101, 'U441', 150.00, 145.00, 1, true, '20231101', '2023-11-01 10:10:45+08'),
(50004, 105, 'U219', 888.00, 888.00, 3, true, '20231101', '2023-11-01 10:20:11+08'),
(50005, 102, 'U883', 35.00, 30.00, 1, false, '20231101', '2023-11-01 10:32:00+08'),
(50006, 110, 'U007', 120.50, 120.50, 2, true, '20231101', '2023-11-01 10:45:33+08'),
(50007, 101, 'U321', 210.00, 210.00, 1, true, '20231101', '2023-11-01 11:02:19+08'),
(50008, 108, 'U556', 45.00, 45.00, 2, false, '20231101', '2023-11-01 11:15:04+08'),
(50009, 101, 'U112', 300.00, 290.00, 3, true, '20231101', '2023-11-01 11:25:55+08'),
(50010, 105, 'U449', 99.90, 99.90, 1, true, '20231101', '2023-11-01 11:40:22+08');
-- Query with a partition filter. Hologres scans only the matching child table.
SELECT COUNT(*) FROM public.dwd_trade_orders_partitioned WHERE dt = '20231101';
-- Drop a child table to reclaim space in seconds (much faster than DELETE).
-- DROP TABLE public.dwd_trade_orders_20231101;
Exemple : Analytique en temps réel pour les grands ensembles de données (table de faits)
Scénario : Résumés de tableau de bord en temps réel avec des volumes de données importants, où l'exigence principale est une agrégation rapide — par exemple, le calcul du volume marchand brut (GMV) et du nombre de commandes.
Le stockage orienté colonne excelle dans ce cas : des taux de compression élevés réduisent les E/S, et les analyses par colonne ne lisent que les colonnes nécessaires à l'agrégation.
BEGIN;
CREATE TABLE IF NOT EXISTS public.dwd_order_summary (
order_id BIGINT PRIMARY KEY,
category_id INT NOT NULL,
gmv NUMERIC(15, 2),
order_time TIMESTAMPTZ NOT NULL
) WITH (
orientation = 'column', -- Best for large-scale aggregation; high compression, efficient column scans
distribution_key = 'order_id', -- Even distribution; enables local joins with other order tables
event_time_column = 'order_time', -- Enables file-level segment clipping for time range filters
clustering_key = 'order_time:asc' -- Reduces disk I/O for "last hour" or "specific day" queries
);
COMMENT ON TABLE public.dwd_order_summary IS 'Fact table for order summary details.';
COMMENT ON COLUMN public.dwd_order_summary.order_id IS 'The unique order ID.';
COMMENT ON COLUMN public.dwd_order_summary.category_id IS 'The category ID.';
COMMENT ON COLUMN public.dwd_order_summary.gmv IS 'The gross merchandise volume.';
COMMENT ON COLUMN public.dwd_order_summary.order_time IS 'The time when the order was placed.';
COMMIT;
Exemple : Requêtes ponctuelles à haute concurrence (table de dimensions)
Scénario : Récupérer un profil utilisateur par user_id en quelques millisecondes, avec un nombre élevé de requêtes par seconde (QPS).
Le stockage orienté ligne est optimisé pour les recherches basées sur la clé primaire. Toutes les données de la ligne sont stockées de manière contiguë, ce qui rend les requêtes ponctuelles extrêmement rapides sans analyser les colonnes non pertinentes.
BEGIN;
CREATE TABLE IF NOT EXISTS public.dim_user_persona (
user_id TEXT PRIMARY KEY,
user_level INT,
persona_jsonb JSONB
) WITH (
orientation = 'row'
-- For row-oriented tables, the primary key is automatically used as the distribution key
-- and clustering key. No additional settings are required.
);
COMMENT ON TABLE public.dim_user_persona IS 'Dimension table for user profiles.';
COMMENT ON COLUMN public.dim_user_persona.user_id IS 'The unique user ID.';
COMMENT ON COLUMN public.dim_user_persona.user_level IS 'The user level.';
COMMENT ON COLUMN public.dim_user_persona.persona_jsonb IS 'The user profile features in JSON format.';
COMMIT;
Exemple : Charge de travail hybride (stockage hybride ligne-colonne)
Scénario : Un système logistique et de service après-vente qui nécessite à la fois de l'analytique (résumé des statuts logistiques) et des requêtes ponctuelles (récupération des détails de commande par order_id).
Le stockage hybride ligne-colonne combine les performances de requêtes ponctuelles de l'ordre de la milliseconde du stockage orienté ligne avec l'agrégation efficace du stockage orienté colonne.
BEGIN;
CREATE TABLE IF NOT EXISTS public.ads_shipping_info (
order_id BIGINT PRIMARY KEY,
shipping_status INT,
receiver_address TEXT,
update_time TIMESTAMPTZ
) WITH (
orientation = 'row,column', -- Supports both point queries and aggregation
distribution_key = 'order_id', -- Controls data distribution across shards
bitmap_columns = 'shipping_status' -- Accelerates "status = X" filter queries on a low-cardinality column
);
COMMENT ON TABLE public.ads_shipping_info IS 'Application table for logistics status queries.';
COMMENT ON COLUMN public.ads_shipping_info.order_id IS 'The order ID.';
COMMENT ON COLUMN public.ads_shipping_info.shipping_status IS 'Logistics status (1: To be shipped, 2: In transit, 3: Delivered).';
COMMENT ON COLUMN public.ads_shipping_info.receiver_address IS 'The shipping address.';
COMMIT;
Limitations
Hologres prend en charge un maximum de 6 400 colonnes par table.
Limites de la clé primaire
-
Composite primary keys: Plusieurs champs peuvent former la clé primaire. Tous les champs doivent être
NOT NULLet doivent être déclarés dans une seule instruction.BEGIN; CREATE TABLE public.test ( id TEXT NOT NULL, ds TEXT NOT NULL, PRIMARY KEY (id, ds) ); CALL SET_TABLE_PROPERTY('public.test', 'orientation', 'column'); COMMIT; Types non pris en charge : FLOAT, DOUBLE, NUMERIC, ARRAY, JSON, DATE et autres types complexes ne peuvent pas être utilisés comme colonnes de clé primaire.
Non modifiable : La clé primaire ne peut pas être modifiée après la création de la table. Recréez la table si vous avez besoin d'une clé primaire différente.
Exigences de stockage : Les tables orientées ligne et hybrides ligne-colonne doivent avoir une clé primaire. Les clés primaires sont facultatives pour les tables orientées colonne.
Prise en charge des contraintes
| Contrainte | Niveau colonne | Niveau table |
|---|---|---|
primary key |
Pris en charge | Pris en charge |
not null |
Pris en charge | — |
null |
Pris en charge | — |
unique |
Non pris en charge | Non pris en charge |
check |
Non pris en charge | Non pris en charge |
default |
Pris en charge | Non pris en charge |
Règles de nommage et d'échappement
Les noms de colonne ne peuvent pas commencer par
hg_.Les noms de schéma ne peuvent pas commencer par
holo_,hg_oupg_.Les noms de table ne peuvent pas dépasser 127 octets.
Entourez les noms de guillemets doubles (
"") lorsqu'il s'agit de mots-clés SQL, de mots réservés, de champs système (tels quectid), d'identificateurs sensibles à la casse, de noms contenant des caractères spéciaux ou de noms commençant par un chiffre.
Syntaxe pour les noms de colonne échappés dans Hologres V2.0 et versions ultérieures :
-- Single escaped column
BEGIN;
CREATE TABLE tbl (c1 INT NOT NULL);
CALL set_table_property('tbl', 'clustering_key', '"c1":asc');
COMMIT;
-- Multiple columns, including an uppercase one (V2.1 and later)
BEGIN;
CREATE TABLE tbl ("C1" INT NOT NULL, c2 TEXT NOT NULL) WITH (clustering_key = '"C1",c2');
COMMIT;
-- Multiple columns, including an uppercase one (V2.0 and later)
BEGIN;
CREATE TABLE tbl ("C1" INT NOT NULL, c2 TEXT NOT NULL);
CALL set_table_property('tbl', 'clustering_key', '"C1",c2');
COMMIT;
Syntaxe pour les noms de colonne échappés dans les versions antérieures à Hologres V2.0 :
BEGIN;
CREATE TABLE tbl (c1 INT NOT NULL);
CALL set_table_property('tbl', 'clustering_key', '"c1:asc"');
COMMIT;
-- Multiple columns, including an uppercase one
BEGIN;
CREATE TABLE tbl ("C1" INT NOT NULL, c2 TEXT NOT NULL);
CALL set_table_property('tbl', 'clustering_key', '"C1,c2"');
COMMIT;
Pour revenir à l'ancienne syntaxe d'analyse dans Hologres V2.0 si nécessaire :
-- Enable the old syntax at the session level.
SET hg_disable_parse_holo_property = on;
-- Enable the old syntax at the database level.
ALTER DATABASE <db_name> SET hg_disable_parse_holo_property = on;
Comportement de IF NOT EXISTS
| Condition | **IF NOT EXISTS spécifié** |
**IF NOT EXISTS non spécifié** |
|---|---|---|
| Une table portant le même nom existe | Renvoie un NOTICE, ignore la création, l'opération réussit | Renvoie une ERROR |
| Aucune table portant le même nom n'existe | L'opération réussit | L'opération réussit |
Limites de modification
Après la création d'une table, les éléments suivants ne peuvent pas être modifiés :
Types de données (avant Hologres V3.0)
Ordre des colonnes
Contrainte de nullabilité (
NOT NULL↔ nullable)Propriétés de disposition de stockage :
orientation,distribution_key,clustering_key,event_time_column
Les éléments suivants peuvent être modifiés après la création de la table :
bitmap_columnsetdictionary_encoding_columns— via ALTER TABLETypes de données : certains types dans les versions V3.0 et ultérieures ; tous les types via REBUILD dans les versions V3.1 et ultérieures — consultez Modifier les types de données et REBUILD
Étapes suivantes
CREATE PARTITION TABLE — gérer le cycle de vie des données à grande échelle à l'aide de tables partitionnées
ALTER TABLE — modifier les propriétés modifiables après la création de la table
Clé de distribution — apprendre à choisir la bonne clé de distribution
Clé de clustering — comprendre comment les clés de clustering améliorent les performances des requêtes
Modes de stockage — comparer en profondeur le stockage orienté colonne, orienté ligne et hybride ligne-colonne