Passer au contenu principal
Crée une nouvelle vue. Les vues peuvent être normales, matérialisées, matérialisées actualisables et de fenêtre.

Vue normale

Syntaxe :
CREATE [OR REPLACE] VIEW [IF NOT EXISTS] [db.]table_name [(alias1 [, alias2 ...])] [ON CLUSTER cluster_name]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | INVOKER | NONE }]
AS SELECT ...
[COMMENT 'comment']
Les vues normales ne stockent aucune donnée. Elles se contentent de lire une autre table à chaque accès. Autrement dit, une vue normale n’est rien d’autre qu’une requête enregistrée. Lorsqu’on lit depuis une vue, cette requête enregistrée est utilisée comme sous-requête dans la clause FROM. À titre d’exemple, supposons que vous ayez créé une vue :
CREATE VIEW view AS SELECT ...
et rédigé une requête :
SELECT a, b, c FROM view
Cette requête est strictement équivalente à l’utilisation de la sous-requête :
SELECT a, b, c FROM (SELECT ...)

Vue paramétrée

Les vues paramétrées sont similaires aux vues normales, mais elles peuvent être créées avec des paramètres qui ne sont pas évalués immédiatement. Ces vues peuvent être utilisées avec des fonctions de table, en utilisant le nom de la vue comme nom de fonction et les valeurs des paramètres comme arguments.
CREATE VIEW view AS SELECT * FROM TABLE WHERE Column1={column1:datatype1} and Column2={column2:datatype2} ...
Ce qui précède crée une vue sur la table, qui peut être utilisée comme fonction de table en remplaçant les paramètres, comme indiqué ci-dessous.
SELECT * FROM view(column1=value1, column2=value2 ...)

Vue matérialisée

CREATE MATERIALIZED VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster_name] [TO[db.]name [(columns)]] [ENGINE = engine] [POPULATE]
[REFRESH ...]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | NONE }]
AS SELECT ...
[COMMENT 'comment']
CREATE OR REPLACE MATERIALIZED VIEW [db.]table_name [ON CLUSTER cluster_name] [TO[db.]name [(columns)]] [ENGINE = engine] [POPULATE]
[REFRESH ...]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | NONE }]
AS SELECT ...
[COMMENT 'comment']
OR REPLACE et IF NOT EXISTS sont mutuellement exclusifs : les combiner provoque une erreur de syntaxe.

CREATE OR REPLACE MATERIALIZED VIEW

CREATE OR REPLACE MATERIALIZED VIEW remplace de manière atomique une vue matérialisée existante ainsi que sa table de stockage interne, s’il y en a une. Cette opération nécessite un moteur de base de données Atomic ou Replicated.
CREATE OR REPLACE MATERIALIZED VIEW [db.]name [ON CLUSTER cluster]
[TO [db.]target_table]
[ENGINE = engine]
[POPULATE]
[REFRESH ...]
AS SELECT ...
Comportements clés :
  • Sans clause TO : l’ancienne table interne est supprimée et une nouvelle est créée. Les données existantes de la table interne sont perdues, sauf si POPULATE est spécifié.
  • Avec clause TO : seule la définition de la vue est remplacée ; la table cible et ses données ne sont pas affectées.
  • Compatible avec REFRESH, ON CLUSTER et toutes les options de moteur. POPULATE est pris en charge uniquement pour les bases de données Atomic — il est rejeté pour les bases de données Replicated (voir la note POPULATE ci-dessous).
  • Nécessite les privilèges CREATE VIEW et DROP VIEW.
CREATE OR REPLACE MATERIALIZED VIEW n’est pris en charge qu’avec les moteurs de base de données Atomic ou Replicated. Il n’est pas pris en charge avec le moteur de base de données Ordinary.
Exemples :
-- Create a materialized view with an inner table
CREATE OR REPLACE MATERIALIZED VIEW mv
    ENGINE = MergeTree ORDER BY x
    AS SELECT x, sum(y) AS total FROM src GROUP BY x;

-- Replace with a new definition (old inner table data is lost)
CREATE OR REPLACE MATERIALIZED VIEW mv
    ENGINE = MergeTree ORDER BY x
    AS SELECT x, count() AS cnt FROM src GROUP BY x;

-- Replace with POPULATE to backfill from existing source data
CREATE OR REPLACE MATERIALIZED VIEW mv
    ENGINE = MergeTree ORDER BY x
    POPULATE
    AS SELECT x FROM src;

-- Replace an inner-table MV with a TO-table MV (target data is preserved)
CREATE OR REPLACE MATERIALIZED VIEW mv TO target
    AS SELECT x FROM src;
Voici un guide étape par étape sur l’utilisation des vues matérialisées.
Les vues matérialisées stockent les données transformées par la requête SELECT correspondante. Lors de la création d’une vue matérialisée sans TO [db].[table], vous devez spécifier ENGINE — le moteur de table utilisé pour stocker les données. Lors de la création d’une vue matérialisée avec TO [db].[table], vous ne pouvez pas non plus utiliser POPULATE. Une vue matérialisée fonctionne comme suit : lors de l’insertion de données dans la table spécifiée dans SELECT, une partie des données insérées est transformée par cette requête SELECT, puis le résultat est inséré dans la vue.
Les vues matérialisées dans ClickHouse utilisent les noms de colonnes plutôt que l’ordre des colonnes lors de l’insertion dans la table de destination. Si certains noms de colonnes ne figurent pas dans le résultat de la requête SELECT, ClickHouse utilise une valeur par défaut, même si la colonne n’est pas Nullable. Une bonne pratique consiste à ajouter des alias pour chaque colonne lors de l’utilisation de vues matérialisées.Les vues matérialisées dans ClickHouse sont davantage implémentées comme des déclencheurs à l’insertion. S’il y a une agrégation dans la requête de la vue, elle ne s’applique qu’au lot de données nouvellement insérées. Toute modification des données existantes de la table source (comme update, delete, drop partition, etc.) ne modifie pas la vue matérialisée.Les vues matérialisées dans ClickHouse n’ont pas de comportement déterministe en cas d’erreur. Cela signifie que les blocs déjà écrits sont conservés dans la table de destination, mais que tous les blocs suivant l’erreur ne le sont pas.Par défaut, si l’envoi vers l’une des vues génère une exception, la requête INSERT échoue. Rien ne garantit qu’à ce stade le bloc ait déjà atteint la table source — cela dépend du moment où il se trouve dans le pipeline d’insertion, et non de l’erreur de la vue. Réessayez l’INSERT ayant échoué avec la déduplication d’insertion (insert_deduplicate, deduplicate_blocks_in_dependent_materialized_views) pour obtenir une livraison exactly-once vers la table source et toutes les vues dépendantes.Définir materialized_views_ignore_errors=true sur la requête INSERT modifie uniquement le signalement des erreurs : chaque erreur de vue est consignée comme un avertissement et la requête INSERT réussit. La livraison vers la destination de la vue en échec est partielle — les blocs traités avant l’exception sont conservés, et le bloc en échec ainsi que tous les blocs suivants sont ignorés pour cette vue. Les vues en aval de cette destination ne voient que les blocs effectivement arrivés, leur livraison est donc elle aussi partielle. Les vues sœurs (et leurs chaînes en aval) qui n’ont pas généré d’exception sont, elles, écrites intégralement, et la table source est alimentée comme d’habitude. Comme l’INSERT est signalé comme réussi, le client ne reçoit aucun signal d’échec et aucun nouvel essai automatique n’est déclenché ; utilisez ce paramètre uniquement lorsque les écritures dans la table source ne doivent pas être bloquées par des problèmes du côté des vues (par exemple, les tables system.*_log).materialized_views_ignore_errors vaut true par défaut pour les tables system.*_log.
Si vous spécifiez POPULATE, les données existantes de la table sont insérées dans la vue lors de sa création, comme avec un CREATE TABLE ... AS SELECT .... Sinon, la requête ne contient que les données insérées dans la table après la création de la vue. Nous ne recommandons pas d’utiliser POPULATE, car les données insérées dans la table pendant la création de la vue n’y seront pas insérées.
Étant donné que POPULATE fonctionne comme CREATE TABLE ... AS SELECT ..., il présente des limitations :
  • Il n’est pas pris en charge avec une base de données Replicated
  • Il n’est pas pris en charge dans ClickHouse Cloud
À la place, vous pouvez utiliser un INSERT ... SELECT distinct.
Une requête SELECT peut contenir DISTINCT, GROUP BY, ORDER BY, LIMIT. Notez que les transformations correspondantes sont effectuées indépendamment sur chaque bloc de données insérées. Par exemple, si GROUP BY est défini, les données sont agrégées pendant l’insertion, mais uniquement à l’intérieur d’un seul paquet de données insérées. Les données ne seront pas agrégées davantage. L’exception est l’utilisation d’un ENGINE qui effectue lui-même l’agrégation des données, comme SummingMergeTree. Si la vue matérialisée utilise la construction TO [db.]name, vous pouvez DETACH la vue, exécuter ALTER sur la table cible, puis ATTACH la vue précédemment détachée (DETACH). Notez que la vue matérialisée est influencée par le paramètre optimize_on_insert. Les données sont fusionnées avant l’insertion dans une vue. Les vues se présentent comme des tables normales. Par exemple, elles figurent dans le résultat de la requête SHOW TABLES. Pour supprimer une vue, utilisez DROP VIEW. Bien que DROP TABLE fonctionne également pour les VIEWs.

Sécurité SQL

DEFINER et SQL SECURITY permettent de spécifier quel utilisateur ClickHouse utiliser lors de l’exécution de la requête sous-jacente de la vue. SQL SECURITY a trois valeurs possibles : DEFINER, INVOKER ou NONE. Vous pouvez spécifier n’importe quel utilisateur existant ou CURRENT_USER dans la clause DEFINER. Le tableau suivant indique quels droits sont requis pour quel utilisateur afin d’interroger la vue. Notez que, quelle que soit l’option de sécurité SQL, il est dans tous les cas nécessaire d’avoir GRANT SELECT ON <view> pour pouvoir la lire.
Option de sécurité SQLVueVue matérialisée
DEFINER alicealice doit disposer du droit SELECT sur la table source de la vue.alice doit disposer du droit SELECT sur la table source de la vue et du droit INSERT sur la table cible de la vue.
INVOKERL’utilisateur doit disposer du droit SELECT sur la table source de la vue.SQL SECURITY INVOKER ne peut pas être spécifié pour les vues matérialisées.
NONE--
SQL SECURITY NONE est une option obsolète. Tout utilisateur disposant des droits pour créer des vues avec SQL SECURITY NONE pourra exécuter n’importe quelle requête arbitraire. Il est donc nécessaire d’avoir GRANT ALLOW SQL SECURITY NONE TO <user> pour créer une vue avec cette option.
Si DEFINER/SQL SECURITY ne sont pas spécifiés, les valeurs par défaut sont utilisées : Si une vue est Attach sans que DEFINER/SQL SECURITY soient spécifiés, la valeur par défaut est SQL SECURITY NONE pour la vue matérialisée et SQL SECURITY INVOKER pour la vue normale. Pour modifier la sécurité SQL d’une vue existante, utilisez
ALTER TABLE MODIFY SQL SECURITY { DEFINER | INVOKER | NONE } [DEFINER = { user | CURRENT_USER }]

Exemples

CREATE VIEW test_view
DEFINER = alice SQL SECURITY DEFINER
AS SELECT ...
CREATE VIEW test_view
SQL SECURITY INVOKER
AS SELECT ...

Live View

Cette fonctionnalité est obsolète et sera supprimée à l’avenir. Pour vous faciliter la tâche, l’ancienne documentation est disponible ici

Vue matérialisée actualisable

CREATE MATERIALIZED VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
REFRESH [EVERY|AFTER interval [OFFSET interval]]
[RANDOMIZE FOR interval]
[DEPENDS ON [db.]name [, [db.]name [, ...]]]
[SETTINGS name = value [, name = value [, ...]]]
[APPEND]
[TO[db.]name] [(columns)] [ENGINE = engine]
[EMPTY]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | NONE }]
AS SELECT ...
[COMMENT 'comment']
interval correspond à une suite d’intervalles simples :
number SECOND|MINUTE|HOUR|DAY|WEEK|MONTH|YEAR
La clause REFRESH doit spécifier au moins l’un des éléments suivants : EVERY, AFTER ou DEPENDS ON. Un REFRESH seul (sans aucun d’eux) est rejeté. REFRESH DEPENDS ON ... sans EVERY/AFTER est une forme abrégée de REFRESH AFTER 0 SECOND DEPENDS ON ... ; voir Dépendances de rafraîchissement ci-dessous. Exécute périodiquement la requête correspondante et stocke son résultat dans une table.
  • Si APPEND est spécifié, chaque rafraîchissement insère des lignes dans la table sans supprimer les lignes existantes. L’insertion n’est pas atomique, comme pour une requête INSERT INTO ... SELECT classique.
  • Sinon, chaque rafraîchissement remplace atomiquement le contenu précédent de la table.
Différences par rapport aux vues matérialisées classiques non actualisables :
  • Pas de déclencheur d’insertion. Lorsque de nouvelles données sont insérées dans la table spécifiée dans SELECT, elles ne sont pas automatiquement propagées vers la vue matérialisée actualisable. À la place, l’insertion des données n’a lieu que lors des rafraîchissements périodiques ou manuels.
  • Aucune restriction sur la requête SELECT. Les fonctions de table (par ex. url()), les vues, UNION et JOIN sont tous autorisés.
Les paramètres de la partie REFRESH ... SETTINGS de la requête sont des paramètres de rafraîchissement (par ex. refresh_retries), distincts des paramètres classiques (par ex. max_threads). Les paramètres classiques peuvent être spécifiés à l’aide de SETTINGS à la fin de la requête.

Planification du rafraîchissement

Exemples de planifications de rafraîchissement :
REFRESH EVERY 1 DAY -- every day, at midnight (UTC)
REFRESH EVERY 1 MONTH -- on 1st day of every month, at midnight
REFRESH EVERY 1 MONTH OFFSET 5 DAY 2 HOUR -- on 6th day of every month, at 2:00 am
REFRESH EVERY 2 WEEK OFFSET 5 DAY 15 HOUR 10 MINUTE -- every other Saturday, at 3:10 pm
REFRESH EVERY 30 MINUTE -- at 00:00, 00:30, 01:00, 01:30, etc
REFRESH AFTER 30 MINUTE -- 30 minutes after the previous refresh completes, no alignment with time of day
-- REFRESH AFTER 1 HOUR OFFSET 1 MINUTE -- syntax error, OFFSET is not allowed with AFTER
REFRESH EVERY 1 WEEK 2 DAYS -- every 9 days, not on any particular day of the week or month;
                            -- specifically, when day number (since 1969-12-29) is divisible by 9
REFRESH EVERY 5 MONTHS -- every 5 months, different months each year (as 12 is not divisible by 5);
                       -- specifically, when month number (since 1970-01) is divisible by 5
RANDOMIZE FOR ajuste aléatoirement le moment de chaque actualisation, par exemple :
REFRESH EVERY 1 DAY OFFSET 2 HOUR RANDOMIZE FOR 1 HOUR -- every day at random time between 01:30 and 02:30
Au plus un seul rafraîchissement peut être en cours à la fois pour une vue donnée. Par exemple, si le rafraîchissement d’une vue avec REFRESH EVERY 1 MINUTE prend 2 minutes, elle ne sera rafraîchie que toutes les 2 minutes. Si elle devient ensuite plus rapide et commence à se rafraîchir en 10 secondes, elle reviendra à un rafraîchissement toutes les minutes. (En particulier, elle ne se rafraîchira pas toutes les 10 secondes pour rattraper un éventuel retard de rafraîchissements manqués : il n’existe pas de tel retard.) En général, le premier rafraîchissement démarre immédiatement après la création de la vue matérialisée : le temps écoulé depuis le dernier rafraîchissement est infini, donc toute planification indique qu’il faut la rafraîchir immédiatement. Si EMPTY est spécifié, ce rafraîchissement initial est ignoré, et le premier rafraîchissement a lieu à l’heure planifiée suivante ; par exemple, pour EVERY 1 HOUR, le premier rafraîchissement aura lieu à la fin de l’heure en cours.

Dans une base de données Replicated

Si la vue matérialisée actualisable se trouve dans une base de données Replicated, les répliques se coordonnent entre elles afin qu’une seule réplique effectue le rafraîchissement à chaque échéance planifiée. Le moteur de table ReplicatedMergeTree est requis afin que toutes les répliques voient les données produites par le rafraîchissement. En mode APPEND, la coordination peut être désactivée avec SETTINGS all_replicas = 1. Les répliques effectuent alors les rafraîchissements indépendamment les unes des autres. Dans ce cas, ReplicatedMergeTree n’est pas requis. En mode non-APPEND, seul le rafraîchissement coordonné est pris en charge. Pour un fonctionnement non coordonné, utilisez la base de données Atomic et la requête CREATE ... ON CLUSTER pour créer des vues matérialisées actualisables sur toutes les répliques. La coordination s’effectue via Keeper. Le chemin du znode est déterminé par le paramètre serveur default_replica_path.

Dépendances d’actualisation

DEPENDS ON synchronise l’actualisation de différentes tables :
CREATE MATERIALIZED VIEW dependent REFRESH EVERY 1 HOUR DEPENDS ON dependency [...]
L’actualisation de la vue dépendante ne démarrera qu’une fois l’actualisation de toutes les vues dont elle dépend terminée. Pour actualiser immédiatement après l’actualisation d’une autre vue :
CREATE MATERIALIZED VIEW dependent REFRESH AFTER 0 SECOND DEPENDS ON dependency [...]
Ou, de façon équivalente :
CREATE MATERIALIZED VIEW dependent REFRESH DEPENDS ON dependency [...]
DEPENDS ON fonctionne uniquement entre des vues matérialisées actualisables. En particulier, si la vue dont elle dépend utilise TO <table>, veillez à utiliser le nom de la vue plutôt que celui de la table. Si la liste DEPENDS ON contient une table ordinaire, une vue non actualisable ou une faute de frappe, la vue ne sera jamais rafraîchie et affichera l’état MissingDependencies dans system.view_refreshes. Les dépendances peuvent être modifiées ou supprimées à l’aide de ALTER ; voir Modification des paramètres de rafraîchissement.

Utilisation de DEPENDS ON pour une latence de propagation cohérente

Si les deux vues utilisent REFRESH EVERY avec la même période, la dépendance s’applique à chaque créneau temporel. Par exemple, supposons que les vues X et Y utilisent toutes deux REFRESH EVERY 1 HOUR et que Y lit les données de la table de sortie de X. Sans dépendance, Y verrait généralement les données du rafraîchissement de l’heure précédente de X. Avec DEPENDS ON X, le rafraîchissement de 11:00 de Y ne démarrera qu’une fois celui de 11:00 de X terminé.
           10:00            11:00            12:00
           │                │                │
  X:        [run]┐           [run]┐           [run]┐
                 │                │                │
  Y:             └►[run]          └►[run]          └►[run]
La dépendance comme l’élément dépendant peuvent chacun sauter des créneaux temporels de manière indépendante si les actualisations durent plus longtemps que la période d’actualisation. Rien ne garantit que l’élément dépendant s’actualise exactement une fois pour chaque actualisation de la dépendance.
           10:00          11:00          12:00          13:00
           │              │              │              |
  X:        [run]┐         [run]┐         [run]┐         [run]┐
                 │              └────┐    (Y skips 12:00)     └───┐
  Y:             └►[10:00 ru------un]└►[11:00 ru---------------un]└►[13:00 run]

Utilisation de DEPENDS ON pour le traitement de flux par lots

Si REFRESH EVERY n’est pas utilisé, la vue dépendante X se rafraîchit si toutes ses dépendances ont été rafraîchies au moins une fois depuis le dernier rafraîchissement de X. REFRESH AFTER T ajoute un délai : la vue dépendante commencera à se rafraîchir T unités de temps après qu’une dépendance a terminé un rafraîchissement. Les dépendances circulaires sont autorisées et utiles. Considérez ce graphe de vues matérialisées actualisables :
  1. X prend un lot de lignes d’un flux et les place dans une table.
  2. Ensuite, Y et Z lisent tous deux dans cette table, effectuent des agrégations différentes et ajoutent les résultats à d’autres tables.
  3. Une fois le lot entièrement traité, X prend le lot suivant, et le cycle se répète.
            source


          ┌─────────┐
     ┌───►│    X    │◄───┐
     │    └──┬───┬──┘    │
  DEPENDS    │   │    DEPENDS
    ON       ▼   ▼      ON
     │      ┌─┐ ┌─┐      │
     └──────┤Y│ │Z├──────┘
            └─┘ └─┘
Exemple complet :
CREATE TABLE current_batch (t UInt64, v Int64) ENGINE ReplicatedMergeTree ORDER BY t;
CREATE TABLE batch_log (max_t UInt64, n Int64, v_sum Int64, processed_at DateTime64) ENGINE ReplicatedMergeTree ORDER BY max_t;
CREATE TABLE stats (h UInt64, n UInt64) ENGINE ReplicatedSummingMergeTree ORDER BY h;

-- (system.numbers stands in for a data source with monotonically increasing timestamps or sequence numbers)
CREATE MATERIALIZED VIEW current_batch_v REFRESH EVERY 10 SECOND DEPENDS ON batch_log_v, stats_v TO current_batch AS SELECT number as t, number * 10 as v FROM system.numbers WHERE number > (SELECT max(max_t) FROM batch_log) LIMIT 100;

CREATE MATERIALIZED VIEW batch_log_v REFRESH DEPENDS ON current_batch_v APPEND TO batch_log AS SELECT max(t) as max_t, count() as n, sum(v) as v_sum, now64() as processed_at FROM current_batch;

CREATE MATERIALIZED VIEW stats_v REFRESH DEPENDS ON current_batch_v APPEND TO stats AS SELECT cityHash64(v) % 20 as h, count() as n FROM current_batch GROUP BY h;

-- Must trigger initial refresh manually.
SYSTEM REFRESH VIEW current_batch_v;
Les chaînes plus longues fonctionnent également. Cela ne fonctionne correctement que lorsque la coordination du rafraîchissement est activée, c’est-à-dire lorsque les vues se trouvent dans une base de données Replicated ou Shared database. Sans coordination, le redémarrage du serveur interrompt le cycle, ce qui nécessite un SYSTEM REFRESH VIEW manuel après chaque redémarrage, plutôt qu’une seule fois après la création des vues.

Paramètres de rafraîchissement

Paramètres de rafraîchissement disponibles :
  • refresh_retries - Nombre de tentatives en cas d’échec de la requête de rafraîchissement avec une exception. Si toutes les tentatives échouent, le système passe à l’heure de rafraîchissement planifiée suivante. 0 signifie aucune nouvelle tentative, -1 signifie un nombre infini de tentatives. Par défaut : 2.
  • refresh_retry_initial_backoff_ms - Délai avant la première nouvelle tentative, si refresh_retries n’est pas égal à zéro. Chaque tentative suivante double le délai, jusqu’à refresh_retry_max_backoff_ms. Par défaut : 100 ms.
  • refresh_retry_max_backoff_ms - Limite de la croissance exponentielle du délai entre les tentatives de rafraîchissement. Par défaut : 60000 ms (1 minute).
  • all_replicas - Dans une base de données Replicated avec APPEND, contrôle si toutes les répliques se rafraîchissent indépendamment ou si une seule réplique se rafraîchit à chaque heure planifiée. Ne peut pas être modifié après la création de la vue. Par défaut : false.

Modification des paramètres de rafraîchissement

Les paramètres de rafraîchissement d’une vue matérialisée actualisable existante peuvent être modifiés à l’aide de ALTER TABLE ... MODIFY REFRESH :
ALTER TABLE [db.]name MODIFY REFRESH EVERY|AFTER ... [RANDOMIZE FOR ...] [DEPENDS ON ...] [SETTINGS ...]
La planification (EVERY ou AFTER) est obligatoire : l’instruction remplace toujours tous les paramètres de rafraîchissement — la planification, RANDOMIZE FOR, DEPENDS ON et les paramètres de rafraîchissement — par ceux qui sont spécifiés. Tout élément omis est réinitialisé à sa valeur par défaut (paramètres) ou supprimé (dépendances, randomisation).
  • Pour modifier uniquement les paramètres de rafraîchissement (par ex. refresh_retries), répétez la planification existante :
    ALTER TABLE rmv MODIFY REFRESH EVERY 1 HOUR SETTINGS refresh_retries = 5;
    
  • ALTER TABLE ... MODIFY SETTING refresh_retries = ... n’est pas pris en charge pour les vues matérialisées ; vous devez passer par MODIFY REFRESH.
  • L’ajout ou la suppression de APPEND n’est pas pris en charge.
  • Le paramètre all_replicas ne peut pas être modifié après la création.
Exemples :
-- Change the schedule, drop existing settings and dependencies.
ALTER TABLE rmv MODIFY REFRESH EVERY 30 MINUTE;

-- Change the schedule and tune retry behavior.
ALTER TABLE rmv MODIFY REFRESH EVERY 30 MINUTE
SETTINGS refresh_retries = 5,
         refresh_retry_initial_backoff_ms = 500,
         refresh_retry_max_backoff_ms = 60000;

-- Keep the dependency while changing the period.
ALTER TABLE rmv MODIFY REFRESH EVERY 6 HOUR DEPENDS ON other_rmv;

-- Drop the dependency by omitting `DEPENDS ON`.
ALTER TABLE rmv MODIFY REFRESH EVERY 6 HOUR;

Autres opérations

L’état de toutes les vues matérialisées actualisables est disponible dans la table system.view_refreshes. Elle contient notamment la progression du rafraîchissement (s’il est en cours), la date et l’heure du dernier et du prochain rafraîchissement, ainsi que le message d’exception si un rafraîchissement a échoué. Pour arrêter, démarrer, déclencher ou annuler manuellement des rafraîchissements, utilisez SYSTEM STOP|START|REFRESH|WAIT|CANCEL VIEW. Pour attendre la fin d’un rafraîchissement, utilisez SYSTEM WAIT VIEW. C’est notamment utile pour attendre le rafraîchissement initial après la création d’une vue.
Fait amusant : la requête de rafraîchissement peut lire dans la vue en cours de rafraîchissement et voir la version des données antérieure au rafraîchissement. Cela signifie que vous pouvez implémenter le jeu de la vie de Conway : https://pastila.nl/?00021a4b/d6156ff819c83d490ad2dcec05676865#O0LGWTO7maUQIA4AcGUtlA==

Window View

Il s’agit d’une fonctionnalité expérimentale qui pourra évoluer de manière non compatible avec les versions antérieures dans les versions ultérieures. Pour utiliser les window views et la requête WATCH, activez le paramètre allow_experimental_window_view. Saisissez la commande set allow_experimental_window_view = 1.
CREATE WINDOW VIEW [IF NOT EXISTS] [db.]table_name [TO [db.]table_name] [INNER ENGINE engine] [ENGINE engine] [WATERMARK strategy] [ALLOWED_LATENESS interval_function] [POPULATE]
AS SELECT ...
GROUP BY time_window_function
[COMMENT 'comment']
La window view peut agréger les données par fenêtre temporelle et produire les résultats lorsque la fenêtre est prête à émettre. Elle stocke les résultats d’agrégation partiels dans une table interne (ou spécifiée) afin de réduire la latence, et peut envoyer le résultat du traitement vers une table spécifiée ou des notifications à l’aide de la requête WATCH. La création d’une window view est similaire à celle d’une MATERIALIZED VIEW. Une window view nécessite un moteur de stockage interne pour stocker les données intermédiaires. Le stockage interne peut être spécifié à l’aide de la clause INNER ENGINE ; la window view utilisera AggregatingMergeTree comme moteur interne par défaut. Lors de la création d’une window view sans TO [db].[table], vous devez spécifier ENGINE – le moteur de table utilisé pour stocker les données.

Fonctions de fenêtre temporelle

Les fonctions de fenêtre temporelle servent à obtenir la borne inférieure et la borne supérieure de la fenêtre des enregistrements. La window view doit être utilisée avec une fonction de fenêtre temporelle.

ATTRIBUTS TEMPORELS

La window view prend en charge le temps de traitement et le temps d’événement. Le temps de traitement permet à la window view de produire des résultats en fonction de l’heure de la machine locale et est utilisé par défaut. C’est la notion du temps la plus simple, mais elle n’offre pas de déterminisme. L’attribut de temps de traitement peut être défini en affectant à time_attr de la fonction de fenêtre temporelle une colonne de table, ou en utilisant la fonction now(). La requête suivante crée une window view avec le temps de traitement.
CREATE WINDOW VIEW wv AS SELECT count(number), tumbleStart(w_id) as w_start from date GROUP BY tumble(now(), INTERVAL '5' SECOND) as w_id
Le temps d’événement correspond au moment où chaque événement s’est produit sur l’appareil qui l’a généré. Ce temps est généralement intégré aux enregistrements au moment de leur création. Le traitement basé sur le temps d’événement permet d’obtenir des résultats cohérents, même en cas d’événements arrivant dans le désordre ou en retard. Window view prend en charge le traitement basé sur le temps d’événement à l’aide de la syntaxe WATERMARK. Window view propose trois stratégies de watermark :
  • STRICTLY_ASCENDING : émet un watermark correspondant à l’horodatage maximal observé jusqu’à présent. Les lignes dont l’horodatage est inférieur à l’horodatage maximal ne sont pas considérées comme en retard.
  • ASCENDING : émet un watermark correspondant à l’horodatage maximal observé jusqu’à présent moins 1. Les lignes dont l’horodatage est égal ou inférieur à l’horodatage maximal ne sont pas considérées comme en retard.
  • BOUNDED : WATERMARK=INTERVAL. Émet des watermarks correspondant à l’horodatage maximal observé moins le délai spécifié.
Les requêtes suivantes montrent des exemples de création d’une window view avec WATERMARK :
CREATE WINDOW VIEW wv WATERMARK=STRICTLY_ASCENDING AS SELECT count(number) FROM date GROUP BY tumble(timestamp, INTERVAL '5' SECOND);
CREATE WINDOW VIEW wv WATERMARK=ASCENDING AS SELECT count(number) FROM date GROUP BY tumble(timestamp, INTERVAL '5' SECOND);
CREATE WINDOW VIEW wv WATERMARK=INTERVAL '3' SECOND AS SELECT count(number) FROM date GROUP BY tumble(timestamp, INTERVAL '5' SECOND);
Par défaut, la fenêtre sera déclenchée à l’arrivée du watermark, et les éléments arrivés après celui-ci seront ignorés. Window View prend en charge le traitement des événements en retard en définissant ALLOWED_LATENESS=INTERVAL. Voici un exemple de gestion du retard :
CREATE WINDOW VIEW test.wv TO test.dst WATERMARK=ASCENDING ALLOWED_LATENESS=INTERVAL '2' SECOND AS SELECT count(a) AS count, tumbleEnd(wid) AS w_end FROM test.mt GROUP BY tumble(timestamp, INTERVAL '5' SECOND) AS wid;
Notez que les éléments émis lors d’un déclenchement tardif doivent être considérés comme des résultats mis à jour d’un calcul précédent. Au lieu de se déclencher à la fin des fenêtres, la window view se déclenche immédiatement à l’arrivée de l’événement tardif. Cela entraîne donc plusieurs résultats pour une même fenêtre. Les utilisateurs doivent tenir compte de ces résultats dupliqués ou les dédupliquer. Vous pouvez modifier la requête SELECT spécifiée dans la window view à l’aide de l’instruction ALTER TABLE ... MODIFY QUERY. La structure de données résultant de la nouvelle requête SELECT doit être identique à celle de la requête SELECT d’origine, avec ou sans la clause TO [db.]name. Notez que les données de la fenêtre en cours seront perdues, car l’état intermédiaire ne peut pas être réutilisé.

Surveillance des nouvelles fenêtres

La window view prend en charge la requête WATCH pour surveiller les modifications, ou vous pouvez utiliser la syntaxe TO pour écrire les résultats dans une table.
WATCH [db.]window_view
[EVENTS]
[LIMIT n]
[FORMAT format]
Il est possible de spécifier un LIMIT pour définir le nombre de mises à jour à recevoir avant de mettre fin à la requête. La clause EVENTS permet d’obtenir une forme abrégée de la requête WATCH : au lieu du résultat de la requête, vous ne recevrez que son watermark le plus récent.

Paramètres

  • window_view_clean_interval : intervalle de nettoyage de la window view, en secondes, pour libérer les données obsolètes. Le système conserve les fenêtres qui n’ont pas encore été entièrement déclenchées en fonction de l’heure système ou de la configuration WATERMARK, et supprime les autres données.
  • window_view_heartbeat_interval : intervalle de heartbeat, en secondes, indiquant que la requête watch est active.
  • wait_for_window_view_fire_signal_timeout : délai d’attente du signal de déclenchement de la window view lors du traitement en temps d’événement.

Exemple

Supposons que nous devions compter le nombre de logs de clics toutes les 10 secondes dans une table de logs appelée data, dont la structure est la suivante :
CREATE TABLE data ( `id` UInt64, `timestamp` DateTime) ENGINE = Memory;
Tout d’abord, nous créons une window view avec une fenêtre fixe de 10 secondes :
CREATE WINDOW VIEW wv as select count(id), tumbleStart(w_id) as window_start from data group by tumble(timestamp, INTERVAL '10' SECOND) as w_id
Ensuite, nous utilisons la requête WATCH pour obtenir les résultats.
WATCH wv
Lorsque des logs sont insérés dans la table data,
INSERT INTO data VALUES(1,now())
La requête WATCH devrait afficher les résultats comme ceci :
┌─count(id)─┬────────window_start─┐
│         1 │ 2020-01-14 16:56:40 │
└───────────┴─────────────────────┘
Sinon, nous pouvons envoyer la sortie vers une autre table à l’aide de la syntaxe TO.
CREATE WINDOW VIEW wv TO dst AS SELECT count(id), tumbleStart(w_id) as window_start FROM data GROUP BY tumble(timestamp, INTERVAL '10' SECOND) as w_id
Vous trouverez d’autres exemples parmi les tests avec état de ClickHouse (ils y sont nommés *window_view*).

Utilisation de Window View

La fonctionnalité window view est utile dans les scénarios suivants :
  • Surveillance : agréger et calculer les métriques des logs au fil du temps, puis envoyer les résultats vers une table cible. Le tableau de bord peut utiliser la table cible comme table source.
  • Analyse : agréger et prétraiter automatiquement les données dans la fenêtre temporelle. Cela peut être utile lors de l’analyse d’un grand nombre de logs. Ce prétraitement élimine les calculs répétés dans plusieurs requêtes et réduit la latence des requêtes.

Vues temporaires

ClickHouse prend en charge les vues temporaires avec les caractéristiques suivantes (comme pour les tables temporaires, le cas échéant) :
  • Durée de vie de la session Une vue temporaire n’existe que pendant la session en cours. Elle est supprimée automatiquement à la fin de la session.
  • Aucune base de données Vous ne pouvez pas qualifier une vue temporaire avec un nom de base de données. Elle existe en dehors des bases de données (dans l’espace de noms de la session).
  • Non répliqué / pas de ON CLUSTER Les objets temporaires sont locaux à la session et ne peuvent pas être créés avec ON CLUSTER.
  • Résolution des noms Si un objet temporaire (table ou vue) porte le même nom qu’un objet persistant et qu’une requête fait référence à ce nom sans base de données, c’est l’objet temporaire qui est utilisé.
  • Objet logique (pas de stockage) Une vue temporaire stocke uniquement son texte SELECT (en utilisant le moteur View en interne). Elle ne conserve pas les données et n’accepte pas INSERT.
  • Clause ENGINE Vous n’avez pas besoin de spécifier ENGINE ; s’il est fourni sous la forme ENGINE = View, il est ignoré ou traité comme la même vue logique.
  • Sécurité / privilèges La création d’une vue temporaire nécessite le privilège CREATE TEMPORARY VIEW, implicitement accordé par CREATE VIEW.
  • SHOW CREATE Utilisez SHOW CREATE TEMPORARY VIEW view_name; pour afficher le DDL d’une vue temporaire.

Syntaxe

CREATE TEMPORARY VIEW [IF NOT EXISTS] view_name AS <select_query>
OR REPLACE n’est pas pris en charge pour les vues temporaires (comme pour les tables temporaires). Si vous devez « remplacer » une vue temporaire, supprimez-la, puis recréez-la.

Exemples

Créez une table source temporaire, ainsi qu’une vue temporaire basée sur celle-ci :
CREATE TEMPORARY TABLE t_src (id UInt32, val String);
INSERT INTO t_src VALUES (1, 'a'), (2, 'b');

CREATE TEMPORARY VIEW tview AS
SELECT id, upper(val) AS u
FROM t_src
WHERE id <= 2;

SELECT * FROM tview ORDER BY id;
Affichez son DDL :
SHOW CREATE TEMPORARY VIEW tview;
Supprimez-la :
DROP TEMPORARY VIEW IF EXISTS tview;  -- temporary views are dropped with TEMPORARY TABLE syntax

Restrictions / limites

  • CREATE OR REPLACE TEMPORARY VIEW ...non autorisé (utilisez DROP + CREATE).
  • CREATE TEMPORARY MATERIALIZED VIEW ... / WINDOW VIEWnon autorisé.
  • CREATE TEMPORARY VIEW db.view AS ...non autorisé (pas de qualificatif de base de données).
  • CREATE TEMPORARY VIEW view ON CLUSTER 'name' AS ...non autorisé (les objets temporaires sont locaux à la session).
  • POPULATE, REFRESH, TO [db.table], les moteurs internes et toutes les clauses propres aux MV → non applicables aux vues temporaires.

Remarques sur les requêtes distribuées

Une vue temporaire n’est qu’une définition ; il n’y a donc aucune donnée à faire circuler. Si votre vue temporaire fait référence à des tables temporaires (par ex., Memory), leurs données peuvent être envoyées vers des serveurs distants lors de l’exécution distribuée des requêtes, de la même manière que pour les tables temporaires.

Exemple

-- A session-scoped, in-memory table
CREATE TEMPORARY TABLE temp_ids (id UInt64) ENGINE = Memory;

INSERT INTO temp_ids VALUES (1), (5), (42);

-- A session-scoped view over the temp table (purely logical)
CREATE TEMPORARY VIEW v_ids AS
SELECT id FROM temp_ids;

-- Replace 'test' with your cluster name.
-- GLOBAL JOIN forces ClickHouse to *ship* the small join-side (temp_ids via v_ids)
-- to every remote server that executes the left side.
SELECT count()
FROM cluster('test', system.numbers) AS n
GLOBAL ANY INNER JOIN v_ids USING (id)
WHERE n.number < 100;

Dernière modification le 25 juin 2026