MergeTree et les autres moteurs de la famille MergeTree (par ex. ReplacingMergeTree, AggregatingMergeTree) sont les moteurs de table les plus couramment utilisés et les plus robustes dans ClickHouse.
Les moteurs de table de la famille MergeTree sont conçus pour des taux d’ingestion de données élevés et de très gros volumes de données.
Les opérations d’insertion créent des parties de table, qui sont fusionnées avec d’autres parties de table par un processus d’arrière-plan.
Principales fonctionnalités des moteurs de table de la famille MergeTree.
- La clé primaire de la table détermine l’ordre de tri au sein de chaque partie de table (index clusterisé). La clé primaire ne référence pas non plus des lignes individuelles, mais des blocs de 8192 lignes appelés granules. Cela rend les clés primaires de très gros jeux de données suffisamment petites pour rester chargées en mémoire vive, tout en offrant un accès rapide aux données sur disque.
- Les tables peuvent être partitionnées à l’aide d’une expression de partition arbitraire. L’élagage des partitions garantit que certaines partitions ne sont pas lues lorsque la requête le permet.
- Les données peuvent être répliquées sur plusieurs nœuds du cluster pour assurer la haute disponibilité, le failover et des mises à niveau sans interruption de service. Voir Réplication des données.
-
Les moteurs de table
MergeTreeprennent en charge différents types de statistiques et méthodes d’échantillonnage pour faciliter l’optimisation des requêtes.
Malgré un nom similaire, le moteur Merge est différent des moteurs
*MergeTree.Créer des tables
Clauses de requête
ENGINE
ENGINE — Nom et paramètres du moteur. ENGINE = MergeTree(). Le moteur MergeTree n’a pas de paramètres.
ORDER BY
ORDER BY — La clé de tri.
Un tuple de noms de colonnes ou d’expressions arbitraires. Exemple : ORDER BY (CounterID + 1, EventDate).
Si aucune clé primaire n’est définie (c.-à-d. si PRIMARY KEY n’a pas été spécifiée), ClickHouse utilise la clé de tri comme clé primaire.
Si aucun tri n’est nécessaire, vous pouvez utiliser la syntaxe ORDER BY tuple().
Autrement, si le paramètre create_table_empty_primary_key_by_default est activé, ORDER BY () est ajouté implicitement aux instructions CREATE TABLE. Voir Sélection d’une clé primaire.
PARTITION BY
PARTITION BY — La clé de partitionnement. Facultatif. Dans la plupart des cas, vous n’avez pas besoin de clé de partitionnement, et si vous devez partitionner, il n’est généralement pas nécessaire d’utiliser une clé de partitionnement plus fine qu’un partitionnement mensuel. Le partitionnement n’accélère pas les requêtes (contrairement à l’expression ORDER BY). Vous ne devez jamais utiliser un partitionnement trop fin. Ne partitionnez pas vos données par identifiant ou nom de client (utilisez plutôt l’identifiant ou le nom du client comme première colonne de l’expression ORDER BY).
Pour un partitionnement par mois, utilisez l’expression toYYYYMM(date_column), où date_column est une colonne de type Date. Les noms de partition ont ici le format "YYYYMM".
PRIMARY KEY — La clé primaire, si elle diffère de la clé de tri. Facultatif.
La définition d’une clé de tri (à l’aide de la clause ORDER BY) définit implicitement une clé primaire.
Il n’est généralement pas nécessaire de spécifier la clé primaire en plus de la clé de tri.
SAMPLE BY
SAMPLE BY — Une expression d’échantillonnage. Optionnel.
Si elle est spécifiée, elle doit faire partie de la clé primaire.
L’expression d’échantillonnage doit renvoyer un entier non signé.
Exemple : SAMPLE BY intHash32(UserID) ORDER BY (CounterID, EventDate, intHash32(UserID)).
TTL
TTL — Une liste de règles qui spécifient la durée de conservation des lignes et la logique de déplacement automatique des parts entre les disques et les volumes. Facultatif.
L’expression doit produire un Date ou un DateTime, par exemple TTL date + INTERVAL 1 DAY.
Le type de règle DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'|GROUP BY spécifie l’action à effectuer sur la part si l’expression est vérifiée (atteint l’heure actuelle) : suppression des lignes expirées, déplacement d’une part (si l’expression est vérifiée pour toutes les lignes d’une part) vers le disque spécifié (TO DISK 'xxx') ou vers le volume (TO VOLUME 'xxx'), ou agrégation des valeurs des lignes expirées. Le type de règle par défaut est la suppression (DELETE). Il est possible de spécifier plusieurs règles, mais il ne doit pas y avoir plus d’une règle DELETE.
Pour plus de détails, voir TTL pour les colonnes et les tables
PARAMÈTRES
CounterID et EventDate. Si vous définissez une clause SAMPLE lors de la sélection des données, ClickHouse renverra un échantillon de données pseudorandom uniforme pour un sous-ensemble d’utilisateurs.
Le paramètre index_granularity peut être omis, car 8192 est la valeur par défaut.
Stockage des données
(CounterID, Date), les données de la partie sont triées par CounterID et, pour chaque CounterID, elles sont ordonnées par Date.
Les données appartenant à des partitions différentes sont séparées dans des parties distinctes. En arrière-plan, ClickHouse fusionne les parties de données pour optimiser le stockage. Les parties appartenant à des partitions différentes ne sont pas fusionnées. Le mécanisme de fusion ne garantit pas que toutes les lignes ayant la même clé primaire se trouveront dans une seule et même partie de données.
Les parties de données peuvent être stockées au format Wide ou Compact. Au format Wide, chaque colonne est stockée dans un fichier distinct du système de fichiers, tandis qu’au format Compact, toutes les colonnes sont stockées dans un seul fichier. Le format Compact peut être utilisé pour améliorer les performances des insertions petites et fréquentes.
Le format de stockage des données est contrôlé par les paramètres min_bytes_for_wide_part et min_rows_for_wide_part du moteur de table. Si le nombre d’octets ou de lignes dans une partie de données est inférieur à la valeur du paramètre correspondant, la partie est stockée au format Compact. Sinon, elle est stockée au format Wide. Si aucun de ces paramètres n’est défini, les parties de données sont stockées au format Wide.
Chaque partie de données est logiquement divisée en granules. Un granule est le plus petit ensemble de données indivisible que ClickHouse lit lors de la sélection de données. ClickHouse ne divise ni les lignes ni les valeurs, de sorte que chaque granule contient toujours un nombre entier de lignes. La première ligne d’un granule est marquée par la valeur de la clé primaire de cette ligne. Pour chaque partie de données, ClickHouse crée un fichier d’index qui stocke les marques. Pour chaque colonne, qu’elle fasse partie de la clé primaire ou non, ClickHouse stocke également les mêmes marques. Ces marques permettent de localiser directement les données dans les fichiers de colonnes.
La taille du granule est limitée par les paramètres index_granularity et index_granularity_bytes du moteur de table. Le nombre de lignes dans un granule se situe dans l’intervalle [1, index_granularity], selon la taille des lignes. La taille d’un granule peut dépasser index_granularity_bytes si la taille d’une seule ligne est supérieure à la valeur du paramètre. Dans ce cas, la taille du granule est égale à celle de la ligne.
Clés primaires et index dans les requêtes
(CounterID, Date) comme exemple. Dans ce cas, l’ordre de tri et l’index se présentent comme suit :
CounterID in ('a', 'h'), le serveur lit les données dans les plages de marques[0, 3)et[6, 8).CounterID IN ('a', 'h') AND Date = 3, le serveur lit les données dans les plages de marques[1, 3)et[7, 8).Date = 3, le serveur lit les données dans la plage de marques[1, 10].
index_granularity * 2 lignes supplémentaires dans chaque bloc de données peuvent être lues.
Les index épars permettent de travailler avec un très grand nombre de lignes de table, car dans la plupart des cas, ces index tiennent dans la RAM de l’ordinateur.
ClickHouse n’exige pas de clé primaire unique. Vous pouvez insérer plusieurs lignes avec la même clé primaire.
Vous pouvez utiliser des expressions de type Nullable dans les clauses PRIMARY KEY et ORDER BY, mais cela est fortement déconseillé. Pour autoriser cette fonctionnalité, activez le paramètre allow_nullable_key. Le principe NULLS_LAST s’applique aux valeurs NULL dans la clause ORDER BY.
Sélection d’une clé primaire
-
Améliorer les performances d’un index.
Si la clé primaire est
(a, b), l’ajout d’une autre colonnecaméliorera les performances si les conditions suivantes sont réunies :- Il existe des requêtes avec une condition sur la colonne
c. - De longues plages de données (plusieurs fois plus longues que
index_granularity) avec des valeurs identiques pour(a, b)sont fréquentes. En d’autres termes, l’ajout d’une colonne supplémentaire permet de sauter des plages de données assez longues.
- Il existe des requêtes avec une condition sur la colonne
- Améliorer la compression. ClickHouse trie les données par clé primaire ; ainsi, plus la cohérence est élevée, meilleure est la compression.
- Fournir une logique supplémentaire lors de la fusion des parties de données dans les moteurs CollapsingMergeTree et SummingMergeTree. Dans ce cas, il est judicieux de spécifier une clé de tri différente de la clé primaire.
SELECT.
Vous pouvez créer une table sans clé primaire en utilisant la syntaxe ORDER BY tuple(). Dans ce cas, ClickHouse stocke les données dans l’ordre d’insertion. Si vous souhaitez conserver l’ordre des données lors de l’insertion via des requêtes INSERT ... SELECT, définissez max_insert_threads = 1.
Pour sélectionner les données dans leur ordre initial, utilisez des requêtes SELECT mono-thread.
Choisir une clé primaire différente de la clé de tri
GROUP BY arbitraires et un filtrage sur les dimensions. Comme SummingMergeTree et AggregatingMergeTree agrègent les lignes ayant la même valeur de clé de tri, il est naturel d’y inclure toutes les dimensions. Par conséquent, l’expression de clé se compose d’une longue liste de colonnes, et cette liste doit être mise à jour fréquemment à mesure que de nouvelles dimensions sont ajoutées.
Dans ce cas, il est judicieux de ne conserver dans la clé primaire que quelques colonnes permettant des lectures par plage efficaces, et d’ajouter les autres colonnes de dimension au tuple de la clé de tri.
La modification de la clé de tri avec ALTER est une opération légère, car lorsqu’une nouvelle colonne est ajoutée simultanément à la table et à la clé de tri, les parties de données existantes n’ont pas besoin d’être modifiées. Comme l’ancienne clé de tri est un préfixe de la nouvelle et qu’il n’y a pas de données dans la colonne nouvellement ajoutée, les données sont triées à la fois selon l’ancienne et la nouvelle clé de tri au moment de la modification de la table.
Utilisation des index et des partitions dans les requêtes
SELECT, ClickHouse analyse si un index peut être utilisé. Un index peut être utilisé si la clause WHERE/PREWHERE contient une expression (comme l’un des termes de la conjonction, ou dans son intégralité) correspondant à une opération de comparaison d’égalité ou d’inégalité, ou si elle contient IN ou LIKE avec un préfixe fixe sur des colonnes ou des expressions faisant partie de la clé primaire ou de la clé de partitionnement, ou sur certaines fonctions partiellement répétitives de ces colonnes, ou encore sur des combinaisons logiques de ces expressions.
Il est ainsi possible d’exécuter rapidement des requêtes sur un ou plusieurs intervalles de la clé primaire. Dans cet exemple, les requêtes seront rapides lorsqu’elles portent sur un tag de suivi spécifique, sur un tag spécifique et une plage de dates, sur un tag spécifique et une date, sur plusieurs tags avec une plage de dates, etc.
Examinons le moteur configuré comme suit :
Utilisation de l’index avec des expressions déterministes dans les clés primaires
length(), toDate(), lower(), left(), cityHash64(), toUUID() ; contrairement à now() ou rand()). Si la clé primaire contient des expressions déterministes, ClickHouse peut les appliquer aux valeurs constantes de la requête et utiliser le résultat pour construire des conditions sur l’index de clé primaire. Cela permet d’ignorer des données pour des prédicats comme =, IN et has.
Un cas d’utilisation courant consiste à garder la clé primaire compacte (par exemple, stocker un hash au lieu d’une longue String), tout en permettant à des prédicats sur la colonne d’origine d’utiliser l’index.
Exemple de clé primaire déterministe (mais non injective) :
length('alice') (et les autres constantes) une seule fois et utilise les valeurs de longueur pour restreindre les intervalles dans l’index de clé primaire. Comme la longueur d’une chaîne n’est pas injective, différentes chaînes user_id peuvent avoir la même longueur, si bien que l’index peut lire des granules supplémentaires (faux positifs). Le résultat reste correct, car le prédicat d’origine (user_id = ..., IN, etc.) est toujours appliqué après la lecture.
Si l’expression déterministe est aussi injective (des entrées différentes ne peuvent pas produire la même sortie pour les types d’argument utilisés), ClickHouse peut en outre utiliser efficacement l’index pour les formes niées : !=, NOT IN et NOT has(...). Par exemple, reverse(p) et hex(p) sont injectives pour String.
Exemple de clé primaire injective :
Utilisation de l’index pour les clés primaires partiellement monotones
Index de saut de données
CREATE.
*MergeTree, des index de saut de données peuvent être spécifiés.
Ces index agrègent certaines informations sur l’expression spécifiée dans des blocs composés de granularity_value granules (la taille d’un granule est spécifiée à l’aide du paramètre index_granularity dans le moteur de table). Ces agrégats sont ensuite utilisés dans les requêtes SELECT afin de réduire la quantité de données à lire sur le disque en sautant de grands blocs de données pour lesquels la condition where ne peut pas être satisfaite.
La clause GRANULARITY peut être omise, la valeur par défaut de granularity_value est 1.
Exemple
Types de skip indexes
MergeTree prend en charge les types de skip indexes suivants.
Pour en savoir plus sur l’utilisation des skip indexes pour optimiser les performances,
consultez “Comprendre les index de saut de données de ClickHouse”.
- index
MinMax - index
Set - index
bloom_filter - index
ngrambf_v1(Obsolète) - index
tokenbf_v1(Obsolète) - index
text - index
vector_similarity
Index de saut MinMax
tuple, les valeurs minimale et maximale de chaque élément du tuple sont stockées.)
Syntax
Set
max_rows valeurs uniques de l’expression spécifiée sont stockées.
max_rows = 0 signifie “stocker toutes les valeurs uniques”.
Syntax
Filtre de Bloom
Syntax
false_positive_rate peut prendre une valeur comprise entre 0 et 1 (par défaut : 0.025) et indique la probabilité de générer un résultat positif (ce qui augmente la quantité de données à lire).
Les types de données suivants sont pris en charge :
(U)Int*Float*EnumDateDateTimeStringFixedStringArrayLowCardinalityNullableUUIDMap
Type de données JSON : indexation des chemins JSONPour le type de données
JSON, un index de type bloom filter peut être créé sur l’ensemble des chemins à l’aide de la fonction JSONAllPaths. Cela permet d’ignorer les granules dans lesquelles un chemin JSON interrogé est absent. Voir les index de saut de données pour JSON pour plus de détails.Filtre de Bloom par n-grammes (Obsolète)
À partir de ClickHouse 26.2, avec la disponibilité générale (GA) de l’index
text, l’index ngrambf_v1 n’est plus recommandé pour la recherche en texte intégral.Voir la page “Recherche en texte intégral avec les index de texte” pour plus de détails.Syntax
Cet index fonctionne uniquement avec les types de données suivants :
Pour estimer les paramètres de
ngrambf_v1, vous pouvez utiliser les fonctions définies par l’utilisateur (UDFs).
UDFs for ngrambf_v1
total_number_of_all_gramsprobability_of_false_positives
4300 ngrams dans le granule et vous souhaitez que les faux positifs restent inférieurs à 0.0001.
Les autres paramètres peuvent ensuite être estimés en exécutant les requêtes suivantes :
Filtre de Bloom de jetons
Avec la disponibilité générale (GA) de l’index
text à partir de la version 26.2 de ClickHouse, l’index tokenbf_v1 n’est plus recommandé pour la recherche en texte intégral.Voir la page “Recherche en texte intégral avec des index de texte” pour plus de détails.Syntax
Filtre de Bloom de sparse grams
ngrambf_v1, mais utilise des tokens sparse grams au lieu de ngrams.
Syntax
Index de texte
Similarité vectorielle
Prise en charge des fonctions
WHERE contiennent des appels à des fonctions qui s’appliquent aux colonnes. Si la colonne fait partie d’un index, ClickHouse essaie d’utiliser cet index lors de l’évaluation des fonctions. ClickHouse prend en charge différents sous-ensembles de fonctions pour l’utilisation des index.
Les index de type set peuvent être utilisés par toutes les fonctions. Les autres types d’index sont pris en charge comme suit :
Les fonctions avec un argument constant inférieur à la taille du ngram ne peuvent pas être utilisées par
ngrambf_v1 pour l’optimisation des requêtes.
(*) Pour que hasTokenCaseInsensitive et hasTokenCaseInsensitiveOrNull soient efficaces, l’index tokenbf_v1 doit être créé sur des données converties en minuscules, par exemple INDEX idx (lower(str_col)) TYPE tokenbf_v1(512, 3, 0).
Les filtres de Bloom peuvent produire des faux positifs. Les index
ngrambf_v1, tokenbf_v1, sparse_grams et bloom_filter ne peuvent donc pas être utilisés pour optimiser les requêtes lorsque le résultat attendu d’une fonction est faux.Par exemple :- Peut être optimisé :
s LIKE '%test%'NOT s NOT LIKE '%test%'s = 1NOT s != 1startsWith(s, 'test')
- Ne peut pas être optimisé :
NOT s LIKE '%test%'s NOT LIKE '%test%'NOT s = 1s != 1NOT startsWith(s, 'test')
Projections
Lorsque vous implémentez des projections, vous devez également prendre en compte le paramètre force_optimize_projection.
SELECT utilisant le modificateur FINAL.
Requête de projection
Index de projection
_part_offset, c.-à-d. SELECT _part_offset ORDER BY <index_expr>.
Syntaxe
Types d’index
- basic : équivalent à un index MergeTree standard sur l’expression.
Stockage des projections
MergeTree anonyme. La table est déduite de la requête de définition de la projection. S’il y a une clause GROUP BY, le moteur de stockage sous-jacent devient AggregatingMergeTree, et toutes les fonctions d’agrégation sont converties en AggregateFunction. S’il y a une clause ORDER BY, la table MergeTree l’utilise comme expression de clé primaire. Lors du merge process, la projection part est fusionnée au moyen de la routine de fusion de son stockage. La checksum de la part de la table parent est combinée avec celle de la projection. Les autres tâches de maintenance sont similaires à celles des index de saut.
Analyse de requête
- Vérifiez si la projection peut être utilisée pour répondre à la requête donnée, c’est-à-dire si elle produit le même résultat qu’une requête sur la table de base.
- Sélectionnez la meilleure correspondance possible, c’est-à-dire celle qui contient le moins de granules à lire.
- Le pipeline de requête qui utilise des projections sera différent de celui qui utilise les parts d’origine. Si la projection est absente dans certaines parts, nous pouvons ajouter le pipeline pour la « projeter » à la volée.
Accès concurrent aux données
TTL pour les colonnes et les tables
TTL peut être définie pour l’ensemble de la table ainsi que pour chaque colonne individuellement. Un TTL au niveau de la table peut également spécifier la logique de déplacement automatique des données entre les disques et les volumes, ou de recompression des parts dont toutes les données ont expiré.
Les expressions doivent s’évaluer en type de données Date, Date32, DateTime ou DateTime64.
Syntaxe
Définition de la durée de vie d’une colonne :
interval, utilisez les opérateurs d’intervalle de temps, par exemple :
TTL de colonne
TTL ne peut pas être utilisée pour les colonnes de clé.
Exemples
Création d’une table avec TTL :
Ajout d’un TTL à une colonne d’une table existante
Modification du TTL d’une colonne
TTL de table
TTL.
DELETE- supprime les lignes expirées (action par défaut) ;RECOMPRESS codec_name- recompresse la part de données aveccodec_name;TO DISK 'aaa'- déplace la part vers le disqueaaa;TO VOLUME 'bbb'- déplace la part vers le disquebbb;GROUP BY- agrège les lignes expirées.
DELETE peut être utilisée avec la clause WHERE pour supprimer uniquement certaines lignes expirées en fonction d’une condition de filtrage :
GROUP BY doit être un préfixe de la clé primaire de la table.
Si une colonne ne fait pas partie de l’expression GROUP BY et n’est pas définie explicitement dans la clause SET, alors, dans la ligne de résultat, elle contient une valeur quelconque issue des lignes regroupées (comme si la fonction d’agrégation any lui était appliquée).
Exemples
Création d’une table avec TTL :
Modification du TTL de la table :
Création d’une table avec recompression des lignes expirées :
x contient la valeur maximale des lignes regroupées, y la valeur minimale, et d une valeur quelconque prise parmi les lignes regroupées.
Suppression des données expirées
TTL a expiré sont supprimées lorsque ClickHouse fusionne des parts de données.
Lorsque ClickHouse détecte que des données ont expiré, il effectue une fusion non planifiée. Pour contrôler la fréquence de ces fusions, vous pouvez définir merge_with_ttl_timeout. Si cette valeur est trop faible, de nombreuses fusions non planifiées pourront être effectuées, ce qui risque de consommer beaucoup de ressources.
Si vous exécutez la requête SELECT entre deux fusions, il se peut que vous obteniez des données expirées. Pour l’éviter, utilisez la requête OPTIMIZE avant SELECT.
Voir aussi
- paramètre ttl_only_drop_parts
Types de disque
s3pour S3 et MinIOgcspour GCSblob_storage_diskpour Azure Blob Storagehdfspour HDFSwebpour un accès en lecture seule depuis le Webcachepour la mise en cache locales3_plainpour les sauvegardes sur S3s3_plain_rewritablepour les tables immuables non répliquées sur S3
Utiliser plusieurs périphériques bloc pour le stockage des données
Introduction
MergeTree peuvent stocker les données sur plusieurs périphériques de stockage par blocs. Cela peut par exemple être utile lorsque les données d’une table donnée se répartissent implicitement entre données « chaudes » et « froides ». Les données les plus récentes sont régulièrement consultées, mais ne nécessitent qu’un faible espace de stockage. À l’inverse, le volume important de données historiques est rarement sollicité. Si plusieurs disques sont disponibles, les données « chaudes » peuvent être placées sur des disques rapides (par exemple, des SSD NVMe ou en mémoire), tandis que les données « froides » peuvent être stockées sur des supports relativement lents (par exemple, des HDD).
Cela s’applique à tous les types de disques, y compris S3 et les autres disques de stockage objet. Par exemple, vous pouvez répartir les données entre plusieurs buckets S3 au sein d’un même volume, ou créer des politiques hiérarchisées qui déplacent les données des disques locaux vers S3. Voir Using S3 disks with multiple volumes pour plus de détails.
Une part de données est la plus petite unité déplaçable pour les moteurs de table MergeTree. Les données appartenant à une même part sont stockées sur un seul disque. Les parts de données peuvent être déplacées entre les disques en arrière-plan (selon les paramètres utilisateur), ainsi qu’au moyen des requêtes ALTER.
Termes
- Disque — Périphérique de bloc monté sur le système de fichiers.
- Disque par défaut — Disque qui stocke le chemin spécifié dans le paramètre du serveur path.
- Volume — Ensemble ordonné de disques équivalents (semblable à JBOD).
- Politique de stockage — Ensemble de volumes et règles de déplacement des données entre eux.
storage_policy des tables de la famille de moteurs MergeTree.
Configuration
<storage_configuration>, par exemple dans un fichier du répertoire config.d.
Structure de la configuration :
<disk_name_N>— Nom du disque. Les noms doivent être différents pour tous les disques.path— chemin sous lequel le serveur stockera les données (dossiersdataetshadow), doit se terminer par ’/’.keep_free_space_bytes— quantité d’espace disque libre à réserver.
policy_name_N— Nom de la politique. Les noms de politique doivent être uniques.volume_name_N— Nom du volume. Les noms de volume doivent être uniques.disk— un disque au sein d’un volume.max_data_part_size_bytes— la taille maximale d’une part pouvant être stockée sur l’un des disques du volume. Si la taille estimée d’une part fusionnée dépassemax_data_part_size_bytes, cette part sera écrite sur le volume suivant. En pratique, cette fonctionnalité permet de conserver les parts nouvelles ou de petite taille sur un volume rapide (SSD) et de les déplacer vers un volume lent (HDD) lorsqu’elles deviennent volumineuses. N’utilisez pas ce paramètre si votre politique ne comporte qu’un seul volume.move_factor— lorsque l’espace disponible devient inférieur à ce facteur, les données commencent automatiquement à être déplacées vers le volume suivant, s’il existe (par défaut, 0.1). ClickHouse trie les parts existantes par taille, de la plus grande à la plus petite (ordre décroissant), et sélectionne les parts dont la taille totale est suffisante pour satisfaire la conditionmove_factor. Si la taille totale de toutes les parts est insuffisante, toutes les parts seront déplacées.perform_ttl_move_on_insert— Désactive le TTL move lors de l’INSERT d’une part de données. Par défaut (si cette option est activée), si vous insérez une part de données déjà expirée selon la règle de TTL move, elle est immédiatement placée sur un volume/disque déclaré dans la règle de déplacement. Cela peut considérablement ralentir l’insert si le volume/disque de destination est lent (par ex. S3). Si cette option est désactivée, la part de données déjà expirée est écrite sur le volume par défaut, puis déplacée juste après vers le volume TTL.load_balancing- Politique d’équilibrage des disques,round_robinouleast_used.least_used_ttl_ms- Configure le timeout (en millisecondes) de mise à jour de l’espace disponible sur tous les disques (0- mise à jour systématique,-1- ne jamais mettre à jour, la valeur par défaut est60000). Notez que, si le disque ne peut être utilisé que par ClickHouse et n’est pas sujet à un redimensionnement/réduction à chaud du système de fichiers, vous pouvez utiliser-1; dans tous les autres cas, cela n’est pas recommandé, car cela finira par entraîner une répartition incorrecte de l’espace.prefer_not_to_merge— Vous ne devriez pas utiliser ce paramètre. Il désactive la fusion des parts de données sur ce volume (ce qui est nuisible et entraîne une dégradation des performances). Lorsque ce paramètre est activé (ne le faites pas), la fusion des données sur ce volume n’est pas autorisée (ce qui est mauvais). Cela permet (mais vous n’en avez pas besoin) de contrôler (si vous voulez contrôler quelque chose, vous faites une erreur) la manière dont ClickHouse fonctionne avec des disques lents (mais ClickHouse sait mieux faire, donc n’utilisez pas ce paramètre).volume_priority— Définit la priorité (ordre) selon laquelle les volumes sont remplis. Une valeur plus faible signifie une priorité plus élevée. Les valeurs du paramètre doivent être des nombres naturels et couvrir collectivement l’intervalle de 1 à N (la priorité la plus faible étant attribuée à N), sans en sauter aucune.- Si tous les volumes sont marqués, ils sont priorisés dans l’ordre indiqué.
- Si seulement certains volumes sont marqués, ceux qui ne le sont pas ont la priorité la plus faible et sont priorisés dans l’ordre où ils sont définis dans la config.
- Si aucun volume n’est marqué, leur priorité est définie en fonction de l’ordre dans lequel ils sont déclarés dans la configuration.
- Deux volumes ne peuvent pas avoir la même valeur de priorité.
hdd_in_order implémente l’approche round-robin. Ainsi, cette policy ne définit qu’un seul volume (single) ; les parties de données sont stockées sur tous ses disques selon un ordre circulaire. Une telle policy peut être très utile si plusieurs disques similaires sont montés sur le système, mais que RAID n’est pas configuré. Gardez à l’esprit que chaque disque pris individuellement n’est pas fiable et que vous pouvez compenser cela avec un facteur de réplication de 3 ou plus.
S’il existe différents types de disques sur le système, la policy moving_from_ssd_to_hdd peut être utilisée à la place. Le volume hot se compose d’un disque SSD (fast_ssd), et la taille maximale d’une part pouvant être stockée sur ce volume est de 1GB. Toutes les parts dont la taille est supérieure à 1GB seront stockées directement sur le volume cold, qui contient un disque HDD disk1.
De plus, une fois que le disque fast_ssd est rempli à plus de 80 %, les données seront transférées vers disk1 par un processus d’arrière-plan.
L’ordre d’énumération des volumes au sein d’une politique de stockage est important si au moins l’un des volumes listés n’a pas de paramètre volume_priority explicite.
Une fois qu’un volume est trop rempli, les données sont déplacées vers le suivant. L’ordre d’énumération des disques est également important, car les données y sont stockées à tour de rôle.
Lors de la création d’une table, il est possible de lui appliquer l’une des stratégies de stockage configurées :
default signifie qu’un seul volume est utilisé, lequel se compose d’un seul disque indiqué dans <path>.
Vous pouvez modifier la politique de stockage après la création de la table avec la requête [ALTER TABLE … MODIFY SETTING] ; la nouvelle politique doit inclure tous les anciens disques et volumes en conservant les mêmes noms.
Le nombre de threads qui effectuent les déplacements en arrière-plan des parties de données peut être modifié via le paramètre background_move_pool_size.
Détails
MergeTree, les données sont écrites sur le disque de différentes manières :
- À la suite d’une insertion (requête
INSERT). - Pendant les fusions en arrière-plan et les mutations.
- Lors d’un téléchargement depuis une autre réplique.
- À la suite du gel d’une partition ALTER TABLE … FREEZE PARTITION.
- Le premier volume (dans l’ordre de définition) qui dispose de suffisamment d’espace disque pour stocker une part (
unreserved_space > current_part_size) et autorise le stockage de parts d’une taille donnée (max_data_part_size_bytes > current_part_size) est choisi. - Au sein de ce volume, on choisit le disque qui suit celui utilisé pour stocker le fragment de données précédent et qui dispose d’un espace libre supérieur à la taille de la part (
unreserved_space - keep_free_space_bytes > current_part_size).
move_factor), selon l’ordre dans lequel les volumes sont déclarés dans le fichier de configuration.
Les données ne sont jamais transférées depuis le dernier volume vers le premier. Il est possible d’utiliser les tables système system.part_log (champ type = MOVE_PART) et system.parts (champs path et disk) pour surveiller les déplacements en arrière-plan. Des informations détaillées sont également disponibles dans les logs du serveur.
L’utilisateur peut forcer le déplacement d’une part ou d’une partition d’un volume vers un autre à l’aide de la requête ALTER TABLE … MOVE PART|PARTITION … TO VOLUME|DISK …, toutes les restrictions applicables aux opérations en arrière-plan étant prises en compte. La requête lance elle-même le déplacement et n’attend pas la fin des opérations en arrière-plan. L’utilisateur recevra un message d’erreur si l’espace libre disponible n’est pas suffisant ou si l’une des conditions requises n’est pas remplie.
Le déplacement des données n’interfère pas avec la réplication des données. Par conséquent, différentes politiques de stockage peuvent être spécifiées pour la même table sur différentes répliques.
Une fois les fusions et mutations en arrière-plan terminées, les anciennes parts ne sont supprimées qu’après un certain délai (old_parts_lifetime).
Pendant cette période, elles ne sont pas déplacées vers d’autres volumes ou disques. Par conséquent, jusqu’à leur suppression définitive, elles sont toujours prises en compte dans l’évaluation de l’espace disque occupé.
L’utilisateur peut répartir de nouvelles parts volumineuses entre différents disques d’un volume JBOD de manière équilibrée à l’aide du paramètre min_bytes_to_rebalance_partition_over_jbod.
Utilisation du stockage externe pour les données
S3, AzureBlobStorage et HDFS à l’aide d’un disque de type s3, azure_blob_storage ou hdfs, respectivement. Consultez la configuration des options de stockage externe pour plus de détails.
Exemple d’utilisation de S3 comme stockage externe à l’aide d’un disque de type s3.
Extrait de configuration :
Utiliser des disques S3 avec plusieurs volumes
Lorsque
use_environment_credentials est utilisé pour l’authentication S3, les identifiants d’environnement (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) sont partagés entre tous les disques S3. Il n’est pas possible d’utiliser des identifiants d’environnement différents selon les disques. Si vous avez besoin d’identifiants distincts pour chaque disque S3, utilisez plutôt des paramètres access_key_id et secret_access_key explicites pour chaque disque.table_disk = true avec un disque local à la table). Voir refresh_parts_interval and table_disk.
configuration du cacheLes versions 22.3 à 22.7 de ClickHouse utilisent une configuration du cache différente ; consultez using local cache si vous utilisez l’une de ces versions.
Colonnes virtuelles
_part— Nom d’une part._part_index— Indice séquentiel de la part dans le résultat de la requête._part_starting_offset— Ligne de début cumulée de la part dans le résultat de la requête._part_offset— Numéro de la ligne dans la part._part_granule_offset— Numéro du granule dans la part._partition_id— Nom d’une partition._part_uuid— Identifiant unique de la part (si le paramètre MergeTreeassign_part_uuidsest activé)._part_data_version— Version des données de la part (soit le numéro de bloc minimal, soit la version de la mutation)._partition_value— Valeurs (un tuple) d’une expressionpartition by._sample_factor— Facteur d’échantillonnage (issu de la requête)._block_number— Numéro d’origine du bloc pour la ligne, attribué lors de l’insertion et conservé lors des fusions lorsque le paramètreenable_block_number_columnest activé._block_offset— Numéro d’origine de la ligne dans le bloc, attribué lors de l’insertion et conservé lors des fusions lorsque le paramètreenable_block_offset_columnest activé._disk_name— Nom du disque utilisé pour le stockage.
Statistiques de colonne
CREATE des tables de la famille *MergeTree* :
ALTER :
set use_statistics = 1.
Élagage des parts avec des statistiques
use_statistics_for_part_pruning est activé, les statistiques peuvent être utilisées pour l’élagage des parts.
Actuellement, seules les statistiques basic (ainsi que les statistiques minmax obsolètes) prennent en charge l’élagage des parts. Lorsque de telles statistiques sont définies sur une colonne, ClickHouse enregistre les valeurs minimale et maximale de cette colonne dans chaque part.
L’élagage des parts permet d’éviter la lecture de parts de données entières lorsque la condition de filtre de la requête ne peut correspondre à aucune ligne dans cette part.
Exemple :
Types disponibles de statistiques de colonne
-
basicUn ensemble compact de résumés à valeur unique dérivés d’une colonne. Selon le type de la colonne, les éléments suivants sont renseignés :-
pour toute colonne dont les valeurs sont représentées par un nombre (entiers, flottants,
Decimal*,Date*,DateTime*,Enum*,IPv4, …) : les valeurs minimale et maximale, qui permettent d’estimer la sélectivité des filtres de plage et d’effectuer l’élagage des parts ; -
pour les colonnes
StringetFixedString: la longueur totale en octets des valeurs nonNULL(à partir de laquelle la longueur moyenne des chaînes peut être déduite) ; -
pour les colonnes
NullableetLowCardinality(Nullable): le nombre de valeursNULL, que l’optimiseur utilise pour exclure les lignesNULLdes estimations de sélectivité. Une seule statistiquebasicpeut renseigner plusieurs de ces éléments à la fois — par exemple, sur une colonneNullable(UInt32), elle suit à la fois les min/max numériques et le nombre de valeurs nulles. Par rapport àminmax,basicfonctionne aussi sur les colonnesString/FixedStringet peut être déclarée sur des wrappersNullablede types commeUUIDouIPv6uniquement pour suivre le nombre de valeurs nulles.
-
pour toute colonne dont les valeurs sont représentées par un nombre (entiers, flottants,
-
minmax(obsolète)
Les statistiques
minmax sont obsolètes et ne peuvent plus être créées (CREATE TABLE ... STATISTICS(minmax) et ALTER TABLE ... ADD/MODIFY STATISTICS ... TYPE minmax renvoient une erreur). Les tables et parts existantes avec des statistiques minmax continuent de fonctionner. Utilisez plutôt les statistiques basic.tdigest
-
uniqDes sketches BJKST qui fournissent une estimation du nombre de valeurs distinctes contenues dans une colonne. Utilise en interneuniq. -
uniq_v2Similaire àuniq, mais utilise en interneuniqCombined(12)(une variante de HyperLogLog). Consomme moins de mémoire queuniqet peut être compilé plus rapidement. -
countmin
Types de données pris en charge
Tous les éléments ci-dessus acceptent également les wrappers
Nullable et LowCardinality(Nullable) des types indiqués. Basic peut aussi être déclaré sur des wrappers Nullable de types comme UUID ou IPv6, uniquement pour suivre le nombre de valeurs nulles.
Opérations prises en charge
Pour
basic sur les colonnes String / FixedString, la statistique n’enregistre que la longueur totale en octets des valeurs non-NULL
(utilisée pour estimer la longueur moyenne des chaînes) et le nombre de valeurs NULL ;
les filtres par plage et l’élagage des parts ne s’appuient pas sur elle.
Paramètres au niveau des colonnes
max_compress_block_size— Taille maximale des blocs de données non compressées avant leur compression pour l’écriture dans une table.min_compress_block_size— Taille minimale des blocs de données non compressées requise pour la compression lors de l’écriture du mark suivant.
- Supprimez
SETTINGSde la déclaration de la colonne :
- Modifiez un paramètre :
- Réinitialise un ou plusieurs paramètres et supprime également la déclaration du paramètre dans l’expression de colonne de la requête CREATE de la table.