Le moteur hérite de [MergeTree](mergetree.md#table_engines-mergetree) et ajoute la logique de réduction des lignes à l'algorithme de fusion des parties de données. `VersionedCollapsingMergeTree` sert le même but que [CollapsingMergeTree](collapsingmergetree.md) mais utilise un autre effondrement algorithme qui permet d'insérer les données dans n'importe quel ordre avec plusieurs threads. En particulier, l' `Version` la colonne aide à réduire correctement les lignes même si elles sont insérées dans le mauvais ordre. Contrairement, `CollapsingMergeTree` permet uniquement une insertion strictement consécutive.
Lors de la création d'un `VersionedCollapsingMergeTree` de table, de la même [clause](mergetree.md) sont requis lors de la création d'un `MergeTree` table.
Considérez une situation où vous devez enregistrer des données en constante évolution pour un objet. Il est raisonnable d'avoir une ligne pour un objet et de mettre à jour la ligne chaque fois qu'il y a des modifications. Cependant, l'opération de mise à jour est coûteuse et lente pour un SGBD car elle nécessite la réécriture des données dans le stockage. La mise à jour n'est pas acceptable si vous devez écrire des données rapidement, mais vous pouvez écrire les modifications sur un objet de manière séquentielle comme suit.
L'utilisation de la `Sign` colonne lors de l'écriture de la ligne. Si `Sign = 1` cela signifie que la ligne est un état d'un objet (appelons-la “state” rangée). Si `Sign = -1` il indique l'annulation de l'état d'un objet avec les mêmes attributs (appelons-la “cancel” rangée). Également utiliser l' `Version` colonne, qui doit identifier chaque état d'un objet avec un numéro distinct.
Par exemple, nous voulons calculer le nombre de pages visitées sur le site et combien de temps ils étaient là. À un moment donné nous écrivons la ligne suivante avec l'état de l'activité de l'utilisateur:
Pour savoir pourquoi nous avons besoin de deux lignes pour chaque changement, voir [Algorithme](#table_engines-versionedcollapsingmergetree-algorithm).
1. Le programme qui écrit les données devraient se souvenir de l'état d'un objet afin de l'annuler. Le “cancel” chaîne doit être une copie de la “state” chaîne avec le contraire `Sign`. Cela augmente la taille initiale de stockage, mais permet d'écrire les données rapidement.
2. Les tableaux de plus en plus longs dans les colonnes réduisent l'efficacité du moteur en raison de la charge d'écriture. Plus les données sont simples, meilleure est l'efficacité.
3.`SELECT` les résultats dépendent fortement de la cohérence de l'histoire de l'objet change. Être précis lors de la préparation des données pour l'insertion. Vous pouvez obtenir des résultats imprévisibles avec des données incohérentes, telles que des valeurs négatives pour des métriques non négatives telles que la profondeur de session.
Lorsque ClickHouse fusionne des parties de données, il supprime chaque paire de lignes ayant la même clé primaire et la même version et différentes `Sign`. L'ordre des lignes n'a pas d'importance.
Lorsque ClickHouse insère des données, il ordonne les lignes par la clé primaire. Si l' `Version` la colonne n'est pas dans la clé primaire, ClickHouse ajoute à la clé primaire implicitement que le dernier champ et l'utilise pour la commande.
ClickHouse ne garantit pas que toutes les lignes avec la même clé primaire sera dans la même partie des données ou même sur le même serveur physique. Cela est vrai à la fois pour l'écriture des données et pour la fusion ultérieure des parties de données. En outre, les processus ClickHouse `SELECT` requêtes avec plusieurs threads, et il ne peut pas prédire l'ordre des lignes dans le résultat. Cela signifie que le regroupement est nécessaire s'il est nécessaire pour obtenir complètement “collapsed” données à partir d'un `VersionedCollapsingMergeTree` table.
Pour finaliser la réduction, écrivez une requête avec un `GROUP BY` fonctions de clause et d'agrégation qui tiennent compte du signe. Par exemple, pour calculer la quantité, l'utilisation `sum(Sign)` plutôt `count()`. Pour calculer la somme de quelque chose, utilisez `sum(Sign * x)` plutôt `sum(x)` et d'ajouter `HAVING sum(Sign) > 0`.
Aggregate `count`, `sum` et `avg` peut être calculée de cette manière. Aggregate `uniq` peut être calculé si un objet a au moins un non-état effondré. Aggregate `min` et `max` ne peut pas être calculé, car `VersionedCollapsingMergeTree` ne sauvegarde pas l'historique des valeurs des États réduits.
Si vous avez besoin d'extraire les données avec “collapsing” mais sans agrégation (par exemple, pour vérifier si des lignes sont présentes dont les valeurs les plus récentes correspondent à certaines conditions), vous pouvez utiliser `FINAL` le modificateur du `FROM` clause. Cette approche est inefficace et ne devrait pas être utilisée avec de grandes tables.
Nous utilisons deux `INSERT` requêtes pour créer deux parties de données différentes. Si nous insérons les données avec une seule requête, ClickHouse crée une partie de données et n'effectuera jamais de fusion.
Que voyons-nous ici et où sont les parties effondrées?
Nous avons créé deux parties de données en utilisant deux `INSERT` requête. Le `SELECT` la requête a été effectuée dans deux threads, et le résultat est un ordre aléatoire de lignes.
L'effondrement n'a pas eu lieu car les parties de données n'ont pas encore été fusionnées. ClickHouse fusionne des parties de données à un moment inconnu que nous ne pouvons pas prédire.