Skip to main content

Description

Le moteur CollapsingMergeTree hérite de MergeTree et ajoute une logique de collapsing des lignes pendant le processus de fusion. Le moteur de table CollapsingMergeTree supprime (collapsing) de manière asynchrone des paires de lignes si tous les champs d’une clé de tri (ORDER BY) sont équivalents, à l’exception du champ spécial Sign, qui peut prendre la valeur 1 ou -1. Les lignes qui n’ont pas de paire avec une valeur Sign opposée sont conservées. Pour plus de détails, consultez la section Collapsing de ce document.
Ce moteur peut réduire considérablement le volume de stockage, et ainsi améliorer l’efficacité des requêtes SELECT.

Paramètres

Tous les paramètres de ce moteur de table, à l’exception du paramètre Sign, ont la même signification que dans MergeTree.
  • Sign — Le nom donné à une colonne indiquant le type de ligne, où 1 correspond à une ligne d’état et -1 à une ligne d’annulation. Type : Int8.

Créer une table

  • Pour une description des paramètres de requête, voir description de la requête.
  • Lors de la création d’une table CollapsingMergeTree, les mêmes clauses de requête sont requises que pour la création d’une table MergeTree.

Collapsing

Données

Considérez le cas où vous devez enregistrer des données qui changent continuellement pour un objet donné. Il peut sembler logique d’avoir une ligne par objet et de la mettre à jour chaque fois que quelque chose change, cependant, les opérations de mise à jour sont coûteuses et lentes pour le SGBD, car elles nécessitent de réécrire les données dans le stockage. Si nous devons écrire des données rapidement, effectuer un grand nombre de mises à jour n’est pas une approche acceptable, mais nous pouvons toujours écrire les modifications d’un objet de manière séquentielle. Pour ce faire, nous utilisons la colonne spéciale Sign.
  • Si Sign = 1, cela signifie que la ligne est une ligne d‘“état” : une ligne contenant des champs qui représentent un état valide actuel.
  • Si Sign = -1, cela signifie que la ligne est une ligne d‘“annulation” : une ligne utilisée pour annuler l’état d’un objet ayant les mêmes attributs.
Par exemple, nous voulons calculer combien de pages les utilisateurs ont consultées sur un certain site web et combien de temps ils les ont visitées. À un instant donné, nous écrivons la ligne suivante avec l’état de l’activité de l’utilisateur :
À un moment ultérieur, nous enregistrons le changement d’activité de l’utilisateur et le consignons dans les deux lignes suivantes :
La première ligne annule l’état précédent de l’objet (qui représente ici un utilisateur). Elle doit copier tous les champs de la clé de tri de la ligne “canceled”, à l’exception de Sign. La deuxième ligne ci-dessus contient l’état actuel. Comme nous n’avons besoin que du dernier état de l’activité de l’utilisateur, la ligne “state” d’origine et la ligne “cancel” que nous avons insérées peuvent être supprimées comme indiqué ci-dessous, ce qui provoque la suppression par collapsing de l’état invalide (ancien) d’un objet :
CollapsingMergeTree met précisément en œuvre ce comportement de collapsing lors de la fusion des parties de données.
La raison pour laquelle deux lignes sont nécessaires pour chaque modification est expliquée plus en détail dans le paragraphe Algorithme.
Les particularités d’une telle approche
  1. Le programme qui écrit les données doit mémoriser l’état d’un objet pour pouvoir l’annuler. La ligne “cancel” doit contenir des copies des champs de la clé de tri de la ligne “state”, ainsi que le Sign opposé. Cela augmente la taille initiale du stockage, mais permet d’écrire les données rapidement.
  2. De longs tableaux dans les colonnes réduisent l’efficacité du moteur en raison de la charge d’écriture plus élevée. Plus les données sont simples, plus l’efficacité est élevée.
  3. Les résultats de SELECT dépendent fortement de la cohérence de l’historique des modifications de l’objet. Soyez vigilant lors de la préparation des données à insérer. Des données incohérentes peuvent produire des résultats imprévisibles. Par exemple, des valeurs négatives pour des métriques non négatives, comme la profondeur de session.

Algorithme

Lorsque ClickHouse fusionne des parts, chaque groupe de lignes consécutives ayant la même clé de tri (ORDER BY) est réduit à deux lignes au maximum : la ligne « état » avec Sign = 1 et la ligne « annulation » avec Sign = -1. Autrement dit, dans ClickHouse, les entrées sont collapsées. Pour chaque partie de données résultante, ClickHouse conserve : De plus, lorsqu’il y a au moins deux lignes « état » de plus que de lignes « annulation », ou au moins deux lignes « annulation » de plus que de lignes « état », la fusion se poursuit. ClickHouse traite toutefois cette situation comme une erreur logique et l’enregistre dans le journal du serveur. Cette erreur peut se produire si les mêmes données sont insérées plusieurs fois. Ainsi, le collapsing ne doit pas modifier les résultats du calcul des statistiques. Les modifications sont progressivement collapsées, de sorte qu’à la fin, seul le dernier état de presque chaque objet subsiste. La colonne Sign est requise, car l’algorithme de fusion ne garantit pas que toutes les lignes ayant la même clé de tri se retrouveront dans la même partie de données résultante, ni même sur le même serveur physique. ClickHouse traite les requêtes SELECT avec plusieurs threads et ne peut pas prédire l’ordre des lignes dans le résultat. Une agrégation est nécessaire si vous devez obtenir des données entièrement « collapsées » à partir de la table CollapsingMergeTree. Pour finaliser le collapsing, écrivez une requête avec la clause GROUP BY et des fonctions d’agrégation qui tiennent compte du signe. Par exemple, pour calculer la quantité, utilisez sum(Sign) au lieu de count(). Pour calculer la somme d’une valeur, utilisez sum(Sign * x) avec HAVING sum(Sign) > 0 au lieu de sum(x) comme dans l’exemple ci-dessous. Les agrégats count, sum et avg peuvent être calculés de cette manière. L’agrégat uniq peut être calculé si un objet possède au moins un état non collapsé. Les agrégats min et max ne peuvent pas être calculés, car CollapsingMergeTree ne conserve pas l’historique des états collapsés.
Si vous devez extraire des données sans agrégation (par exemple, pour vérifier si des lignes dont les valeurs les plus récentes correspondent à certaines conditions sont présentes), vous pouvez utiliser le modificateur FINAL pour la clause FROM. Il fusionnera les données avant de renvoyer le résultat. Pour CollapsingMergeTree, seule la ligne d’état la plus récente pour chaque clé est renvoyée.

Exemples

Exemple d’utilisation

Considérons les données d’exemple suivantes :
Créons une table UAct en utilisant CollapsingMergeTree :
Ensuite, nous allons insérer des données :
Nous utilisons deux requêtes INSERT pour créer deux parties de données distinctes.
Si nous insérons les données avec une seule requête, ClickHouse ne crée qu’une seule partie de données et n’effectuera jamais de fusion.
Nous pouvons sélectionner les données à l’aide de :
Examinons les données renvoyées ci-dessus pour voir si le collapsing a eu lieu… Avec deux requêtes INSERT, nous avons créé deux parties de données. La requête SELECT a été exécutée dans deux threads, et nous avons obtenu les lignes dans un ordre aléatoire. Cependant, le collapsing n’a pas eu lieu, car il n’y a pas encore eu de fusion des parties de données, et ClickHouse fusionne les parties de données en arrière-plan à un moment imprévisible. Nous avons donc besoin d’une agrégation, que nous effectuons avec la fonction d’agrégation sum et la clause HAVING :
Si nous n’avons pas besoin d’agrégation et souhaitons forcer le collapsing, nous pouvons également utiliser le modificateur FINAL dans la clause FROM.
Cette façon de sélectionner les données est moins efficace et n’est pas recommandée pour de grands volumes de données parcourues (des millions de lignes).

Exemple d’une autre approche

Cette approche repose sur l’idée que les fusions ne prennent en compte que les champs clés. Dans la ligne “annulation”, nous pouvons donc spécifier des valeurs négatives qui annulent l’effet de la version précédente de la ligne lors de la somme, sans utiliser la colonne Sign. Pour cet exemple, nous utiliserons les données d’exemple ci-dessous :
Pour cette approche, il est nécessaire de modifier les types de données de PageViews et Duration afin de pouvoir stocker des valeurs négatives. Nous modifions donc le type de ces colonnes, de UInt8 à Int16, lorsque nous créons notre table UAct à l’aide de collapsingMergeTree :
Testons cette approche en insérant des données dans notre table. Pour des exemples ou de petites tables, cela reste toutefois acceptable :
Dernière modification le 23 juillet 2026