Skip to main content
Dans la version 24.3 de ClickHouse, l’analyseur a été activé par défaut. Vous trouverez plus de détails sur son fonctionnement ici.

Incompatibilités connues

Bien qu’elle corrige un grand nombre de bugs et apporte de nouvelles optimisations, cette version introduit également certains changements incompatibles dans le comportement de ClickHouse. Veuillez prendre connaissance des modifications ci-dessous afin de déterminer comment réécrire vos requêtes pour l’analyseur.

Les requêtes invalides ne sont plus optimisées

L’ancienne infrastructure de planification des requêtes appliquait des optimisations au niveau de l’AST avant l’étape de validation des requêtes. Les optimisations pouvaient réécrire la requête initiale pour la rendre valide et exécutable. Dans l’analyseur, la validation des requêtes a lieu avant l’étape d’optimisation. Cela signifie que les requêtes invalides qu’il était auparavant possible d’exécuter ne sont désormais plus prises en charge. Dans ce cas, la requête doit être corrigée manuellement.

Exemple 1

La requête suivante utilise la colonne number dans la liste de projection, alors que seul toString(number) est disponible après l’agrégation. Dans l’ancien analyseur, GROUP BY toString(number) était optimisé en GROUP BY number,, ce qui rendait la requête valide.

Exemple 2

Le même problème se pose dans cette requête. La colonne number est utilisée après agrégation avec une autre clé. L’ancien analyseur de requêtes corrigeait cette requête en déplaçant le filtre number > 5 de la clause HAVING vers la clause WHERE.
Pour corriger la requête, vous devez déplacer dans la section WHERE toutes les conditions qui s’appliquent à des colonnes non agrégées, afin de respecter la syntaxe SQL standard :
Pour faciliter la migration, l’analyseur peut reproduire l’ancienne réécriture de HAVING vers WHERE pour les conjonctions AND non agrégées. Activez analyzer_compatibility_allow_non_aggregate_in_having = 1 pour adopter ce comportement. Ce paramètre est disponible depuis ClickHouse 26.7. Le paramètre est ignoré pour WITH CUBE, WITH ROLLUP, WITH TOTALS et GROUPING SETS. Les conjonctions contenant des fonctions d’agrégation, grouping ou des fonctions non déterministes restent dans HAVING ; si une conjonction contient une fonction de fenêtre ou une fonction avec état (par exemple rowNumberInBlock), la réécriture est désactivée pour l’ensemble de HAVING, conformément au comportement legacy.

CREATE VIEW avec une requête invalide

L’analyseur effectue toujours un contrôle de type. Auparavant, il était possible de créer une VIEW avec une requête SELECT invalide. Elle échouait ensuite lors du premier SELECT ou INSERT (dans le cas d’une MATERIALIZED VIEW). Il n’est désormais plus possible de créer une VIEW de cette manière.

Exemple

Incompatibilités connues de la clause JOIN

JOIN avec une colonne issue d’une projection

Par défaut, un alias de la liste SELECT ne peut pas être utilisé comme clé JOIN USING. Un nouveau paramètre, analyzer_compatibility_join_using_top_level_identifier, lorsqu’il est activé, modifie le comportement de JOIN USING afin de privilégier la résolution des identifiants à partir des expressions de la liste de projection de la requête SELECT, plutôt que d’utiliser directement les colonnes de la table de gauche. Par exemple :
Avec analyzer_compatibility_join_using_top_level_identifier défini sur true, la condition de jointure est interprétée comme t1.a + 1 = t2.b, conformément au comportement des versions antérieures. Le résultat sera 2, 'two'. Lorsque ce paramètre est défini sur false, la condition de jointure devient par défaut t1.b = t2.b, et la requête renverra 2, 'one'. Si b n’est pas présent dans t1, la requête échouera avec une erreur.

Changements de comportement avec JOIN USING et les colonnes ALIAS/MATERIALIZED

Dans l’analyseur, l’utilisation de * dans une requête JOIN USING faisant intervenir des colonnes ALIAS ou MATERIALIZED inclura ces colonnes dans le jeu de résultats par défaut. Par exemple :
Dans l’analyseur, le résultat de cette requête inclura la colonne payload, ainsi que id provenant des deux tables. En revanche, l’analyseur précédent n’incluait ces colonnes ALIAS que lorsque certains paramètres (asterisk_include_alias_columns ou asterisk_include_materialized_columns) étaient activés, et les colonnes pouvaient apparaître dans un ordre différent. Pour garantir des résultats cohérents et conformes aux attentes, en particulier lors de la migration d’anciennes requêtes vers l’analyseur, il est conseillé de spécifier explicitement les colonnes dans la clause SELECT plutôt que d’utiliser *.

Gestion des modificateurs de type pour les colonnes dans la clause USING

Dans l’analyseur, les règles de détermination du supertype commun pour les colonnes spécifiées dans la clause USING ont été harmonisées afin de produire des résultats plus prévisibles, en particulier lors de l’utilisation de modificateurs de type tels que LowCardinality et Nullable.
  • LowCardinality(T) et T : lorsqu’une colonne de type LowCardinality(T) est mise en jointure avec une colonne de type T, le supertype commun obtenu sera T, ce qui supprime de fait le modificateur LowCardinality.
  • Nullable(T) et T : lorsqu’une colonne de type Nullable(T) est mise en jointure avec une colonne de type T, le supertype commun obtenu sera Nullable(T), ce qui garantit que la propriété de nullabilité est conservée.
Par exemple :
Dans cette requête, le supertype commun de id est déterminé comme étant String, le modificateur LowCardinality de t1 étant ignoré.

Modifications des noms de colonnes de projection

Lors du calcul des noms de projection, les alias ne sont pas remplacés.

Types d’arguments de fonction incompatibles

Dans l’analyseur, l’inférence de type a lieu lors de l’analyse de la requête initiale. Ce changement signifie que les vérifications de type sont effectuées avant l’évaluation en court-circuit ; les arguments de la fonction if doivent donc toujours avoir un supertype commun. Par exemple, la requête suivante échoue avec There is no supertype for types Array(UInt8), String because some of them are Array and some of them are not:

Clusters hétérogènes

L’analyseur modifie sensiblement le protocole de communication entre les serveurs du cluster. Il est donc impossible d’exécuter des requêtes distribuées sur des serveurs dont les valeurs du paramètre enable_analyzer diffèrent.

Les mutations sont interprétées par l’ancien analyseur

Les mutations utilisent encore l’ancien analyseur. Cela signifie que certaines nouvelles fonctionnalités de ClickHouse SQL ne peuvent pas être utilisées dans les mutations. Par exemple, la clause QUALIFY. Vous pouvez en suivre l’état ici.

Fonctionnalités non prises en charge

La liste des fonctionnalités que l’analyseur ne prend pas encore en charge figure ci-dessous :
  • Index Annoy.
  • Index Hypothesis. Prise en charge en cours ici.
  • La vue fenêtrée n’est pas prise en charge. Aucune prise en charge n’est prévue à l’avenir.

Migration vers Cloud

Nous activons l’analyseur sur toutes les instances où il est actuellement désactivé, afin de permettre de nouvelles optimisations fonctionnelles et de performance. Cette modification applique des règles de portée SQL plus strictes et oblige les clients à mettre à jour manuellement les requêtes non conformes.

Workflow de migration

  1. Identifiez la requête en filtrant system.query_log à l’aide de normalized_query_hash :
  1. Exécutez la requête avec l’analyseur activé en ajoutant les paramètres suivants.
  1. Refactorisez et vérifiez le résultat de la requête afin de vous assurer qu’il correspond à la sortie générée lorsque l’analyseur est désactivé.
Veuillez consulter les incompatibilités les plus fréquentes rencontrées lors des tests internes.

Identifiant d’expression inconnu

Erreur : Unknown expression identifier ... in scope ... (UNKNOWN_IDENTIFIER). Code d’exception : 47 Cause : Les requêtes qui reposent sur des comportements legacy non standard et permissifs, comme la référence à des alias calculés dans des filtres, des projections de sous-requêtes ambiguës ou une portée de CTE « dynamic », sont désormais correctement reconnues comme invalides et rejetées immédiatement. Solution : Mettez à jour vos modèles SQL comme suit :
  • Logique de filtrage : déplacez la logique de WHERE vers HAVING si vous filtrez sur les résultats, ou dupliquez l’expression dans WHERE si vous filtrez sur les données source.
  • Portée des sous-requêtes : sélectionnez explicitement toutes les colonnes nécessaires à la requête externe.
  • Clés de jointure : utilisez ON avec des expressions complètes plutôt que USING si la clé est un alias.
  • Dans les requêtes externes, référencez l’alias de la sous-requête/CTE elle-même, et non les tables qu’elle contient.

Colonnes non agrégées dans GROUP BY

Erreur : Column ... is not under aggregate function and not in GROUP BY keys (NOT_AN_AGGREGATE). Code d’exception : 215 Cause : L’ancien analyseur permettait de sélectionner des colonnes absentes de la clause GROUP BY (en prenant souvent une valeur arbitraire). L’analyseur suit la norme SQL : chaque colonne sélectionnée doit être soit agrégée, soit une clé de regroupement. Solution : encapsulez la colonne dans any(), argMax(), ou ajoutez-la au GROUP BY.

Colonnes non agrégées dans HAVING

Erreur : Column ... is not under aggregate function and not in GROUP BY keys (NOT_AN_AGGREGATE). Code d’exception : 215 Cause : L’ancien analyseur déplaçait silencieusement vers WHERE les conjonctions non agrégées reliées par AND dans HAVING, en les traitant comme des filtres de pré-agrégation. L’analyseur respecte le standard SQL : HAVING ne peut référencer que les clés d’agrégation et les fonctions d’agrégation. Solution : Déplacez manuellement le prédicat de HAVING vers WHERE, ou activez analyzer_compatibility_allow_non_aggregate_in_having = 1 (disponible depuis ClickHouse 26.7) pour rétablir la réécriture legacy afin de faciliter la migration. Ce paramètre de compatibilité est ignoré pour WITH CUBE, WITH ROLLUP, WITH TOTALS et GROUPING SETS. Les conjonctions contenant fonction d’agrégation, grouping ou des fonctions non déterministes restent dans HAVING ; si une conjonction contient une fonction de fenêtre ou une fonction avec état (par exemple rowNumberInBlock), la réécriture est désactivée pour l’ensemble de HAVING, conformément au comportement legacy.

Noms de CTE en double

Erreur : CTE with name ... already exists (MULTIPLE_EXPRESSIONS_FOR_ALIAS). Code d’exception : 179 Cause : l’ancien analyseur permettait de définir plusieurs expressions de table communes (WITH …) portant le même nom, en masquant la précédente. L’analyseur interdit cette ambiguïté. Solution : renommez les CTE en double pour leur donner des noms uniques.

Identifiants de colonnes ambigus

Erreur : JOIN [JOIN TYPE] ambiguous identifier ... (AMBIGUOUS_IDENTIFIER) Code d’exception : 207 Cause : La requête fait référence à un nom de colonne présent dans plusieurs tables d’un JOIN sans préciser la table source. L’ancien analyseur devinait souvent la colonne selon une logique interne ; l’analyseur exige désormais un nom explicite. Solution : Qualifiez entièrement la colonne avec table_alias.column_name.

Utilisation incorrecte de FINAL

Erreur : Table expression modifiers FINAL are not supported for subquery... ou Storage ... doesn't support FINAL (UNSUPPORTED_METHOD). Codes d’exception : 1, 181 Cause : FINAL est un modificateur du stockage des tables (plus précisément pour [Shared]ReplacingMergeTree). L’analyseur rejette FINAL lorsqu’il est appliqué à :
  • des sous-requêtes ou des tables dérivées (par ex., FROM (SELECT …) FINAL).
  • des moteurs de table qui ne le prennent pas en charge (par ex., SharedMergeTree).
Solution : appliquez FINAL uniquement à la table source à l’intérieur de la sous-requête, ou supprimez-le si le moteur ne le prend pas en charge.

Insensibilité à la casse de la fonction countDistinct()

Erreur : Function with name countdistinct does not exist (UNKNOWN_FUNCTION). Code d’exception : 46 Cause : Les noms de fonction sont sensibles à la casse ou associés de manière stricte dans l’analyseur. countdistinct (tout en minuscules) n’est plus reconnu automatiquement. Solution : Utilisez la forme standard countDistinct (camelCase) ou uniq, spécifique à ClickHouse.
Dernière modification le 23 juillet 2026