Changements incompatibles avec les versions précédentes
Modifications des requêtes, des fonctions et de la syntaxe
- Pour les vues dont le corps est un simple
SELECTsur une seule tableDistributed, l’intégralité de la requête externe est désormais transmise aux shards (nouveau paramètreoptimize_trivial_view_pushdown_to_distributed, activé par défaut). Cela modifie le comportement observable de ces vues : les clausesFINALetSAMPLEappliquées à la référence de la vue sont désormais propagées à la table locale du shard au lieu d’être ignorées, etextremesn’est plus renvoyé sur les clusters à un seul shard. Définissezoptimize_trivial_view_pushdown_to_distributed = 0pour rétablir le comportement précédent. #101791 (simonmichal). - Les patch parts des
UPDATElégers utilisent désormais un nouveau format sur disque v2, trié par (sorting_key..., _block_number, _block_offset) et appliqué au moyen d’un nouvel algorithme de fusion. Le pic de mémoire est désormais borné par la plus longue séquence de clés de tri identiques, et non plus par la taille totale du patch, et les mises à jour qui franchissent les limites de fusion ne se rabattent plus sur une application par Join en mémoire. Les patch parts à l’ancien format restent lisibles. Lors d’une mise à niveau progressive depuis une version antérieure à 26.8, conservezpatch_parts_version = 'v1'ou utilisez le paramètrecompatibilityjusqu’à ce que toutes les répliques soient mises à niveau. #103182 (CurtizJ). AggregatingMergeTreerejette désormais, dès la création de la table, les schémas dans lesquels une colonne ne fait partie ni de la clé de tri ni d’une mesure d’état d’agrégation (AggregateFunction/SimpleAggregateFunction). Ces colonnes sont en effet réduites silencieusement à une valeur arbitraire lors des fusions en arrière-plan, ce qui produit des résultats erronés pour les requêtes qui effectuent unGROUP BYou un filtrage sur celles-ci. Définissezallow_dimensions_outside_sorting_key = 1pour rétablir le comportement précédent. #108087 (alexey-milovidov).- ClickHouse utilise désormais systématiquement le hachage unifié de déduplication des insertions, pour les insertions synchrones comme asynchrones ; les anciens comportements de déduplication par insertion sont supprimés. Le paramètre serveur
insert_deduplication_versionest conservé comme garde-fou de migration : le serveur refuse de démarrer s’il est défini sur une valeur legacy (old_separate_hashesoucompatible_double_hashes). Pour effectuer une mise à niveau depuis une version utilisant une valeur legacy, exécutez d’abord une version prenant en chargecompatible_double_hashes(qui écrit à la fois les hachages legacy et unifiés). Pour les tables répliquées, exécutez-la pendant au moinsreplicated_deduplication_window_seconds(une heure par défaut ; avec les fenêtres par défaut, les hachages unifiés de toutes les insertions sont conservés sur cette période, ce qui est jugé suffisant pour une boucle de nouvelles tentatives d’insertion). Pour les tables non répliquées avecnon_replicated_deduplication_window> 0, cette fenêtre repose sur un nombre d’insertions plutôt que sur une durée : exécutez donccompatible_double_hashespendant au moins ce nombre d’insertions. Supprimez ensuite le paramètre (ou définissez-le surnew_unified_hash) avant de passer à cette version. #108361 (CheSema). - Le paramètre
use_legacy_to_timevaut désormais0par défaut :toTimeconvertit donc les valeurs vers le type de donnéesTimeau lieu de convertir une date avec heure en une date fixe. L’ancien comportement reste disponible via la fonctiontoTimeWithFixedDateou en définissantuse_legacy_to_time = 1. #108729 (alexey-milovidov). - Les modèles Naive Bayes (utilisés par
naiveBayesClassifier) sont désormais configurés sous forme de dictionnaire avec la dispositionNAIVE_BAYES, construit au chargement à partir d’une table de comptages de n-grammes pré-agrégés par classe. Ils remplacent l’ancienne configuration côté serveur (un fichier de configuration XML référençant des fichiers de modèle.binsérialisés), qui n’est plus prise en charge : les modèles existants doivent être recréés sous forme de dictionnaires. Trois nouvelles fonctions viennent compléternaiveBayesClassifier:naiveBayesClassifierWithProbrenvoie la classe prédite accompagnée de sa probabilité,naiveBayesClassifierWithAllProbsrenvoie chaque classe avec sa probabilité, etnaiveBayesNgramsdécoupe le texte en n-grammes de la même manière que le dictionnaire, afin de construire les données d’entraînement à partir de texte brut étiqueté. Par ailleurs, plusieurs optimisations de performances ont été apportées : sur un modèle de langue à trigrammes de points de code de 9,7 MiB, la consommation mémoire est environ 49 fois plus faible (de 1,84 GiB à 38 MiB), et le chargement comme la classification sont environ 11 fois plus rapides. #108773 (nihalzp). - La valeur par défaut du paramètre
max_insert_threadspasse de1(aucun parallélisme) àauto, qui correspond au nombre de cœurs CPU disponibles pour le serveur (réduit en cas de pression mémoire viamax_insert_threads_min_free_memory_per_thread).INSERT SELECTest ainsi parallélisé par défaut, et la partie écriture d’unINSERTsimple éligible peut également l’être lorsque le chemin d’écriture de destination peut être réparti en toute sécurité. Cela peut modifier le nombre de parts créées et l’ordre des lignes insérées. Pour rétablir le comportement précédent, définissezmax_insert_threadssur1, oucompatibilitysur une version antérieure à26.8. #109000 (alexey-milovidov). #109006 (alexey-milovidov). - La lecture au format CSV d’un
Tupleutilisé seul prend désormais un champ par élément à chaque position : un\Ndans le champ d’un élément de premier niveau correspond donc à cet élément, etinput_format_null_as_defaults’y applique. Auparavant, un\Ninitial était interprété comme une valeur nulle pour la colonne entière : la ligne était alors remplacée par la valeur par défaut de la colonne, puis l’analyse des cellules restantes échouait. Ce changement est non rétrocompatible pour une ligne qui fournit un seul champ pour l’ensemble d’unTupleutilisé seul : il lui manque désormais les éléments restants et elle est rejetée ; pour unTupleà un seul élément, où le nombre de champs est identique dans les deux cas, elle produit silencieusement la valeur par défaut de l’élément au lieu duDEFAULTde la colonne. Définissezinput_format_csv_deserialize_separate_columns_into_tuple = 0pour lire de nouveau un tel champ comme la colonne entière. #109744 (groeneai). - Ajout de la clause
VALID FOR <interval>àCREATE USERetALTER USER, comme raccourci deVALID UNTIL. L’échéance d’expiration est calculée en ajoutant l’intervalle indiqué à l’heure courante au moment de l’exécution de la requête, puis stockée sous la formeVALID UNTIL. La colonnevalid_untilde la tablesystem.usersest désormais de typeArray(DateTime64(0))au lieu deArray(DateTime), afin de représenter exactement les échéances postérieures à l’année 2106 ; les outils qui lisent cette colonne doivent prendre en charge le nouveau type. #110171 (alexey-milovidov). EXPLAIN SYNTAXrenvoie désormais la requête reformatée sous la forme d’un unique enregistrementString(contenant des sauts de ligne) au lieu d’un enregistrement par ligne : sa sortie est ainsi une ligne unique, directement exploitable (par exemple,SELECT count() FROM (EXPLAIN SYNTAX ...)renvoie1). Ce comportement est contrôlé par la nouvelle optionsingle_record, dont la valeur par défaut est1; définissezsingle_record = 0pour rétablir l’ancienne sortie à un enregistrement par ligne. Les autres types d’EXPLAIN(PLAN/PIPELINE/AST) conservent leur sortie arborescente ligne par ligne. #110479 (alexey-milovidov).- La fonction
hasColumnInTablen’accepte plus les arguments facultatifshostname,usernameetpasswordqui permettaient de vérifier une colonne sur un serveur distant arbitraire ; seule la formehasColumnInTable(database, table, column)subsiste. Le mode distant supprimé posait un problème de sécurité : il permettait à n’importe quel utilisateur de déclencher des connexions sortantes vers des hôtes arbitraires, exposait des identifiants dans les journaux de requêtes et n’était soumis à aucun privilège. #110881 (alexey-milovidov). - Les moteurs de base de données
PostgreSQLetMaterializedPostgreSQLrespectent désormais la configurationremote_url_allow_hostsdu serveur, à l’instar du moteur de tablePostgreSQL, de la fonction de tablepostgresqlet des dictionnaires créés par DDL. Cette politique s’applique lors d’unCREATE DATABASEet d’unATTACH DATABASEexécuté par un utilisateur : siremote_url_allow_hostsest configuré sur votre serveur, la création ou le rattachement d’une base de donnéesPostgreSQLouMaterializedPostgreSQLpointant vers un hôte absent de la liste autorisée est désormais rejeté avecUNACCEPTABLE_URL. Les bases de données existantes continuent d’être chargées au démarrage du serveur, si bien qu’une mise à niveau ne peut pas empêcher le serveur de démarrer. #111135 (alexey-milovidov). - Suppression du lecteur et du rédacteur reposant sur la bibliothèque Apache Arrow pour les formats
ArrowetArrowStream. L’implémentation native de ClickHouse, utilisée par défaut depuis la version 26.7, est désormais la seule disponible. Les paramètresinput_format_arrow_use_native_readeretoutput_format_arrow_use_native_writersont obsolètes : ils sont toujours acceptés mais n’ont aucun effet, si bien qu’une requête qui les définissait à0pour forcer l’implémentation Apache Arrow utilise désormais l’implémentation native. #111996 (alexey-milovidov). - Les identifiants TLS d’une source MySQL (
ssl_ca,ssl_cert,ssl_key) ne peuvent plus être spécifiés sous forme de chemins de fichiers depuis SQL — dans une collection nommée créée avecCREATE NAMED COLLECTION, comme argument de requête ou dans une requêteCREATE DICTIONARY— car le serveur ouvre ces fichiers avec ses propres privilèges. Les chemins restent pris en charge dans le fichier de configuration du serveur. Dans les autres cas, transmettez le contenu du certificat ou de la clé dans les nouveaux paramètresssl_ca_pem,ssl_cert_pemetssl_key_pem, qui sont masqués dans les journaux et dans les requêtesSHOW, au même titre que les mots de passe. #112070 (alexey-milovidov). disable_insertion_and_mutationempêche désormais la consommation en arrière-plan depuis les tablesKafka,RabbitMQetNATS, tout en autorisant les écritures directes vers le stockage externe. Les tablesKafka2,NATSetRabbitMQsoumises à cette restriction n’initialisent pas de consommateurs pour lesSELECTdirects. Le paramètremessage_queue_disable_insertion, introduit récemment, nécessite désormais un redémarrage du serveur. #113660 (cwurm).- Un
PARTITION BYouORDER BYde fenêtre sur une colonneAggregateFunctionest désormais rejeté avecILLEGAL_COLUMN, comme l’était déjà unORDER BYde premier niveau sur une telle colonne. Auparavant, une telle requête était acceptée par au moins un analyseur, et lePARTITION BYde fenêtre partitionnait différemment selon la valeur demax_threads. Ce refus s’applique également à un état imbriqué dansArray,Tuple,Map,VariantouSimpleAggregateFunction. UnSimpleAggregateFunctionsur un type ordinaire,QBit, ainsi queGROUP BYetDISTINCTsur un état, ne sont pas concernés. #113878 (groeneai). - Correction des contrôles d’accès pour les commandes
SYSTEM ... CACHE ON CLUSTER. Elles exigeaient le groupe de privilègesSYSTEM DROP CACHEau lieu du privilège propre à chaque commande, ce qui, d’une part, refusait l’accès aux détenteurs d’un seul privilège de cache granulaire et, d’autre part, permettait à un détenteur du groupe d’exécuterSYSTEM SYNC FILESYSTEM CACHE ON CLUSTERsans disposer deSYSTEM SYNC FILESYSTEM CACHE. #114042 (groeneai). - Le table engine
NATSaccepte désormais des identifiants intégrés via le nouveau paramètrenats_credentials(même charge utile qu’un fichier.creds) et n’accepte plusnats_credential_filedepuis SQL : ce path désigne un fichier situé sur le système de fichiers du serveur, que celui-ci ouvre avec ses propres privilèges. Il ne peut donc être spécifié que dans une collection nommée définie dans le fichier de configuration du serveur, ou vianats.credential_filedirectement dans la configuration du serveur. Une requête peut remplacer un tel path configuré par desnats_credentialsintégrés, sauf si l’administrateur l’a verrouillé avec<nats_credential_file overridable="false">. Les tables créées avant cette restriction continuent de fonctionner après une mise à niveau. #114644 (alexey-milovidov).
Modifications des types de données et des formats
- Rejet du format d’archive de sauvegarde
zip/zipxpour les sauvegardes stockées sur un stockage d’objet — destinations directesS3(...)/AzureBlobStorage(...)et destinationsDisk(...)reposant sur S3 ou Azure — pourBACKUPcomme pourRESTORE. Le format Zip impose des accès aléatoires (seek) pour lire son répertoire central, ce qui est très lent sur un stockage d’objet. Utilisez plutôt un format basé sur tar, tel quetar.gz. #101770 (Onyx2406). - Extension de la plage prise en charge par
DateTime64, qui passe de[1900-01-01, 2299-12-31]à[0000-01-01, 9999-12-31]. Les valeurs situées hors de l’ancienne plage sont désormais calculées correctement (via cctz) au lieu d’être ramenées à la borne. Avec une precision de 8 ou 9, la plage reste plus étroite, car les ticks sont stockés enInt64(avec une précision à la nanoseconde, le maximum reste2262-04-11). Rétrocompatibilité : si vous utilisiez auparavant des dates-heures hors plage en vous appuyant sur les règles de saturation très spécifiques de l’ancienne plage, sachez que les résultats changent désormais et sont plus exacts. #107907 (alexey-milovidov). - Un nombre JSON sans guillemets destiné à une colonne
DateTime64/DateTimedansJSONEachRowet les formats similaires est désormais interprété comme un Unix timestamp (secondes écoulées depuis l’epoch), avec une précision inférieure à la seconde facultative, de manière cohérente avec le formatValues,CASTettoDateTime64. Auparavant, un nombre comportant une partie fractionnaire (par ex.1703363853.035) était rejeté avec l’erreurCANNOT_PARSE_INPUT_ASSERTION_FAILED, et un integer seul (par ex.1703363853) était lu comme la valeur brute mise à l’échelle d’unDateTime64, ce qui produisait un timestamp en1970-.... Il s’agit d’un changement non rétrocompatible pour les integers sans guillemets fournis à des colonnesDateTime64; les strings entre guillemets et la sortie JSON de ClickHouse lui-même (toujours entre guillemets) ne sont pas concernées. #108091 (alexey-milovidov). - Le codec expérimental
ALPeffectue désormais enFloat64les calculs de mise à l’échelle deFloat32, ce qui élimine les exceptions sur les données décimales et améliore considérablement les taux de compression. #111627 (rienath). - Rejet des valeurs de paramètres de durée (millisecondes/secondes) qui dépassent la capacité d’un Int64 exprimé en microsecondes #112757 (azat).
- Les métriques asynchrones peuvent désormais être de type
Map, et les métriques par cœur de CPU et par périphérique ont été regroupées en métriques clé-valeur uniques :OSUserTimeCPU0,OSUserTimeCPU1, … sont devenues une seule métriqueOSUserTimeCPUdotée d’une map associant le numéro du cœur de CPU à la valeur (il en va de même pour les autres métriquesOS*TimeCPU*,CPUFrequencyMHz_*,Temperature*,EDAC*,Block*_*,Network(Receive|Send)*_*,Disk*_*,*BlobsQueueEstimateetAsyncLogging*QueueSize).system.asynchronous_metricsdispose d’une nouvelle colonnekey_values Map(LowCardinality(String), Float64)(la colonnevaluevautNaNpour ces métriques),system.asynchronous_metric_logles enregistre à raison d’une ligne par clé dans une nouvelle colonnekey, le Prometheus endpoint les exporte avec un label (par ex.ClickHouseAsyncMetrics_BlockReadBytes{device="sda"}), et leMetricsTransmitterde Graphite les envoie sous la forme<prefix>.<Metric>.<key>. Si votre supervision s’appuie sur les anciens noms de métriques, définissezasynchronous_metrics_key_values_modesurlegacy_namespour les conserver, ou surbothpendant la migration ; ce paramètre serveur peut être appliqué avecSYSTEM RELOAD CONFIG, sans redémarrage. #115333 (alexey-milovidov). #116791 (alexey-milovidov). - Les disques de stockage objet utilisent désormais par défaut les transactions natives du stockage des métadonnées, ce qui renforce la cohérence des mises à jour de leurs métadonnées. #89658 (Michicosun).
Modifications des paramètres et de la configuration
- Suppression des fonctions
snowflakeToDateTime,snowflakeToDateTime64,dateTimeToSnowflakeetdateTime64ToSnowflake, dépréciées de longue date. Elles avaient été dépréciées dès la v24.6 au profit desnowflakeIDToDateTime,snowflakeIDToDateTime64,dateTimeToSnowflakeIDetdateTime64ToSnowflakeID, qu’il convient d’utiliser à la place. Le paramètreallow_deprecated_snowflake_conversion_functions(qui permettait de les réactiver) est désormais obsolète et n’a plus aucun effet. #108711 (alexey-milovidov). - Extension de la plage prise en charge par
Date32, qui passe de[1900-01-01, 2299-12-31]à[0000-01-01, 9999-12-31], comme pourDateTime64. L’analyse et les conversions acceptent désormais la plage étendue au lieu de ramener silencieusement les valeurs aux anciennes bornes. Remarques sur la rétrocompatibilité : dans la conversion numériquetoDate32(N), les valeurs comprises dans[120530, 2932896]sont désormais interprétées comme des numéros de jour (dates de2300-01-01à9999-12-31) et non plus comme des timestamps Unix du début de l’année 1970, conformément à la règle selon laquelle tout nombre compris dans la plage des numéros de jour est traité comme un numéro de jour ; les nombres inférieurs au numéro de jour de0000-01-01et les timestamps postérieurs à9999-12-31sont ramenés aux nouvelles bornes. #111534 (alexey-milovidov).
Autres changements non rétrocompatibles
arrayIntersectetarraySymmetricDifferencene traitent plus une valeur répétée au sein d’un même argument comme si elle apparaissait dans plusieurs arguments. Les requêtes qui reposent sur l’ancien comportement peuvent désormais renvoyer des résultats différents :arrayIntersect([1], [2], [1, 1])renvoie[]au lieu de[1],arrayIntersect([1, 2], [2], [1, 1, 2])renvoie[2]au lieu de[1, 2], etarraySymmetricDifference([1], [2], [1, 1])renvoie[2, 1]au lieu de[2]. PourarraySymmetricDifference, deux arguments suffisent :arraySymmetricDifference([1], [2, 2])renvoie[2, 1]au lieu de[1]. Désormais, une valeur n’est comptabilisée pour un argument que si elle figurait dans chacun des arguments précédents ; le résultat contient ainsi exactement les valeurs présentes dans tous les arguments. Dans le cadre de cette même modification,arrayIntersectconstruit sa table de hachage à partir du plus petit argument plutôt qu’à partir de tous, ce qui le rend jusqu’à 1,85 fois plus rapide et réduit d’un tiers sa consommation mémoire lorsque les arguments sont de tailles très différentes.arrayUnionn’est pas concerné. #113021 (alexey-milovidov).- Le type de statistiques de colonne
minmaxest désormais déprécié. #108680 (hanfei1991). - Correction de la vérification d’accès pour
SYSTEM PREWARM PRIMARY INDEX CACHE ... ON CLUSTER, qui exigeait à tort le privilègeSYSTEM PREWARM MARK CACHEau lieu deSYSTEM PREWARM PRIMARY INDEX CACHE. #109198 (Algunenano). - Correction de
SYSTEM STOP/START CLEANUPet deSYSTEM STOP/START VIRTUAL PARTS UPDATE ON CLUSTER, qui exigeaientSYSTEM PULLING REPLICATION LOGau lieu deSYSTEM CLEANUP/SYSTEM VIRTUAL PARTS UPDATE. #110289 (groeneai). - Le glob
/(nombre quelconque de répertoires) correspond désormais aussi au répertoire lui-même. Auparavant,/n’était pas traité comme un cas particulier dans les motifs glob :data/**/file.txtne correspondait donc pas àdata/file.txt(zéro niveau de répertoire). #97676 (alexey-milovidov).
Nouvelles fonctionnalités
Fonctions et types de données
- Ajout des fonctions
parseQueryToJSONetformatQueryFromJSONpour sérialiser et désérialiser des AST au format JSON, ainsi que d’un dialecte expérimentalclickhouse_jsonactivé parenable_json_ast_dialect. #100412 (alexey-milovidov). #113480 (fm4v). - Ajout de la table système
system.stemmers, qui répertorie toutes les langues de racinisation disponibles pouvant être indiquées pour la fonctionstem. #100611 (Ergus). - Ajout de la prise en charge des opérateurs postfixés
AT TIME ZONEetAT LOCALdu SQL standard, en tant que sucre syntaxique pourtoTimeZone. L’expressionexpr AT TIME ZONE zoneest désormais équivalente àtoTimeZone(expr, zone), etexpr AT LOCALàtoTimeZone(expr, timeZone()). #106092 (lvzhipin03). - Le table engine
URLet la fonction de tableurlredirigent désormais vers le backend approprié en fonction du schéma de l’URL :file://est pris en charge par le moteurFile,s3:///gs:///gcs:///oss://parS3,az:///azure:///abfss:///abfs://parAzureBlobStorage,hdfs://parHDFS, ethttp(s)://par le moteurURL, comme auparavant. Le paramètreurl_baseest appliqué avant la redirection selon le schéma. Seuls les schémas S3 résolus par lesurl_scheme_mapperspar défaut sont redirigés ; les autres schémas de fournisseurs compatibles S3 (cos,obs, …) ne le sont pas et nécessitent d’utiliser directement le moteur ou la fonctions3. #106093 (alexey-milovidov). - Ajout de la fonction
dotProductTransposed(aliasscalarProductTransposed), qui calcule le produit scalaire approximatif entre une colonneQBitet un vecteur de référence, en complément des fonctions existantesL2DistanceTransposedetcosineDistanceTransposed. #108100 (alexey-milovidov). - Ajout d’un paramètre facultatif de pas (stride) au type de données
QBit(QBit(T, dimension, stride)), qui stocke des groupes de dimensions dans des flux distincts afin qu’une recherche vectorielle puisse lire efficacement les seules premières dimensions (par exemple pour les embeddings Matryoshka). Les fonctions de distance transposées acceptent un quatrième argument facultatif,used_dims, permettant de lire un nombre réduit de dimensions. #108103 (alexey-milovidov). - Ajout de la prise en charge du type d’élément
Int8dans le type de donnéesQBit, ce qui permet le stockage et la recherche vectorielle par distance transposée (L2DistanceTransposed,cosineDistanceTransposed) sur des vecteurs quantifiés d’entiers 8 bits. #108105 (alexey-milovidov). - Nouvelle fonction
randomHadamardTransform(vector[, seed[, output_dims]]): une transformée de Hadamard randomisée déterministe d’un vecteur de flottants — une rotation orthogonale qui préserve la norme, utile pour prétraiter des embeddings avant quantification et (lorsqu’elle est tronquée) comme projection aléatoire de type Johnson–Lindenstrauss / Hadamard randomisée sous-échantillonnée. #108227 (alexey-milovidov). - Implémentation de la fonction d’agrégation
mergedJSONPatchpour l’agrégation de type merge-patch (RFC 7396) sur des valeurs JSON, avec prise en charge de la fusion d’états et de l’utilisation avec AggregatingMergeTree. Il est possible d’agréger une colonne JSON en utilisant un horodatage ou une autre colonne d’ordonnancement comme clé de tri afin d’obtenir l’état le plus récent. #108349 (larryluogit). - Ajout de la fonction
xxHash64Spark, qui calcule des valeursxxHash64compatibles avec Spark pour les entréesStringetNULLen utilisant la graine42, et renvoie unInt64. #108436 (lalitium). - Ajout de la fonction
digits(n, offset[, length]), qui renvoie le nombre extrait dencommençant à l’indexoffset(1-indexed)et comportantlengthchiffres. Silengthn’est pas fourni, la fonction renvoie le nombre depuis la position de départ jusqu’à la fin. #109012 (1000ms). - Ajout de la fonction arithmétique
sqr, qui calcule le carré d’un nombre. #109061 (lalitium). - Ajout des fonctions de distance transposées quantifiées
cosineDistanceTransposedQuantized,L2DistanceTransposedQuantizedetdotProductTransposedQuantized, qui opèrent sur unQBit(Int8)de codes Lloyd-Max issus dequantizeBFloat16ToInt8, en déquantifiant à la volée les codes stockés. Un vecteur de référence à virgule flottante constitue la requête en pleine précision, comparée avec une précisionFloat32(une requêteFloat64est convertie à une précision inférieure) ; une référenceArray(Int8)est elle-même déquantifiée, ce qui donne une distance symétrique entre valeurs quantifiées. #109405 (alexey-milovidov). - Ajout d’une nouvelle fonction
dictGetRoot, qui renvoie l’ancêtre le plus élevé (la racine) d’une clé dans un dictionnaire hiérarchique. Elle offre un équivalent pratique àdictGetHierarchy(dict_name, key)[-1]. #109459 (alexey-milovidov). - Ajout de la fonction de table
mergeTreeCodecBlockCounts(database, table), qui indique, pour chaque triplet (partie de données, colonne, sous-flux) d’une tableMergeTree, le nombre de blocs compressés utilisant chaque codec. #109623 (rienath). - Ajout de la fonction
notHas, négation dehaspour les tableaux, les maps et le JSON. Lorsque l’ensemble de recherche est un tableau constant,notHas(constant_array, x)est réécrit enx NOT IN constant_arrayparoptimize_rewrite_has_to_in(activé par défaut) : la fonction s’exécute alors via une recherche dans un set et peut élaguer les données grâce à l’index de clé primaire, commeNOT IN. #109926 (nihalzp). - Ajout du type de données géographique
MultiPoint, stocké sous la formeArray(Point)et intégré au typeGeometry. #109951 (davidmenggx). - Les fonctions
arrayElement(l’opérateurvec[n]) etarraySliceprennent désormais en charge le type de donnéesQBit:qbit[n]renvoie le n-ième élément du vecteur en pleine précision, etarraySlice(qbit, offset, length)renvoie une projection sur un sous-ensemble de dimensions. Toutes deux ne lisent que les plans de bits des groupes de stride nécessaires, et les tranches alignées sur les limites des groupes de stride réutilisent les flux stockés sans copie. #109953 (Utkal059). - Ajout d’un tokenizer
splitByRegexppour les index de texte et la fonctiontokens. Il découpe l’entrée en jetons en utilisant une expression régulière comme séparateur, par exempletokenizer = splitByRegexp('[^\p{L}\p{N}#+]+'), ce qui permet de conserver intacts les jetons contenant des caractères spéciaux tels queC++ouC#, que d’autres tokenizers scinderaient. #110002 (Ergus). - Ajout des fonctions
geometryIntersectCartesianetgeometryIntersectSpherical, qui indiquent si deux géométries s’intersectent. Contrairement àpolygonsIntersectCartesian/polygonsIntersectSpherical, elles acceptent n’importe quel type de données géométrique (Point,LineString,MultiLineString,Ring,Polygon,MultiPolygon), y compris le type génériqueGeometry, et les deux arguments peuvent être de types différents. #110062 (alexey-milovidov). - Le lecteur ORC natif prend désormais en charge le type
uniontyped’ORC, qu’il fait correspondre au type ClickHouseVariant(auparavant, ces colonnes étaient rejetées avec l’erreurUnsupported ORC type). #110078 (alexey-milovidov). - Le format de sortie ORC natif peut désormais écrire le type ClickHouse
Variant, qu’il fait correspondre à ununiontypeORC (auparavant, l’écriture échouait avec l’erreurILLEGAL_COLUMN). #110085 (alexey-milovidov). - Ajout de formats de tramage, sélectionnés via le nouveau paramètre
framing_output_format: ils multiplexent les différentes parties de la réponse à une requête dans un même flux de réponse HTTP — blocs de données, totaux et extrêmes, paquets de progression, événements de profilage, journaux du serveur et exceptions. Formats de tramage implémentés :None(par défaut, le comportement reste inchangé),EventStream(HTTP server-sent events),JSONEachPacketBase64etJSONEachPacketString(un objet JSON par paquet, avec des données encodées en base64 ou sous forme de string). #110127 (alexey-milovidov). - Ajout de la fonction de table
bigqueryet du table engineBigQuerypour lire et écrire dans des tables Google BigQuery, y compris dans les jeux de données publics. La structure de la table est déduite du schéma de la table BigQuery. L’authentification prend en charge un jeton d’accès OAuth, une clé de compte de service au format JSON et un client OAuth avec jeton d’actualisation. #110166 (alexey-milovidov). - Nouvelle fonction
aiRedact, qui détecte et masque les informations personnelles identifiables (PII) dans un texte à l’aide d’un fournisseur de LLM. Indiquez les catégories à masquer (par ex.['email', 'name']) ou passez un tableau vide pour utiliser un ensemble de catégories de PII par défaut. Les valeurs détectées sont remplacées par un jeton ([REDACTED]par défaut). #110464 (davidmenggx). - Ajout de la fonction
aiFilter, qui évalue une condition exprimée en langage naturel sur un texte à l’aide d’un LLM et renvoie unUInt8utilisable dansWHERE,PREWHEREetJOIN ... ON. #110594 (ylw510). - Prise en charge des connexions TLS/SSL vers PostgreSQL pour le table engine
PostgreSQL, la fonction de tablepostgresql, les moteurs de base de donnéesPostgreSQLetMaterializedPostgreSQL, ainsi que les dictionnairesPostgreSQL:sslmode, plus les certificats et la clé, fournis soit sous forme de contenu littéral (sslrootcert_pem,sslcert_pem,sslkey_pem; masqués comme les mots de passe), soit sous forme de chemins (sslrootcert,sslcert,sslkey; acceptés uniquement depuis une collection nommée définie dans le fichier de configuration du serveur). #110615 (alexey-milovidov). - La fonction de table
postgresqlet le table enginePostgreSQLpermettent désormais de se connecter à un autre serveur ClickHouse via le protocole PostgreSQL (lorsqu’un nom de table est utilisé ; la variantequery(...)n’est pas encore prise en charge). Ajout des fonctions de compatibilité PostgreSQLformat_typeetcurrent_setting. #110760 (alexey-milovidov). - Nouvelle fonction
aiSimilarityqui calcule la similarité sémantique entre deux textes à l’aide d’un modèle d’embedding. Elle renvoie unNullable(Float32)compris dans[-1, 1], où1signifie que les textes sont identiques, ouNULLsi un opérande estNULL/vide ou si le calcul de son embedding a échoué. #110777 (davidmenggx). - Ajout des moteurs de base de données
RemoteetRemoteSecure, qui offrent un accès en temps réel aux tables d’une base de données située sur un serveur ClickHouse distant, en lui transmettant les requêtesSELECTetINSERT. Ils sont aux échanges entre serveurs ClickHouse ce que les moteurs de base de donnéesMySQLetPostgreSQLsont à ces systèmes. #110975 (alexey-milovidov). - Prise en charge des opérateurs pipe dans les requêtes SQL :
FROM t |> WHERE x > 1 |> AGGREGATE count() AS c GROUP BY y |> ORDER BY c DESC |> LIMIT 10, à l’image de la syntaxe pipe de GoogleSQL. Toute requêteSELECTpeut être suivie d’une chaîne d’opérateurs|>, chaque opérateur encapsulant la requête qui le précède dans une sous-requête ; l’AST obtenu est donc identique à celui de la requête équivalente écrite avec des sous-requêtes imbriquées. Dans une requête qui commence par la clauseFROM, la clauseSELECTest désormais facultative et vaut par défautSELECT *. #111151 (alexey-milovidov). - Ajout de la fonction d’agrégation
gini, qui calcule le coefficient de Gini de valeurs numériques finies et non négatives, y compris dans le cadre d’agrégations groupées et distribuées. #112280 (amirreza1307). #114643 (groeneai). - Prise en charge du PNG animé dans le format de sortie
PNG. Une colonnettransforme le résultat d’une requête en animation ; l’échelle de temps detest définie paroutput_format_image_time_multiplier_secondsetoutput_format_image_time_divisor_seconds, tandis queoutput_format_image_streaming_animationpermet d’écrire les images au fur et à mesure que la requête les produit, au lieu de les mettre en mémoire tampon. #112846 (alexey-milovidov). - Ajout d’une colonne
finish_timeàsystem.mutations, qui enregistre la date de fin d’une mutation. Pour les mutations non terminées et celles dont la date de fin est inconnue, cette colonne vaut zéro. #113474 (nikitamikhaylov). - Ajout d’un nouveau type de schéma
bucketedpoursystem.metric_log, qui stocke toutes les métriques dans une seule colonneMap(Enum16(...), Int64)à l’aide de la sérialisationMappar buckets (128 buckets), ainsi qu’une colonneALIASpar métrique pour assurer la compatibilité : la table ne comporte plus que quelques colonnes au lieu de plusieurs milliers, les valeurs nulles ne sont pas stockées, et la lecture d’une seule métrique ne lit qu’un seul des 128 buckets. En outre, uneMapavec des clésEnumpeut désormais être indexée par le nom (string) de la valeur de l’enum, par exemplemap['name']. #115380 (alexey-milovidov). - Ajout d’un tokenizer
chinesepour la fonctiontokenset les index de texteMergeTree. Il segmente le texte chinois en mots à l’aide d’un dictionnaire et d’un modèle de Markov caché (l’algorithme reprend celui de jieba), avec deux granularités :coarse_grained(par défaut) etfine_grained. #89945 (amosbird). - Ajout de la fonction d’agrégation
groupFormat, qui met en forme les lignes de chaque groupe selon un format de sortie donné et renvoie le résultat sous forme de string. #93201 (wandersofb). - Ajout du combinateur de fonction d’agrégation
-Tuple, qui applique indépendamment la fonction d’agrégation sous-jacente à chaque élément d’une colonneTupleet renvoie unTuplecontenant les résultats, en conservant les noms des éléments :sumTuple(t)pourt = (a, b)renvoie(sum(a), sum(b)). Les fonctions d’agrégation à plusieurs arguments prennent un tuple par argument, les éléments étant appariés selon leur position :corrTuple((a1, a2), (b1, b2))renvoie(corr(a1, b1), corr(a2, b2)). Contrairement à-ForEachappliqué aux tableaux, les éléments peuvent être de types différents, et le type de résultat ainsi que le nom de chaque élément sont conservés. #98190 (RinChanNOWWW).
Fonctionnalités SQL et de requêtes
- Ajout de la prise en charge des clauses WHERE dans les définitions de projections. Les projections avec WHERE ne matérialisent que les lignes correspondant au prédicat, et l’optimiseur peut les utiliser (selon une estimation des coûts) lorsque la clause WHERE de la requête implique celle de la projection. #102347 (SBALAVIGNESH123).
- Ajout d’un moyen d’accéder aux tables et aux bases de données via des chemins d’URL dans l’interface HTTP (par ex. `/database/table.format.gz?filter=a>0`), ainsi que de nouveaux paramètres (`http_allow_database_as_path`, `http_allow_table_as_file`, `http_allow_filters_as_path`, `http_allow_filters_as_unrecognized_url_parameters`, `select`, `order`, `sort`, `filter`, `page`, `compression`, `format`, `input_format`, `output_format`, `default_format`, `database`) qui se combinent entre eux et avec le paramètre d’URL `query` existant. #105249 (alexey-milovidov).
- Ajout des moteurs de table
RemoteetRemoteSecure, équivalents persistants des fonctions de tableremoteetremoteSecure.CREATE TABLE ... ENGINE = Remote('addresses', db, table, ...)fonctionne désormais en plus deCREATE TABLE ... AS remote(...). #106189 (alexey-milovidov). - Ajout de
EXPLAIN ANALYZEpour analyser les performances des requêtes : la requête est exécutée et les métriques d’exécution réelles sont présentées dans le format habituel du plan de requête. #106586 (Fgrtue). #110668 (Fgrtue). - Ajout des commandes
SYSTEM STOP,SYSTEM START,SYSTEM PAUSE,SYSTEM CANCELetSYSTEM REFRESH, indépendantes du moteur, ainsi que de leurs variantes... ALL BACKGROUNDà l’échelle du serveur, pour contrôler l’activité en arrière-plan des tablesKafka,RabbitMQ,NATS,S3Queue/AzureQueueet des vues matérialisées actualisables via une interface unifiée. Pour les vues matérialisées actualisables, elles servent d’alias aux commandesSYSTEM ... VIEWexistantes. Dans le cadre de la prise en charge de ces contrôles pour NATS, les tables JetStream n’acquittent désormais les messages qu’après une insertion réussie (sémantique « au moins une fois » ; auparavant, les messages étaient acquittés automatiquement à la livraison et pouvaient être perdus en cas d’échec de l’insertion). Un nouveau paramètrenats_wait_for_flush_interval(falsepar défaut, ce qui conserve le comportement précédent à faible latence) permet de maintenir un cycle de consommation ouvert pendant tout l’intervalle de vidage, au lieu de procéder au vidage dès que la file d’attente est vide. Un nouveau paramètrenats_commit_on_selectfait en sorte qu’unSELECTdirect sur une table JetStream consomme (acquitte) les messages qu’il lit. #107476 (NIKTONIKTO717). - Les fonctions de table et moteurs de table
mysql,postgresqletsqliteacceptent désormais une requête utilisateur (au lieu d’un nom de table) et la transmettent telle quelle à la base de données externe, sous forme de sous-requête(SELECT ...)ou sous la formequery('SELECT ...'). La structure de la table obtenue est déduite du résultat de la requête, et une telle table est en lecture seule. #107740 (alexey-milovidov). - Introduction du moteur de table
QueryRunner. Les enregistrements insérés dans une tableQueryRunnerreprésentent des requêtes que le moteur exécute. Ce moteur peut servir à l’exécution asynchrone de requêtes, à l’exécution par lots de requêtes générées, à l’acheminement de requêtes vers des clusters distants, aux benchmarks, au fuzzing et aux tests avec du trafic fantôme. #107888 (mstetsyuk). - Prise en charge du mode de cadre
GROUPSpour les fonctions de fenêtre (SQL:2011), par exempleany(price) OVER (PARTITION BY symbol ORDER BY ts GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING). Dans un cadreGROUPS, les bornes se comptent en groupes de pairs entiers (ensembles de lignes ayant la même valeur pour la cléORDER BY) :N PRECEDING/N FOLLOWINGdésignent doncNgroupes de pairs avant/après le groupe de pairs de la ligne en cours, et non des lignes physiques (ROWS) ou des écarts de valeursORDER BY(RANGE). #108653 (nihalzp). - Une instruction
CREATE MATERIALIZED VIEW ... POPULATEsimple est désormais atomique en local : l’abonnement de la vue aux nouvelles insertions dans la table source et le snapshot des données existantes sont effectués ensemble sous un bref verrou exclusif sur la source, de sorte que les lignes insérées via le même serveur pendant le remplissage ne sont plus ni perdues ni dupliquées (nouveau paramètrematerialized_views_populate_atomically, activé par défaut). Cette garantie ne couvre que le chemin d’insertion local (les insertions arrivant sur une autre réplique ou via un chemin d’écriture distribué en sont exclues) et elle nécessite une source capable de fournir un snapshot figé (familleMergeTreeetMemory) ; les autres sources, ainsi queCREATE OR REPLACE/REPLACEet les vues créées dans des bases de donnéesReplicated, conservent l’ancien remplissage non atomique.POPULATEpeut désormais aussi être combiné avecTOpour remplir rétroactivement la table cible. #108715 (alexey-milovidov). ALTER USER,ALTER ROLEetALTER SETTINGS PROFILEacceptent désormaisSET name = valuecomme alias deMODIFY SETTING name = value. Cette syntaxe modifie des paramètres individuels sur place sans toucher aux autres, contrairement à la clauseSETTINGSseule, qui remplace l’intégralité de la liste des paramètres. Le risque d’effacer accidentellement les autres paramètres d’un utilisateur s’en trouve réduit. #108722 (groeneai).- Prise en charge de
ALTER TABLE ... MODIFY CONSTRAINT [IF EXISTS] name CHECK exprpour modifier sur place l’expression d’une contrainte existante. #108768 (alexey-milovidov). - Ajout de l’algorithme IEJoin, fondé sur le tri, pour les jointures dont la section
ONcomporte deux comparaisons d’inégalité (<,<=,>,>=) entre les tables jointes ; il s’active en ajoutantie_joinau paramètrejoin_algorithm. Les types pris en charge sontALL INNER/LEFT/RIGHT/FULL JOINetSEMI/ANTILEFT/RIGHT JOIN. Auparavant, ces requêtes étaient exécutées sous forme deCROSS JOINavec un filtre (INNERuniquement), ce qui est nettement plus lent sur de grandes tables. #109920 (vdimir). - Ajout d’une nouvelle table système,
system.user_query_log, qui permet à chaque utilisateur de consulter ses propres enregistrements du journal de requêtes sans avoir besoin d’accéder à la table du journal de requêtes. L’implémentation d’origine et l’idée reviennent à Yue Ni (@niyue). #110156 (alexey-milovidov). - Nouveau paramètre
run_query_in_background. Le serveur accepte la requête, renvoie immédiatement un résultat vide et l’exécute jusqu’au bout, quoi qu’il advienne de la connexion. Le résultat est ignoré. Suivez la requête grâce à sonquery_iddanssystem.processesetsystem.query_log. Destiné aux requêtes longues telles queINSERT ... SELECT,CREATE TABLE … AS SELECTouCREATE MATERIALIZED VIEW … POPULATE, qui ne doivent pas être interrompues par la perte de la connexion. #112816 (mstetsyuk). - Prise en charge de ALTER TABLE … MODIFY PROJECTION pour modifier les paramètres propres à une projection existante (par exemple index_granularity) sans avoir à la reconstruire. Les nouveaux paramètres s’appliquent de manière différée, au fil des fusions. #113343 (diegomestre2).
- Le catalogue du moteur S3 Tables pour les lacs de données prend désormais en charge
INSERT, en plus de l’interrogation des tables existantes. #113505 (scanhex12). - Le catalogue
Icebergprend désormais en charge Snowflake Horizon Catalog viacatalog_type = 'horizon', ce qui permet de lire et d’écrire des tablesIceberggérées par Snowflake. #114547 (melvynator). - Ajout du paramètre
skip_unavailable_shards_mode(également disponible en tant que paramètre du moteurDistributed), qui permet de choisir quelles exceptions provenant d’une partition (shard) distante sont ignorées silencieusement lorsqueskip_unavailable_shardsest activé. Il offre ainsi un contrôle plus fin du comportement des requêtes dans les environnements distribués. #79091 (byte-sourcerer).
Stockage, lacs de données et stockage d’objet
- Ajout de la prise en charge du format de fichier Puffin (https://iceberg.apache.org/puffin-spec/). Ce format peut désormais être utilisé dans les fonctions de table telles que
file,url,s3, etc. #103936 (scanhex12). - Ajout d’un mode de stockage de parties de données « packed » pour les tables
MergeTree, qui regroupe l’ensemble des fichiers d’une partie de données dans une archive unique (data.packed) au lieu d’un fichier par flux. Ce mode est contrôlé par les paramètresmin_bytes_for_full_part_storage,min_rows_for_full_part_storageetmin_level_for_full_part_storage, et il est désactivé par défaut. Remarque sur la compatibilité : dès qu’une table écrit des parties de données packed, les versions antérieures du serveur ne peuvent plus les lire ; l’activation de ce format empêche donc tout retour à une version antérieure du serveur. #108118 (Algunenano). - Ajout du paramètre
nats_credentialsau table engine NATS, qui permet aux utilisateurs de spécifier directement les identifiants NATS sous forme de string (correspondant à la charge utile d’un fichier.creds). #110733 (addshore).
Formats de données et ingestion
- Ajout du format de sortie
HiveText, qui écrit les données au format texteLazySimpleSerDed’Apache Hive. Les champs sont séparés par\x01, les lignes par le délimiteur défini dans le nouveau paramètreformat_hive_text_rows_delimiter(\npar défaut), et les valeurs imbriquées de typeArray,MapetTupleutilisent la liste de séparateurs de Hive. Ce format de sortie cible leLazySimpleSerDepar défaut de Hive et n’est pas symétrique avec le format d’entréeHiveTextde ClickHouse en ce qui concerne les valeurs imbriquées ou les délimiteurs de lignes personnalisés. #107582 (alexey-milovidov). - Ajout du format de sortie
GeoJSON, qui permet d’écrire des documents GeoJSONFeatureCollectionà raison d’une entité par ligne. Le nouveau paramètreformat_geojson_validate_geometry(activé par défaut) valide les formes GeoJSON en lecture comme en écriture ; le format d’entréeGeoJSONinfère désormaisidcommeNullable(String), ce qui permet de distinguer les identifiants absents ounulldes strings vides. #108065 (nihalzp).
Paramètres, accès et observability
- Ajout d’une page intégrée de recherche dans la documentation, accessible via le path
/docsde l’interface HTTP, qui permet une recherche instantanée dans la tablesystem.documentationet affiche la documentation de référence (avec coloration syntaxique, formules mathématiques et liens croisés). #108345 (alexey-milovidov). - Ajout d’un tokenizer japonais pour les index de texte et les fonctions tokens/hasAnyTokens/hasAllTokens, reposant sur l’analyseur morphologique MeCab. Le dictionnaire est chargé à l’exécution depuis un emplacement défini dans la configuration du serveur, puis vérifié au moyen d’une somme de contrôle SHA-256 avant utilisation. #111420 (Ergus).
- Ajout d’un nouveau paramètre du cache du système de fichiers,
system_cache_extensions, qui détermine les fichiers stockés dans le cache système lorsqueuse_split_cacheest activé. #111575 (kirillgarbar). - Ajout du paramètre
always_fetch_mutated_part, qui permet à une réplique de télécharger les parties de données mutées depuis d’autres répliques au lieu d’exécuter les mutations localement. #113020 (rorylshanks).
Autres nouvelles fonctionnalités
- Ajout de la prise en charge de
WITH TIESpour les valeurs négatives deLIMIT. #100930 (nihalzp). - Ajout des paramètres de restauration
restore_table_data,restore_access_entitiesetrestore_functions, qui permettent de contrôler finement ce qui est restauré. Ils peuvent remplacerstructure_onlycatégorie par catégorie — par exemple,structure_only=true, restore_access_entities=truerestaure les définitions de tables et les entités d’accès, sans les données des tables. #102402 (fm4v). - Le chargement différé peut désormais être configuré dictionnaire par dictionnaire à l’aide de
dictionary_lazy_loaddans la définition du dictionnaire, ce qui prévaut sur le paramètre serveur globaldictionaries_lazy_load. Certains dictionnaires peuvent ainsi être chargés de manière différée, tandis que d’autres sont chargés immédiatement. #108314 (mstetsyuk). - L’opérateur d’indice de tableau accepte désormais un tableau d’entiers comme index :
arr[indexes]renvoie les éléments situés à chacune des positions indiquées, ce qui équivaut àarrayMap(i -> arr[i], indexes). #108371 (ucasfl). - Ajout des fonctions
geoToUTM,UTMToGeo,geoToMGRSetMGRSToGeopour convertir des coordonnées géographiques WGS84 vers les systèmes de coordonnées UTM et MGRS, et inversement. #108939 (alexey-milovidov). - Ajout des commandes
SYSTEM UNLOAD DICTIONARYetSYSTEM UNLOAD DICTIONARIESpour libérer la mémoire occupée par les dictionnaires sans supprimer leur définition. Les dictionnaires seront rechargés de manière différée lors du prochain accès. #109639 (Manerone). - Ajout d’un nouveau tokenizer
icupour les index de texte et les fonctionstokens,hasAnyTokensethasAllTokens, qui offre une segmentation Unicode en mots adaptée à la locale (y compris une segmentation à base de dictionnaire pour des langues comme le chinois, le japonais et le thaï). #109940 (Ergus). - Ajout d’un nouveau codec
ZXC— un codec LZ asymétrique à compression lente et décompression très rapide, dont le taux de compression se situe entre ceux deLZ4et deZSTD. #110620 (alexey-milovidov). - Ajout du paramètre
s3_base, qui permet de résoudre les URL relatives des fonctions de tables3,s3Cluster,gcsetossainsi que du table engineS3par rapport à une URL de base S3. Ajout du moteur de base de donnéesURL, qui résout les noms de tables en tant qu’URL par rapport à une base facultative et les transmet au backend approprié. #111512 (alexey-milovidov). - Prise en charge de l’expansion des caractères génériques pour
url()et le moteurURL, par énumération des pages d’index HTTP (listes de répertoires au format HTML ou texte brut) et extraction des URL correspondantes. Les caractères génériques sont appliqués au composant de chemin de l’URL, avec des limites sur la taille des pages d’index et sur le nombre de répertoires parcourus. #95181 (niyue). - Ajout de
AWS_MSK_IAMcomme valeur prise en charge pourkafka_sasl_mechanism, ce qui permet à ClickHouse de s’authentifier auprès d’Amazon MSK à l’aide de rôles IAM, sans avoir à gérer d’identifiants SASL/SCRAM. #96100 (kalavt). - Ajout d’un postprocesseur à l’index de texte, qui transforme les jetons après la tokenisation. #98939 (Ergus).
Fonctionnalités expérimentales
Planification et exécution des requêtes
- Ajout de “drivers” pour les fonctions exécutables définies par l’utilisateur. Un driver déclaré dans
<user_defined_executable_function_drivers_config>peut être utilisé dansCREATE FUNCTION name ARGUMENTS (...) RETURNS T ENGINE = DriverName(...) AS '...code...'pour compiler ou traiter d’une autre manière un extrait de code utilisateur lors de la création de la fonction, et produire une UDF exécutable prête à l’emploi. La configuration obtenue est stockée dans<dynamic_user_defined_executable_functions_path>, et la requête d’origine est conservée sous la formeATTACH FUNCTIONafin que la fonction persiste après un redémarrage du serveur. Un driver de démonstration,c_function_body, compile et exécute des corps de fonctions C dans des conteneurs Docker isolés en modeexecutable_pool. #105131 (alexey-milovidov). - Les requêtes adressées à la Prometheus Query API sur
/api/v1/queryet/api/v1/query_rangesont désormais enregistrées danssystem.query_logavec les métriquesread_rowsetread_bytes. #106611 (JTCunning). - Prise en charge des lectures via un plan de requête distribué pour
SELECT ... FINALsur les tables de la famille MergeTree lorsquemake_distributed_planest activé. #108148 (davenger). - Ajout d’une exécution expérimentale des répliques parallèles basée sur le plan pour les requêtes MergeTree. #108504 (devcrafter).
- Ajout d’une fonction de table expérimentale
eval, qui évalue une expression constante sous forme de chaîne de requête, puis exécute l’unique requêteSELECTobtenue. Cette fonctionnalité est désactivée par défaut et peut être activée via le paramètreallow_experimental_eval_table_function. Auteur : Yue Ni #110132 (alexey-milovidov). - Répliques parallèles basées sur le plan (
parallel_replicas_plan_based) : la frontière entre exécution locale et distante est désormais déterminée par une optimisation au niveau du plan, appliquée à un plan de requête standard, et les requêtes sur des vues contenant unUNIONsont parallélisées sansparallel_replicas_allow_view_over_mergetree. Les requêtes utilisantIN (subquery)basculent désormais vers un plan local au lieu d’échouer. #111063 (devcrafter). #112443 (devcrafter). - Renforcement de la sécurité des fonctions d’IA expérimentales : refus par défaut des endpoints non sécurisés (
http) vers des hôtes distants (nouveau paramètreai_function_allow_insecure_endpoint), plafonnement par défaut du nombre d’appels d’API sortants par requête (ai_function_max_api_calls_per_queryvaut désormais1000par défaut) et assainissement des réponses d’erreur des fournisseurs écrites dans les journaux. #111286 (george-larionov). - Les répliques parallèles basées sur le plan (
parallel_replicas_plan_based) distribuent désormais les JOIN éligibles (INNER,LEFT,RIGHT, y comprisSEMI/ANTI) : la jointure est exécutée dans son intégralité au sein d’un fragment de plan distribué, l’un des côtés étant coordonné entre les répliques et l’autre diffusé. #112268 (devcrafter). - Signalement de l’erreur ayant provoqué l’annulation d’une requête distribuée (
make_distributed_plan = 1) au lieu d’un simpleQUERY_WAS_CANCELLED. Auparavant, l’erreur réelle d’une task de worker en échec n’apparaissait que dans le journal du serveur. #112590 (davenger). - Prise en charge de l’exécution distribuée des plans de requête contenant
IN (subquery)sans réécriture enJOIN. Le set est construit une seule fois sur l’initiateur et ses valeurs sont transmises avec les tasks des workers. Le forçage derewrite_in_to_joinest supprimé ; la réécriture reste disponible via un paramètre explicite. #113826 (davenger). - Une requête à plan distribué (
make_distributed_plan) arrête désormais ses étapes en amont dès qu’une clauseLIMITest satisfaite, au lieu de calculer le résultat complet pour ensuite l’écarter. #114806 (davenger). - Correction de l’erreur
Illegal type Decimal(18, 0) of argument of function toIntervalNanosecondlorsqu’une requête PromQL utiliseoffsetdans un sélecteur de plage, par exemplerate(m[2m] offset 5m). #114997 (nikitamikhaylov). - Prise en charge de l’agrégation
GROUPING SETSdans les plans distribués construits par l’optimiseur de requêtes Cascades (make_distributed_plan = 1, enable_cascades_optimizer = 1). #115426 (davenger). - Les tables
TimeSeriespeuvent désormais conserver une table d’« échantillons récents » : lorsque le nouveau paramètre de moteurrecent_samples_ttl_secondsest non nul, le moteur crée une copie de la table samples soumise à un TTL (partitionnée selonrecent_samples_partition_by, par jour par défaut) et alimentée à chaque insertion ; les requêtes PromQL dont l’intervalle de temps s’inscrit dans la fenêtre TTL lisent alors automatiquement cette copie, ce qui accélère considérablement (de plusieurs fois) les règles d’alerte et d’enregistrement ainsi que les tableaux de bord sur de courtes plages, sur les tables volumineuses. Ce comportement peut être désactivé à l’aide du nouveau paramètre de niveau requêtetime_series_prefer_recent_samples_table. #115441 (nikitamikhaylov). - Les plans de requête distribués (
make_distributed_plan) arrêtent désormais sans délai les étapes en amont inactives une fois une clauseLIMITsatisfaite : un récepteur d’échange inactif litNoMoreDataNeededdès sa réception, et une source d’échange inactive détecte la fermeture de sa sortie et propage l’arrêt en amont. Auparavant, ces étapes continuaient à lire et à calculer des données qui n’étaient consommées par personne. #115690 (davenger). - Le mode automatique des répliques parallèles peut désormais collecter des statistiques d’exécution et activer les répliques parallèles pour les requêtes prises en charge lorsque
parallel_replicas_plan_basedest activé. #115788 (devcrafter). - Ajout de Cascades, un optimiseur de requêtes expérimental basé sur les coûts pour les plans de requête distribués, activé via
enable_cascades_optimizer = 1combiné àmake_distributed_plan = 1. En fonction du coût estimé, il choisit entre les stratégies de jointure par shuffle, broadcast, répliquée et locale, l’agrégation en deux phases, par shuffle et locale, le top-N distribué en deux étapes, ainsi que les lectures parallèles et répliquées, en insérant des opérateurs d’échange si nécessaire. #86353 (davenger).
Stockage, lacs de données et index
- Ajout d’un cache SLRU en mémoire pour les fichiers de métadonnées Paimon désérialisés (listes de manifestes et manifestes). Lorsque ce cache est activé via le paramètre
use_paimon_metadata_files_cache, les requêtes répétées sur une même table Paimon n’ont plus besoin de retélécharger ni de réanalyser les métadonnées depuis le stockage d’objet. #104657 (Binnn-MX). - Le
ReaderExecutorexpérimental (use_reader_executor, désactivé par défaut) peut désormais maintenir ouverte une connexion à une source distante et la réutiliser d’une lecture séquentielle à l’autre, ce qui réduit le nombre de requêtes adressées au stockage d’objet lors des parcours. #107735 (CheSema). - Ajout d’un cache du système de fichiers en lecture directe (read-through) dans le chemin de lecture du
ReaderExecutorexpérimental (use_reader_executor, désactivé par défaut). #110029 (CheSema). - Ajout d’un paramètre
MergeTreeexpérimental,allow_experimental_adaptive_codec_selection. Lorsqu’il est activé, les fusions et les mutations sélectionnent, bloc par bloc, le codec produisant la sortie la plus compacte pour les colonnes qui utilisent le codec par défaut. #111834 (rienath). - Ajout d’un niveau de cache de pages en espace utilisateur dans le chemin de lecture du
ReaderExecutorexpérimental (use_reader_executor, désactivé par défaut). En cas d’échec de cache (miss), l’executor alimente désormais le cache de pages en espace utilisateur, puis sert les lectures suivantes directement depuis celui-ci, sans copie (zero-copy). #114890 (CheSema). - La compaction des fichiers manifestes
Icebergest désormais disponible viaOPTIMIZE TABLE ... MANIFEST, afin de réduire le nombre de fichiers de métadonnées. Elle est conditionnée par le paramètreallow_experimental_iceberg_compaction. #98178 (SmitaRKulkarni).
Fonctions, formats et IA
- Expérimental : exécution de
SELECT count(*) FROM t WHERE col <op> default(col)à partir des statistiques de parcimonie par colonne stockées dansserialization.json, sans aucun parcours des données, lorsque le prédicat partitionne exactement la colonne en valeurs par défaut et valeurs non par défaut. #105890 (Algunenano). - Ajout de la famille expérimentale de codecs vectoriels
Quantize(...)ainsi que d’une réécriture facultative (opt-in) de la recherche vectorielle approximative en deux étapes sur des flux compagnons quantifiés. #108565 (shankar-iyer). - Réintroduction du codec expérimental
SZ3de compression avec perte à erreur bornée pour les colonnesFloat32/Float64(et les tableaux de ces types). Il nécessiteallow_experimental_codecs. #108788 (alexey-milovidov). - Correction de la lecture des données compressées avec le codec expérimental
SZ3('ALGO_LORENZO_REG', ...), qui échouait auparavant avecCORRUPTED_DATA, et élimination d’un comportement indéfini lors de la compression de valeurs à virgule flottante non finies (NaNet infinis) avec le codec expérimentalSZ3. #110762 (alexey-milovidov). - PromQL : les fonctions de date/heure (
hour(),minute(),month(),year(),day_of_week(),day_of_month(),day_of_year(),days_in_month()) peuvent désormais être appelées sans arguments ; elles utilisent alorsvector(time())par défaut, comme dans Prometheus. #111869 (valerypetrov). - PromQL : correction des opérations sur les vecteurs instantanés sans tags, par exemple
vector(1) + vector(2),topk(1, vector(1)),label_replace(vector(1), ...)et les opérateurs binaires avecon(), qui échouaient avec une erreur de type. #111872 (valerypetrov). - PromQL : implémentation de la fonction
deriv, avec correction d’un bug qui faisait renvoyer à la fonction d’agrégation sous-jacente des valeurs 1000 fois trop petites avec des timestamps à la milliseconde. #112360 (valerypetrov). - Application de l’optimisation de lecture dans l’ordre aux requêtes
ORDER BYlorsqueparallel_replicas_plan_basedest activé : le tri est désormais transmis aux répliques puis fusionné sur l’initiateur, de sorte que chaque réplique lit les données dans l’ordre de la clé de tri. Corrige également l’erreurUnknown function __topKFilterpourORDER BYsur une colonne ne faisant pas partie de la clé primaire lorsque ce paramètre est activé. #114315 (devcrafter). - Correction des lectures de recherche vectorielle après le rechargement d’une part (par exemple après
ATTACHou un redémarrage du serveur) : les parts ne perdent plus leurs sous-colonnes de codecQuantized, de sorte que les recherches lisent les sous-colonnes quantifiées au lieu de se rabattre sur la colonne en pleine précision. #114763 (shankar-iyer). - Le table engine expérimental
TimeSeriesn’applique plus le codecGorillaaux colonnesvaluecréées automatiquement dans la table interne des échantillons ; elles utilisent désormaisCODEC(ZSTD(1))par défaut. Les colonnes déclarées explicitement conservent les codecs définis par l’utilisateur. La valeur par défaut de la colonnetimestampreste inchangée (CODEC(DoubleDelta, ZSTD(1))). #112110 (nikitamikhaylov). #114790 (nikitamikhaylov). - Prise en charge de
ROLLUP,CUBE,GROUPING SETSet de la fonctiongroupingdans les requêtes exécutées avecmake_distributed_plan = 1. #114950 (davenger). - Ajout d’une variante Real Doubles (RD) et d’un argument facultatif
ALP(AUTO|STD|RD)au codec expérimental ALP. Utilisé sans argument, ALP choisit désormais automatiquement entre le schéma STD existant et RD, au lieu d’utiliser systématiquement STD. #99654 (nazarii-piontko).
Autres fonctionnalités expérimentales
- Ajout d’une affinité statique entre partitions et shards pour StorageKafka2 via les paramètres kafka_partition_shard_num et kafka_shard_count, permettant à plusieurs shards ClickHouse de consommer de manière déterministe des sous-ensembles disjoints de partitions Kafka. #108886 (JingYanchao).
- Vous pouvez désormais vous authentifier auprès de OneLake à l’aide d’un jeton bearer obtenu au préalable, via le paramètre
onelake_bearer_token, au lieu deonelake_client_idetonelake_client_secret. Cela évite de partager un secret client à longue durée de vie. Le jeton n’étant pas renouvelé, la base de données doit être recréée à son expiration. #109104 (asya-ch). - Correction de
data_uncompressed_bytespour les index de saut regroupés dansskp_idx.packed(viapacked_skip_index_max_bytes) : la taille non compressée indiquée correspondait en réalité à la taille compressée, ce qui pouvait également empêcher l’activation dedistributed_index_analysis. #109272 (Algunenano). - Ajout de la prise en charge de la compression Zstandard dans le gestionnaire HTTP expérimental Prometheus remote-write v1. #110907 (JTCunning).
- PromQL : implémentation des fonctions
clamp,clamp_min,clamp_maxetround. #111870 (valerypetrov). - PromQL :
quantileavec un niveau de quantile en dehors de [0, 1] renvoie désormais -Inf/+Inf/NaN, comme Prometheus, au lieu de lever une erreur, ethistogram_quantileignore désormais, comme Prometheus, les séries d’entrée dont le labelleest absent ou non analysable. #111871 (valerypetrov). - PromQL : implémentation des fonctions
changes()etresets(). #112352 (valerypetrov). - Les statistiques d’insertion et les requêtes passant par l’endpoint Prometheus remote-write sont désormais correctement collectées. #112825 (JTCunning).
- PromQL : les valeurs finies sont désormais préservées lors d’un modulo avec un diviseur infini. #113746 (fallintoplace).
- Rejet des sauts de ligne littéraux dans les strings PromQL ordinaires entre guillemets. #114381 (fallintoplace).
- Une valeur très élevée de
distributed_plan_workers_numne provoque plus l’arrêt brutal du serveur avec unestd::length_errorlorsque les paramètres expérimentauxmake_distributed_planetenable_cascades_optimizersont activés. Un tel nombre de nœuds est désormais rejeté avecINVALID_SETTING_VALUE. #115398 (groeneai). - Implémentation de l’endpoint
/api/v1/seriesde la Prometheus HTTP API pour les tablesTimeSeries: sélecteurs de sériesmatch[](les valeurs répétées sont combinées par union), intervalle de tempsstart/endfacultatif et paramètrelimitfacultatif. #115676 (nikitamikhaylov).
Améliorations des performances
Performances des jointures et des agrégations
- Activation du cache des conditions de requête pour les requêtes passant par le filtrage dynamique TopK (
ORDER BY ... LIMIT n). L’entrée du QCC est partitionnée selon les paramètres du plan TopK : une même requête réutilise ainsi les résultats mis en cache des filtres WHERE, tandis qu’une valeur différente deLIMIT, de colonne de tri ou de sens de tri produit une nouvelle entrée. #104478 (alexey-milovidov). - Propagation de LIMIT dans l’agrégation dans l’ordre (aggregation-in-order) afin de permettre un arrêt anticipé lorsque la clé GROUP BY correspond à la clé ORDER BY et à la clé de tri de la table, ce qui réduit considérablement le nombre de lignes lues. #104859 (thevar1able).
- Activation par défaut de
allow_aggregate_partitions_independently. Lorsqu’une cléGROUP BYest compatible avec la clé de partition, ClickHouse peut agréger chaque partition indépendamment et se passer de l’étape de fusion globale. Des heuristiques d’exécution désactivent automatiquement l’optimisation lorsque l’organisation des partitions la rendrait défavorable (trop peu de partitions, trop de partitions ou tailles de partitions fortement déséquilibrées). #105128 (alexey-milovidov). - Activation par défaut de
read_in_order_use_virtual_row. Lors d’une lecture dans l’ordre de la clé primaire (par ex.ORDER BY primary_key LIMIT n) sur une table comportant de nombreux parts, seuls les parts susceptibles de contribuer réellement au résultat sont lus (plus une fenêtre de lecture anticipée d’au plusmax_threadsparts, qui maintient la lecture en parallèle), ce qui réduit considérablement le pic de consommation mémoire. #106215 (alexey-milovidov). - Réduction de l’utilisation mémoire et amélioration des performances des
JOIN. Le côté droit d’une jointure par hachage utilise désormais une référence de ligne compacte de 8 octets basée sur un index, de sorte que les entrées de la table de hachage des jointuresALLsont aussi petites que celles des jointuresANY, quel que soit le type de clé. Lors de bancs d’essai sur de grandes requêtes de jointureparallel_hash— jointuresINNERetANYde tables de 100 à 300 millions de lignes sur des clésUInt64etString, avec des clés uniques comme dupliquées —, la requête médiane s’est révélée environ 12 % plus rapide, avec un pic de mémoire réduit d’environ 15 %, sans qu’aucune requête ne ralentisse. Ce sont les jointuresINNERsur des clésUInt64qui en ont le plus bénéficié (médiane environ 21 % plus rapide, avec 38 % de mémoire en moins). #107189 (harikrishnan94). - Ajout de l’algorithme d’énumération de l’ordre des jointures dpsub, qui fournit des plans de jointure optimaux avec un surcoût d’optimisation inférieur à celui de dpsize et prend en charge les jointures autres qu’internes. #107351 (fkastrati).
- Les agrégations à un niveau peu gourmandes en mémoire ne sont plus converties en agrégations à deux niveaux : un memory tracker dédié est désormais rattaché à l’état d’agrégation, au lieu de s’appuyer sur la mémoire de l’ensemble de la requête. #107490 (m-selmi).
- L’AST complet de la requête n’est plus construit lors de l’analyse des requêtes d’agrégation : la clé du cache des statistiques de taille de la table de hachage d’agrégation est désormais calculée à partir du plan de requête plutôt que de l’AST. #107643 (novikd).
- Possibilité de basculer d’une jointure
hashlors de la première exécution d’une requête versparallel_hashlors des exécutions suivantes, en fonction des statistiques d’exécution collectées lors de la première exécution. #108125 (m-selmi). - Utilisation de la taille de la table de hachage issue des statistiques d’exécution des jointures pour optimiser la taille des runtime filters de jointure lors des exécutions ultérieures de la requête. Ce comportement est contrôlé par le nouveau paramètre
join_runtime_filter_size_from_hash_table_stats. #108313 (m-selmi). - Accélération et réduction de l’utilisation mémoire des requêtes
DISTINCTsur les tablesMergeTreepartitionnées, en conservant les lignes de chaque partition dans un seul flux : ainsi, leDISTINCTpréliminaire de chaque flux porte sur un ensemble disjoint de clés, au lieu que les mêmes clés apparaissent dans plusieursDISTINCTpréliminaires. Cette optimisation s’applique lorsque l’expression de partitionnement est une fonction déterministe des colonnes duDISTINCT, et elle est soumise à une heuristique de coût portant sur le nombre de partitions et leur déséquilibre (qu’il est possible de forcer à l’aide du paramètreforce_distinct_partitions_independently, désactivé par défaut). Cette même disjonction par partition est propagée à travers les étapesExpression,FilteretARRAY JOINjusqu’aux consommateurs finauxDISTINCT,LIMIT BYetGROUP BY, afin qu’ils puissent eux aussi faire l’économie de leur fusion. Ce comportement est contrôlé par les nouveaux paramètresallow_distinct_partitions_independently(activé par défaut) etmax_number_of_partitions_for_independent_distinct, ce dernier permettant d’ajuster l’heuristique. #108326 (nihalzp). - Les filtres d’exécution sont désormais construits sur les clés d’égalité, même lorsque la clause
ONcontient également des prédicats de non-égalité, ce qui réduit le nombre de lignes entrant dans la jointure par hachage pour les jointures mixtes (égalité et non-égalité).LEFT ANTI JOINn’est pas concerné. #108579 (29antonioac). - Abaissement du seuil de prélecture logicielle pour les tables de hachage d’agrégation et de jointure, de
4 * L2 cache sizeàL2 cache size, de sorte que la prélecture est activée dès que la table de hachage ne tient plus dans le cache L2. Cela corrige une régression sur les opérationsGROUP BYetJOINportant sur des tables de hachage de taille moyenne (~1-8 MiB) sur les plateformes dont le cache L2 signalé est important (par exemple aarch64 avec un L2 de 2 MiB). #108655 (groeneai). - Amélioration des performances des fonctions de fenêtre. Les requêtes de fenêtre sur des tables larges incluant
SELECT *consomment désormais nettement moins de mémoire et s’exécutent plus rapidement. Les agrégats de fenêtre, notammentquantile*,uniq*etgroupArray, sont plus rapides avecOVER ()etOVER (ORDER BY ... RANGE ...). La fonctioncume_distest également plus rapide, et les fenêtres utilisantPARTITION BYouORDER BYsont désormais plus performantes sur les colonnes comportant de nombreuses valeurs répétées. #108688 (nihalzp). - Les requêtes d’agrégation sans fonctions d’agrégation utilisent désormais des méthodes basées sur
HashSetau lieu deHashMap(pour les types de clés pris en charge). Des accélérations allant jusqu’à 1,8x ont été observées. #108862 (nickitat). - Réduction de la surcharge liée à la contention de verrous dans l’algorithme de jointure
parallel_hash. #108938 (m-selmi). - Ajout d’une nouvelle valeur
parallel_full_sorting_mergepourjoin_algorithm: pour les jointures d’égalité compatibles avec le hachage, elle découpe une jointure full sorting merge join, selon le hachage des clés de jointure, en jointures par fusion indépendantes par fragment, exécutées sur tous les threads. Elle conserve la faible consommation mémoire, en flux continu, d’une jointure par fusion tout en la parallélisant (lors d’un benchmark, environ 2,4x plus rapide et environ 3,3x moins gourmande en mémoire queparallel_hash). Les jointuresASOFse rabattent sur un uniquefull_sorting_merge; pour les types de clés incompatibles avec le hachage (virgule flottante,JSON,Object,Dynamic), seule la réécriture par dispersion de hachage est omise, et ils peuvent toujours être fragmentés à la source par plages de clé primaire lorsquequery_plan_join_shard_by_pk_rangesest activé. Le résultat n’est pas ordonné. #109005 (alexey-milovidov). - Les statistiques de colonnes sont désormais matérialisées par défaut lors de l’
INSERTlorsque la taille active actuelle de la table, augmentée de la taille du bloc écrit, ne dépasse pas la valeur du nouveau paramètrematerialize_statistics_on_insert_max_table_size(25 GiB par défaut) ; la vérification s’effectuant bloc par bloc, un premier chargement massif dans une table vide peut tout de même matérialiser les statistiques pour chaque bloc écrit. L’optimiseur de jointures basé sur les coûts dispose ainsi d’estimations précises pour les tables de dimensions fraîchement chargées, ce qui évite des ordres de jointure pathologiques (par exemple, les requêtes TPC-H Q5 et Q8 n’expirent plus avec un facteur d’échelle de 40), tandis que les grandes tables de faits déjà établies continuent de matérialiser leurs statistiques lors des fusions. #109454 (alexey-milovidov). - Optimisation de la fonction d’agrégation
uniqCombineddans le cas d’une agrégation sans clé. #109794 (CurtizJ). - Optimisation des fonctions d’agrégation
uniqHLL12etuniqCombined. #109831 (CurtizJ). - Parallélisation du traitement des lignes non jointes dans l’algorithme de jointure
parallel_hashdans deux cas supplémentaires : en présence d’un filtre résiduel et avec de petites clés de jointure (table de hachage à un seul niveau). #110008 (m-selmi). - Un filtre est désormais poussé sous une fonction de fenêtre lorsque le prédicat ne référence que les colonnes
PARTITION BYde la fenêtre. Un tel prédicat écrit après la fenêtre (unWHEREexterne englobant une sous-requête fenêtrée, ou une conjonction dansQUALIFY) atteint désormais le stockage et permet l’élagage par clé primaire / par partition, ainsi que l’utilisation des index de saut et des projections. Par exemple,SELECT ... row_number() OVER (PARTITION BY key ORDER BY ts) AS rn ... QUALIFY rn = 1 AND key = 'x'ne lit plus ni ne fenêtre l’intégralité de la table. #110114 (groeneai). - Avec
join_use_nulls = 1, unWHERErejetant les valeurs NULL et référençant des colonnes des deux côtés d’une jointure externe (par ex.WHERE l.k = 42 AND r.k = 42) convertit désormais la jointure enINNER(ouLEFT/RIGHT) et élague la clé primaire, comme avecjoin_use_nulls = 0. Auparavant, la conversion n’avait pas lieu dans ce cas et les deux tables étaient lues intégralement. #110121 (groeneai). - Optimisation des fonctions
uniq,uniqExactetuniqHLL12dans le cas d’une agrégation sans clé. #110150 (CurtizJ). - Un
JOINdont la conditionONest constamment fausse (par ex.ON 1 = 2,ON NULL, ou une condition qui se réduit à faux commea.t = 'A' AND a.t = 'B') ne lit plus le côté qui ne contribue pas au résultat. Une nouvelle optimisation du plan de requête remplace par une source vide les entrées qui ne peuvent produire aucune ligne. Contrôlée par le paramètrequery_plan_short_circuit_constant_false_join(activé par défaut). #110234 (groeneai). - Parallélisation de la fusion finale des tables de hachage d’agrégation à un seul niveau : l’espace des clés est divisé en partitions de hachage disjointes que les threads fusionnent indépendamment (paramètre
enable_parallel_single_level_merge, activé par défaut). Accélère les requêtesGROUP BYdont les tables de hachage par thread restent sous le seuil de passage à deux niveaux, mais dont la fusion représentait l’essentiel du temps d’exécution. #110395 (nihalzp). - Les clés d’agrégation composées d’un seul
Stringutilisent désormais une représentation de table de hachage plus compacte, ce qui améliore les charges de travailGROUP BYfortement axées sur les chaînes de caractères. Le nouveau paramètreenable_packed_string_keys_in_aggregationest activé par défaut ; le désactiver, ou définircompatibilitysur une valeur inférieure à26.8, rétablit l’ancien cheminStringHashTable, qui peut être plus rapide pour des clés à très faible cardinalité de plus de 11 octets. #110573 (harikrishnan94). #112089 (harikrishnan94). - Amélioration des performances de la full sorting merge join, jusqu’à 1,5 à 3 fois plus rapide dans les scénarios de données clairsemées. #111200 (vdimir).
- Activation de
join_runtime_filter_from_fixed_hash_tablelorsque les types de clé de jointure côté sonde et côté construction diffèrent (par exemple, une clé de sonde Nullable avec une clé de construction non Nullable). #111244 (m-selmi). - Amélioration des performances des jointures
RIGHTetFULLavec l’algorithmeparallel_hashlorsque le côté droit contient des clés de jointureNULLou des lignes filtrées par l’expressionON, grâce à la suppression de la reconstruction des null maps. #111258 (m-selmi). - Nouvel algorithme adaptatif pour le
GROUP BYparallèle (contrôlé par le paramètreenable_adaptive_aggregator, activé par défaut) : chaque thread agrège dans sa propre table de hachage jusqu’à ce qu’elle contienneadaptive_aggregator_freeze_thresholdclés, puis la fige. Ainsi, les clés fréquentes continuent de mettre à jour les petites tables résidant en cache sans aucune coordination, tandis que les clés rares sont acheminées selon leur hachage vers des files d’attente par bucket et agrégées une seule fois, lors de la fusion parallèle par bucket. #111459 (nihalzp). - Accélération du hachage ligne par ligne des valeurs de colonnes JSON/
Objectstockées dans les données partagées (utilisé par exemple paruniq/uniqExactsur une colonne JSON et par les clés hachées deGROUP BY/DISTINCT), grâce à la suppression de la reconstruction d’unColumnDynamicpour chaque valeur. Les valeurs de hachage restent inchangées. #111501 (valerypetrov). - Amélioration des performances des hash JOIN RIGHT et FULL comportant plusieurs disjonctions
ORdans la section ON, ainsi que des RIGHT/FULL JOIN avec des conditions résiduelles (d’inégalité). #111590 (m-selmi). - La lecture ordonnée à travers une JOIN fonctionne désormais aussi lorsqu’un seuil de déversement automatique sur disque est configuré pour une jointure de hachage (comportement par défaut depuis la version 26.5). Lorsque cette optimisation s’applique, la jointure reste en mémoire afin de préserver l’ordre du côté gauche ; définissez
query_plan_read_in_order_through_spilling_join = 0pour rétablir le comportement précédent, dans lequel ces jointures ne sont pas utilisées pour la lecture ordonnée et peuvent librement déverser sur disque. Par ailleurs, unORDER BY ... LIMITsur uneLEFT JOINlue dans l’ordre n’annonce plus la table entière comme nombre de lignes à lire ; il ne déclenche donc plusmax_rows_to_readavecread_overflow_mode = 'throw'pour une lecture qui s’arrête prématurément. #111973 (alexey-milovidov). - Réactivation de l’optimisation des clés consécutives pour l’agrégation
TTL ... GROUP BYlors des fusions. L’agrégateur était construit en passantmin_chunk_bytes_for_parallel_parsing(un seuil en octets, 10 MiB par défaut) à la place demin_hit_rate_to_use_consecutive_keys_optimization(un taux de réussite dans[0, 1], 0,5 par défaut), si bien que l’optimisation était systématiquement désactivée sur ce chemin. Les résultats ne sont pas affectés. #112314 (groeneai). - La réplication différée des colonnes pour
ARRAY JOINn’est plus perdue lorsqu’un plan de requête est sérialisé. Avecserialize_query_plan = 1, le nœud exécutant un fragment de plan distant ignoraitenable_lazy_columns_replicationet matérialisait systématiquement chaque copie répliquée, alors même que ce paramètre est activé par défaut. #112330 (groeneai). - Une égalité dans la clause
WHEREest désormais fusionnée dans la condition deJOINlorsque ses opérandes ont des types différents mais un supertype commun, commeInt32etNullable(Int32). Une jointure CROSS peut ainsi être convertie en jointure INNER. #112630 (m-selmi). - Correction d’une réallocation quadratique lors de la réplication d’un
Arraydont les éléments contiennent des valeursJSONstockées dans les données partagées, par exemple unArray(JSON)constant passé à une fonction d’agrégation. Ces requêtes copiaient un nombre d’octets qui croissait de manière quadratique avec le nombre de lignes. #112897 (groeneai). - Rétablissement de l’élagage des parties de données et des granules lorsque les limites d’un prédicat de plage portant sur une clé primaire ou une clé de partition MergeTree sont fournies via une clause
JOIN ONavec un côté constant d’une seule ligne, par exempleSELECT count() FROM t JOIN bounds ON t.d >= bounds.lo AND t.d <= bounds.hi. Depuis la version 25.2, une telle requête lisait toutes les parties de données, et le paramètrequery_plan_use_logical_join_step, qui permettait de rétablir l’élagage, est devenu obsolète dans la version 26.5, si bien qu’il n’existait plus aucun moyen de le récupérer. #112957 (groeneai). - Correction de la complexité cubique de la planification des requêtes pour une jointure avec une table
Mergeportant sur de nombreuses tables de structures différentes. Ces requêtes pouvaient auparavant passer plusieurs minutes en planification sans réagir àmax_execution_timeni àKILL QUERY. #113140 (alexey-milovidov). - Correction d’une régression de performance : une agrégation sans clés
GROUP BYsérialisait, à chaque exécution, l’intégralité du sous-arbre de son plan d’entrée, y compris le contenu complet des littéraux issus du pliage de constantes, afin de calculer une clé de cache de taille de table de hachage qu’elle ne peut de toute façon jamais utiliser. Une requête telle queSELECT quantileMerge(arrayJoin(arrayMap(x -> state, range(5000000))))passait environ 63 ms par exécution dans l’optimisation du plan de requête, contre 0,15 ms désormais. #113333 (groeneai). - Les opérateurs d’agrégation PromQL
topk,bottomketlimitksont désormais évalués avec un plan en flux dont l’état de sélection est enO(time_steps * k), au lieu de rassembler toutes les séries dans une seule ligne avec une mémoire intermédiaire enO(time_steps * series^2). Les requêtes portant sur des métriques à forte cardinalité qui échouaient auparavant avecMEMORY_LIMIT_EXCEEDEDs’exécutent désormais avec une mémoire bornée, et l’évaluation est parallélisée au lieu d’être monothread. #113656 (nikitamikhaylov). - Remplacement de la table de hachage par bucket des fonctions d’agrégation
timeSeries*ToGridpar un tableau plat et trié d’échantillons : l’ingestion d’un échantillon devient un simple ajout en O(1) pour les entrées ordonnées (de loin le cas le plus courant), et la copie suivie du tri par bucket lors de la finalisation disparaît. #113681 (nikitamikhaylov). - Les sous-expressions PromQL partagées par plusieurs étapes du plan (l’opérande de
topk/bottomk/limitk, le côté gauche deor) sont désormais évaluées une seule fois au lieu de deux : le SQL généré à partir de PromQL matérialise maintenant les sous-requêtes partagées. Cela supprime un parcours redondant de la table samples ;topkappliqué àratedevient environ deux fois plus rapide à froid, et les requêtes de règles kubernetes-mixin gagnent de 10 à 29 %. #113772 (nikitamikhaylov). - Le cache des conditions de requête est désormais activé par défaut pour les requêtes qui utilisent l’optimisation
ORDER BY <column> LIMIT n(TopK). Définissezuse_query_condition_cache_for_top_k = 0pour le désactiver. #111492 #114539 (alexey-milovidov). - Parallélisation de la conversion des états d’agrégation par thread du format à un niveau vers le format à deux niveaux avant la fusion. Cela corrige une régression d’un facteur 2 à 3 des requêtes
GROUP BYcourtes comportant des états d’agrégation volumineux (par exempleCOUNT(DISTINCT ...), ClickBench Q10/Q11) sur des machines dotées d’un très grand nombre de cœurs. Cette régression avait été introduite dans les builds de développement de la version 26.7, lorsque la comptabilisation de la mémoire d’agrégation avait été rendue précise. #114691 (alexey-milovidov). - Accélération des fonctions de fenêtre sur les tables
MergeTreepartitionnées : chaque partition est lue via son propre flux et les fenêtres sont évaluées pour chaque partition, ce qui évite la redistribution par hachage qui, d’ordinaire, répartit chaque ligne entre les threads avant le tri de la fenêtre. Cette optimisation s’applique lorsque l’expression de partition de la table est une fonction déterministe des colonnesPARTITION BYde la fenêtre, et elle est soumise à la même heuristique de coût queGROUP BY/DISTINCTpour chaque partition (suffisamment de partitions par rapport àmax_threads, aucune partition dominante). Elle est contrôlée par les nouveaux paramètresallow_window_partitions_independently(activé par défaut),force_window_partitions_independentlyetmax_number_of_partitions_for_independent_window. #114783 (nihalzp). - Accélération des fonctions d’agrégation
timeSeries*ToGrid: le calcul du bucket pour chaque échantillon évite désormais la division Int128, et les échantillons consécutifs appartenant au même bucket ne déclenchent plus de recherche dans la table de hachage. #114889 (nikitamikhaylov). - Les échantillons des fonctions d’agrégation
timeSeries*ToGridsont désormais traités par séquences d’échantillons consécutifs tombant dans un même bucket de la grille, ce qui accélère d’un facteur 1,2 à 2 l’étape d’ingestion des échantillons detimeSeriesRateToGridet des fonctions associées sur des données de séries temporelles triées. #115041 (nikitamikhaylov). - Une agrégation sans clés
GROUP BYne répartit plus sa sortie d’une seule ligne surmax_threadsflux : les requêtes dont le plan se poursuit après une telle agrégation bénéficient ainsi d’un pipeline nettement plus léger (moins de processeurs à créer, planifier et profiler), sans aucune perte de parallélisme. #115170 (nikitamikhaylov). - Évaluation plus rapide des requêtes instantanées PromQL : les fonctions d’agrégation
timeSeries*ToGridutilisent le chemin vectorisé de classification des échantillons pour les grilles à point unique, ettimeSeriesIdToGroupremplit directement sa colonne de résultat. #115267 (nikitamikhaylov). - Un
JOINdont la sectionONcontient plusieurs égalités combinées parORne matérialise plus les colonnes de clé du côté droit que la requête ne sélectionne pas. #115465 (nickitat). - Accélération de la construction de la table de hachage d’une jointure
ANY,SEMIouANTIlorsque le côté droit répète de nombreuses fois les mêmes clés de jointure : la jointure ne relit plus le paramètrejoin_any_take_last_rowen mémoire pour chaque ligne du côté droit. #115820 (nickitat). - Accélération de
GROUP BYsans fonctions d’agrégation sur des clésString,FixedStringetLowCardinality: la requête ne réécrit plus une valeur de substitution inutilisée dans la table de hachage pour chaque ligne, mais uniquement pour les lignes qui ajoutent une nouvelle clé. #115834 (nickitat). - Réduction de l’utilisation de la mémoire et du temps d’optimisation du plan de requête pour les agrégations avec clé portant sur de grands littéraux issus du constant folding. La clé de cache des statistiques de table de hachage d’agrégation est désormais hachée au fil de sa sérialisation, au lieu d’être d’abord accumulée en mémoire ; un plan contenant un grand littéral n’en conserve donc plus de copie pendant l’optimisation. Pour un littéral de 80 Mo, le pic de mémoire diminue d’environ 250 Mo et le temps d’optimisation est divisé par environ 2,5. La clé calculée reste inchangée. #115847 (groeneai).
- Optimisation des requêtes
GROUP BY ... ORDER BY ... LIMITetGROUP BY ... LIMITgrâce à un tas borné maintenu pendant l’agrégation, qui permet d’élaguer les groupes ne pouvant pas figurer dans le résultat. L’utilisation de la mémoire et le temps d’exécution sont ainsi considérablement réduits pour les regroupements à forte cardinalité. Contrôlé par le paramètreenable_group_by_top_k_optimization. Basé sur l’implémentation initiale de Dmitriy Terenichev #96630 (thevar1able).
Optimisation et exécution des requêtes
- La lecture ordonnée avec les répliques parallèles utilise désormais la même logique de découpage de la table en
max_threadsparties que la lecture locale, pour un meilleur parallélisme. #101434 (nickitat). - Ajout de l’élagage spatial GeoParquet au niveau des row groups et des pages dans le lecteur Parquet. L’élagage au niveau des row groups ignore les row groups entiers dont la boîte englobante ne chevauche pas la géométrie de la requête. L’élagage au niveau des pages utilise l’index de colonne
covering.bboxpour ignorer les pages non pertinentes au sein des row groups. Généralise également la propagation des prédicats spatiaux viaIFunctionBase::isSpatialPredicate()et ajoute unGeoFilterqui évalue les prédicats spatiaux lors de la lecture des lignes Parquet. #104435 (bacek). - Ajout du paramètre
use_constant_folding_in_index_analysis(désactivé par défaut). Lorsqu’il est activé, l’analyse de la clé primaireMergeTree, des indexMinMaxet des index de saut intègre les constantes de niveau partition dans le prédicat de filtrage, séparément pour chaque partie de données, ce qui améliore l’élagage pour les filtres dont les branches dépendent des valeurs de partition, par exemple(a = 1 AND b >= 1) OR (a = 2 AND b > 10)avecPARTITION BY a. #104582 (Michicosun). - Application d’un positionnement exact des lignes pour les requêtes de recherche vectorielle avec
vector_search_with_rescoring, avant le calcul exact des distances dans le pipeline de requête. #105591 (skuznetsov). - Ajout d’une optimisation du plan de requête qui fait descendre les fonctions réduisant le volume de données (
length,lengthUTF8,empty,notEmpty) sous les étapesSortingetFilter, en remplaçant l’argument volumineux de typeString/FixedStringpar le résultat de taille fixe, qui n’a ainsi plus besoin d’être mis en mémoire tampon lors d’un tri ni copié par un filtre. Contrôlée par le nouveau paramètrequery_plan_push_down_volume_reducing_functions, activé par défaut. #106199 (fastio). - Accélération du chargement du cache du système de fichiers au démarrage grâce à l’encodage de la taille de chaque fichier de cache dans son nom (
<offset>_<size>), ce qui évite un appelstatpar fichier. Le chargement des fichiers de cache écrits par des versions antérieures reste pris en charge. #107415 (alexey-milovidov). - Amélioration des performances des requêtes de recherche textuelle combinées à un filtre sur la clé primaire. #108114 (CurtizJ).
- Amélioration des performances de la fonction
pointInPolygonavec un polygone constant. Le cache des polygones prétraités utilise désormais comme clé les arguments constants bruts : un polygone constant n’est donc analysé qu’une seule fois (en cas d’échec de cache) au lieu d’être réanalysé pour chaque bloc d’entrée. #108184 (groeneai). - Les compteurs de sélectivité de
system.predicate_statistics_logne sont plus maintenus sur le chemin de lecture MergeTree lorsque la fonctionnalité est désactivée (predicate_statistics_sample_rate = 0, valeur par défaut). Cela supprime de chaque lecture une mise à jour atomique par granule ainsi qu’un comptage de bitsO(rows)sur le filtre, corrigeant une régression de performances particulièrement visible sur aarch64. #108190 (groeneai). - Ajout du paramètre
merge_use_batch_sorting_queueMergeTree, qui permet d’utiliser facultativement la file d’attente de tri par batch pour les fusionsMergeTreeordinaires, réduisant ainsi le temps CPU et le temps d’exécution réel des charges de fusion pour lesquelles la fusion triée représente un coût important. #108468 (rorylshanks). - Accélération de la planification des requêtes avec l’analyseur pour les expressions qui référencent le même alias
WITHou répètent de nombreuses fois la même sous-expression (par exemple des chaînesif/multiIfprofondément imbriquées), en évitant de reconstruire les sous-expressions partagées lors de la construction du DAG d’actions. #108523 (novikd). - Accélération de l’analyse de requêtes pour les requêtes comportant de nombreuses chaînes
ANDde comparaisons, ou des chaînes très longues : l’optimisationoptimize_and_compare_chainest désormais limitée par un budget de travail (nouveau paramètreoptimize_and_compare_chain_max_hash_work) au lieu de calculer le hachage d’une grande partie de l’arbre de requête, et la résolution des lambdas ne recalcule plus les hachages du corps des lambdas pour sa protection contre la récursion. #108757 (alexey-milovidov). - Les postprocesseurs servant uniquement au filtrage (
if(..., '', token)) construisent désormais le granule à partir des jetons bruts et éliminent les valeurs vides dès la construction, ce qui évite la materialization par occurrence et l’exécution d’ActionsDAGpropres au chemin général. #109049 (ahmadov). - Suppression d’un goulot d’étranglement monothread dans
ShuffleSendStepdu plan de requête distribuée : chaque flux amont répartit désormais ses lignes par compartiment de destination de manière indépendante, au lieu de faire transiter l’ensemble du fragment par un uniqueScatterByPartitionTransform. #109206 (davenger). - Réduction de la surcharge CPU liée à l’évaluation des expressions pour les requêtes comportant un grand nombre de colonnes (par exemple, une recherche vectorielle sur une colonne
QBitavec un petit pas, où chaque vecteur se décompose en centaines de sous-colonnes de plans de bits, toutes transmises à un unique appel*DistanceTransposed). #109380 (alexey-milovidov). - Descente d’un filtre sous
LIMIT BYlorsque le prédicat ne référence que les colonnes clés deLIMIT BYet que la clause conserve au moins une ligne par groupe non vide (LIMIT n BYavecn >= 1etOFFSET 0). Ces prédicats (écrits sous la forme d’unWHEREexterne englobant une sous-requêteLIMIT BY) peuvent ainsi atteindre le stockage et bénéficier de l’élagage par clé primaire, des index de saut et des projections, au lieu de lire toute la table et d’appliquer d’abord le top-N par groupe, sans modifier la sémantique des exceptions pourOFFSET,LIMIT 0 BYou les formesLIMIT BYnégatives. #110116 (groeneai). - Suppression d’une allocation sur le tas à chaque vérification d’hyperrectangle lors de l’analyse d’index de clé primaire, ce qui accélère le filtrage des marques de 5 à 26 % selon la forme de la requête. #110153 (raimannma).
- La propagation des filtres Parquet (élagage des groupes de lignes et index de colonnes) prend désormais en charge les conversions entre variantes de
DateTime64, entre variantes deDecimal, ainsi qu’entreFloat32etFloat64. #110457 (al13n321). - Optimisation de la construction des index de saut de type texte et filtre de Bloom avec le tokenizer sparseGrams #110541 (UnamedRus).
- Prise en compte combinée du coût d’E/S et de la sélectivité dans l’ordonnancement des conditions PREWHERE. Cela corrige une régression de performance de l’exécution de PREWHERE survenant dans certains cas, introduite par https://github.com/ClickHouse/ClickHouse/pull/101275. Fait partie de https://github.com/ClickHouse/ClickHouse/issues/110462 #110695 (Avogar).
- Réduction du hachage des jetons définis dans le filtre
IN/NOT INdu postprocesseur. #111690 (ahmadov). - Les fonctions mapContainsKeyLike, mapContainsValueLike, mapExtractKeyLike et mapExtractValueLike utilisées avec un motif non constant consomment moins de mémoire et de temps lorsque enable_lazy_columns_replication est activé. Le motif n’est plus copié de manière anticipée pour chaque entrée de la map au moment de la capture : la copie est différée jusqu’à l’exécution de la lambda interne et libérée plus tôt, si bien que le pic de consommation compte une copie développée du motif en moins. #111749 (diegomestre2).
- Activation par défaut (et passage en bêta) de deux fonctionnalités sur disque : 1)
packed_skip_index_max_bytes = '1M': les sous-flux d’index de saut d’au plus 1 MiB sont désormais écrits dans une seule archiveskp_idx.packedpar part, ce qui réduit le nombre d’objets et de requêtes d’écriture sur le stockage d’objet. Compatibilité : seules les parts nouvellement écrites sont concernées, et elles restent entièrement lisibles par les versions plus anciennes ; les versions antérieures à 26.6 n’utilisent tout simplement pas les index packed pour l’élagage (ils sont considérés comme non matérialisés). Définissezpacked_skip_index_max_bytes = 0pour conserver la disposition autonome, avec un fichier par index. 2)compute_exact_num_defaults_for_sparse_columnscombiné àoptimize_trivial_count_with_sparsity_filter: des compteursnum_defaultsexacts par colonne sont persistés et utilisés pour répondre àSELECT count() FROM t WHERE <pred>sans parcourir les données lorsque le prédicat sépare les lignes entre valeurs par défaut et valeurs non par défaut. Compatibilité : l’indicateurexact_num_defaultsdansserialization.jsonest ignoré par les versions plus anciennes, si bien que les parts restent entièrement lisibles après une rétrogradation ; la réécriture du comptage ne s’applique qu’aux parts qui contiennent des compteurs exacts, ce qui garantit des résultats corrects sur les tables comportant des parts hétérogènes. #111816 (Algunenano). - Lorsqu’elle ne peut pas appliquer le filtre complet, l’optimisation des conditions transitives n’utilise désormais son filtre supplémentaire que pour l’analyse d’index. Voir le paramètre
optimize_and_compare_chain. #112076 (yariks5s). - L’API de requête Prometheus (
/api/v1/query,/api/v1/query_range) du moteur expérimental TimeSeries exécute désormais les requêtes en parallèle plutôt que sur un seul thread. #112108 (nikitamikhaylov). randomHadamardTransformappliqué à un vecteur constant est désormais évalué une seule fois au lieu d’une fois par ligne. Cela accélère les requêtes de recherche vectorielle qui font pivoter le vecteur de requête avecrandomHadamardTransformavant de le comparer à une colonneQBit. #112921 (alexey-milovidov).- Rétablit le partage des sets entre les tâches par part d’une même mutation filtrant avec
IN (subquery)sur une colonne de clé primaire.enable_sharing_sets_for_mutationsest activé par défaut, mais le set construit pour l’analyse de la clé primaire ne participait plus au cache partagé, si bien qu’une table comportant N parts matérialisait le même set N fois. #112941 (groeneai). - Dans les plans de requête distribuée (
make_distributed_plan),ORDER BY ... LIMIT kutilise désormais la matérialisation paresseuse sur chaque réplique : les colonnes larges ne sont lues que pour les k premières lignes locales de cette réplique, et non pour chaque ligne candidate. #113111 (shankar-iyer). - Accélération de la planification des requêtes lorsque les statistiques de colonne
uniq_v2sont utilisées. Le nombre estimé de valeurs distinctes est désormais mis en cache au lieu d’être recalculé à chaque appel, alors que la planification en émet de nombreux par requête. #113357 (groeneai). - Le pushdown de filtre fonctionne désormais pour les sous-colonnes
Tupledans les fichiers Parquet et ORC. Un prédicat tel queWHERE tup.1 = 555555surfile(),s3()ouurl()élague désormais les groupes de lignes et les intervalles d’index de lignes à l’aide des statistiques propres à l’élément du tuple, au lieu de lire le fichier entier. #113383 (groeneai). - Amélioration des performances des requêtes PromQL sur le moteur TimeSeries : le SQL interne des sélecteurs lit désormais directement les colonnes de clé primaire de la table des échantillons (sans conversions superflues) et vérifie la plage d’horodatage avant le set d’identifiants de séries, ce qui accélère de 30 à 44 % les requêtes à froid faisant un usage intensif des sélecteurs. #113768 (nikitamikhaylov).
- Les sélecteurs PromQL qui correspondent à toutes les séries d’une métrique filtrent désormais la table des échantillons d’une table
TimeSeriesà l’aide d’une plage continue de clé primaire suridlors de l’analyse de l’index, au lieu d’une volumineuse conditionid IN <set>, lorsque la structure de l’id est un tuple à deux composantes avec le générateur d’id canonique. Cela élimine le coût prépondérant de l’analyse d’index monothread dans les requêtes PromQL riches en sélecteurs : jusqu’à −45 % de latence à froid sur les formes de requêtes de tableaux de bord et de règles, et −11 % de moyenne géométrique à froid sur l’ensemble de la suite, sur une table de 62 milliards d’échantillons. #114131 (nikitamikhaylov). - Les points de terminaison
/api/v1/queryet/api/v1/query_rangede la Prometheus HTTP API évaluent désormais une seule fois une sous-requête PromQL partagée par plusieurs étapes du plan, comme le faisaient déjà les fonctions de tableprometheusQueryetprometheusQueryRange. Auparavant, une requête effectuée avecenable_analyzer = 0, ou par un utilisateur dont le profil définit ce paramètre, relisait la sous-requête partagée une fois pour chaque étape qui y faisait référence. #114261 (groeneai). - Correction d’une régression introduite dans la version 26.7 : pour une table
MergeTreetriée partoUnixTimestamp(ou une autre conversion en entier) d’une colonneDateTime64, un simple filtre de plage sur cette colonne n’utilisait plus la clé primaire et lisait tous les granules des parties de données correspondantes. En outre, un filtre tel quetoInt64(ts) >= csur une table triée par la colonneDateTime64brute utilise désormais la clé primaire. #114413 (alexey-milovidov). - Accélération de l’exécution de
INsur des colonnes regroupées (par exemple triées par clé primaire) grâce à la réutilisation du résultat de la ligne précédente pour les lignes consécutives identiques. #114853 (nikitamikhaylov). - Correction d’un temps d’exécution quadratique lorsque les fonctions
h3kRing,h3ToChildren,h3PolygonToCellseth3PolygonToCellsWithContainmentconstruisent leur résultat sur de nombreuses lignes. Lors d’un test de charge en intégration continue, une requête portant sur 196 000 lignes passait 838 secondes à copier de la mémoire ; elle s’exécute désormais en 5 secondes environ. #115773 (groeneai). - Optimisation des recherches inverses dans les dictionnaires. Un prédicat d’égalité constant tel que
WHERE dictGet(dict, attr, key_expr) = valueest désormais directement réduit par évaluation des constantes en un filtre sur la clé (key_expr = const,key_expr IN [...]ouWHERE 0) au lieu d’être réécrit en une sous-requêteIN (SELECT ... FROM dictionary(...)), et le chemin constant dedictGetKeyss’exécute désormais en parallèle. #91164 (nihalzp). - Ajout d’un nouveau paramètre
merge_tree_generic_exclusion_search_max_stepsqui limite le nombre d’étapes que l’algorithme de recherche par exclusion générique consacre à l’analyse de l’index de clé primaire de chaque partie de données. Ce budget est consacré en priorité aux plus grandes plages de clés restantes, de sorte que même un budget réduit suffit à écarter l’essentiel des données ; les plages qui n’ont pas été entièrement analysées sont lues en totalité : les résultats des requêtes restent donc corrects, mais davantage de granules peuvent être lus. La limite est appliquée de manière souple : elle peut être dépassée d’au plusmerge_tree_coarse_index_granularityétapes, plus une étape pour chaque plage en laquelle la partie de données est déjà divisée (par exemple, par le cache des conditions de requête). La valeur par défaut 0 signifie un nombre d’étapes illimité. #92779 (EmeraldShift). - Les requêtes comportant
ORDER BYetLIMITsur desVIEWreposant sur des tables distribuées bénéficient désormais de l’optimisation par fusion de flux triés. Les clausesORDER BY/LIMITexternes sont propagées dans la requête interne d’une vue simple, de sorte que chaque shard trie ses données localement et que le coordinateur fusionne des flux déjà triés, au lieu d’effectuer un tri complet sur le coordinateur. #94102 (matanper).
Performances du stockage, des E/S et du lac de données
- Utilisation des bornes de l’index minmax de partition pour éliminer davantage de granules lors de l’analyse de la clé primaire des tables
MergeTree, lorsqu’une colonne de la clé primaire est également une colonne d’entrée de la clé de partition. Par exemple, dans une tableMergeTreeavecORDER BY (id, event_time)etPARTITION BY toYYYYMM(event_time), ClickHouse utilisera l’index minmax de partition surevent_timelors de l’analyse d’index de la clé primaire afin de décider plus finement quels granules éliminer. Contrôlé par le nouveau paramètreuse_partition_minmax_for_primary_key_pruning(activé par défaut). #103480 (UnamedRus). - Accélération des opérateurs qui parcourent un flux trié à la recherche de séquences de valeurs de clé identiques :
DISTINCTdans l’ordre,LIMIT BYdans l’ordre,LIMIT BYnégatif dans l’ordre, ainsi que les jointuresfull_sorting_mergeetpartial_merge. #106502 (nihalzp). - Le lecteur Parquet v3 peut désormais ignorer des groupes de lignes entiers à l’aide de la page de dictionnaire (en plus des statistiques min/max et des filtres de Bloom) pour les conditions d’égalité et
IN, lorsqu’un bloc de colonne est entièrement encodé par dictionnaire. Contrôlé par le nouveau paramètreinput_format_parquet_dictionary_filter_push_down. #106952 (alexey-milovidov). - Utilisation de libdeflate pour la compression et la décompression gzip/zlib/deflate, désormais plus rapides (compression ~1,15× avec un meilleur ratio, décompression ~1,4–1,5×) pour les données
.gz/HTTP/url/s3et le codec GZIP de Parquet. #108074 (alexey-milovidov). - Accélération des fonctions
trimLeft/trimRight/trimBothavec les espaces par défaut (et de leurs aliasltrim/rtrim/trim) : les lignes consécutives ne nécessitant aucune suppression d’espaces sont copiées en un seul lot, et le parcours des espaces ligne par ligne n’est exécuté que pour les lignes comportant réellement un espace en début ou en fin. #108177 (groeneai). - Accélération de la lecture des tables Iceberg grâce au préchargement du fichier manifest suivant pendant l’analyse du manifest courant, ce qui permet de faire se chevaucher les I/O et le travail CPU. #108543 (asya-ch).
- Les requêtes de recherche vectorielle utilisant le rescoring limitent désormais le calcul exact des distances aux lignes candidates de l’index vectoriel, au lieu d’effectuer un rescoring par force brute des lignes voisines du même granule
MergeTree. #108846 (skuznetsov). - Ajout du paramètre
merge_tree_min_bytes_per_read_streamafin de limiter le nombre excessif de flux de lecture et la surcharge du pipeline lors des parcoursMergeTreelocaux ordinaires, non ordonnés et portant sur des colonnes étroites, sur les serveurs dotés d’un grand nombre de cœurs. #109035 (jiebinn). - Accélération de la sérialisation et des fusions des colonnes
JSONdont les données partagées contiennent de nombreux chemins épars. Lors de l’aplatissement des données partagées en colonnes par chemin,flattenAndBucketSharedDataPathsne parcourt plus chaque colonne de chemin accumulée à chaque ligne et n’insère plus les valeurs par défaut cellule par cellule ; le parcours de tous les chemins ligne par ligne est supprimé et les lacunes sont comblées en masse. #109341 (groeneai). - Le protocole natif envoie désormais les colonnes
Stringsous la forme d’un flux distinct de positions d’octets cumulées (la même disposition que celle utilisée parArraypour ses positions), suivi des données concaténées, au lieu d’un préfixe de longueur varint par valeur, dès lors que les deux pairs utilisent la révision de protocole 54489 ou ultérieure. Un client peut alors lire les colonnesStringavec une préallocation exacte du tampon et une seule copie en bloc, soit environ 4 fois plus vite qu’avec la disposition par valeur. Les anciens clients et serveurs ne sont pas affectés : la disposition est négociée via la révision du protocole. La même disposition est disponible dans les formatsNativeetBuffersgrâce aux nouveaux paramètresoutput_format_native_write_string_with_size_stream/input_format_native_read_string_with_size_stream(désactivés par défaut, afin que les formats restent portables). #110320 (vahid-sohrabloo). - Les requêtes avec
FINALqui lisent dans l’ordre de la clé primaire (ORDER BYsur un préfixe de la clé de tri) avec un petitLIMITn’utilisent plussplit_intersecting_parts_ranges_into_layers_final. #110431 (KochetovNicolai). - Matérialisation différée (matérialisation tardive) pour la lecture de fichiers Parquet depuis le stockage d’objet, y compris les tables Iceberg : pour les requêtes
ORDER BY ... LIMIT n, les colonnes qui ne servent ni au tri ni au filtrage ne sont lues que pour lesnlignes retenues par leLIMIT. Sur un fichier Parquet de 200 Mo stocké sur S3,SELECT k, s ... ORDER BY k DESC LIMIT 10lit 3,3 Mo au lieu de 171 Mo (51 fois moins d’IO, 8 fois plus rapide). Contrôlée par le nouveau paramètrequery_plan_optimize_lazy_materialization_for_object_storage(activé par défaut ; nécessite égalementquery_plan_optimize_lazy_materialization). #110970 (alexey-milovidov). - Les requêtes sur des tables Iceberg comportant de nombreux fichiers de suppression démarrent désormais plus rapidement. ClickHouse lit et décode les fichiers manifest de suppression en parallèle plutôt qu’un par un, ce qui permet à leurs lectures sur le stockage de se chevaucher. Le nouveau paramètre
iceberg_delete_manifest_decode_concurrency(valeur par défaut :4) détermine le nombre de fichiers décodés simultanément. #112679 (asya-ch). - Ajout d’une sérialisation Parquet optionnelle des types UInt128/UInt256/Int128/Int256 en DECIMAL afin de permettre l’élagage des groupes de lignes et des pages. #113347 (bobrik).
- Correction de la multiplication des requêtes de lecture sur les disques distants lorsqu’une étape de la chaîne de lecteurs lit des plages de marques fragmentées, par exemple des plages filtrées par des index primaires ou de saut. #113584 (CurtizJ).
- Suppression de la vérification redondante du tri lors de l’écriture de parts
MergeTreedont les clés de tri sont toutes constantes. #113899 (perfloop-agent). - La matérialisation différée pour les requêtes
ORDER BY ... LIMIT ns’applique désormais également aux fichiers Parquet locaux lus avec la fonction de tablefileet le moteur de tableFile: les colonnes qui ne servent ni au tri ni au filtrage ne sont lues que pour lesnlignes retenues par leLIMIT. Si le fichier a été modifié entre les deux passes, la seconde lecture d’un fichier retenu échoue de manière sûre avec la nouvelle erreurFILE_CHANGED_DURING_READ. Contrôlée par le nouveau paramètrequery_plan_optimize_lazy_materialization_for_file(activé par défaut). Corrige également l’échec de la matérialisation différée pour le stockage d’objet avec l’erreurNot found column or subcolumn ... in blocklorsqu’une sous-colonne demandée (par exemple d’une colonneJSON) est différée. #114262 (alexey-milovidov). - Accélère la construction du set pour
IN (subquery)sur les tablesMergeTreepartitionnées en conservant les lignes de chaque partition dans un seul flux et en dédupliquant chaque flux indépendamment : l’unique transformation de remplissage du set — qui hachait auparavant chaque ligne de manière séquentielle — ne traite ainsi plus que des lignes uniques. Cette optimisation s’applique lorsque l’expression de partition est une fonction déterministe des colonnes de sortie de la sous-requête. Elle n’est pas appliquée lorsque la plus grande partition contient plus de deux fois le nombre de lignes de la partition moyenne ; le nouveau paramètreforce_creating_set_partitions_independently(désactivé par défaut) permet de contourner cette vérification. Elle est contrôlée par le nouveau paramètreallow_creating_set_partitions_independently(activé par défaut). #114645 (nihalzp). - Marque comme
table_readonlyles tables de journaux systèmeMergeTreenon répliquées ayant fait l’objet d’une rotation et dépourvues de TTL, afin d’éviter des opérations d’arrière-plan inutiles. Le paramètretable_readonlyMergeTreeinterrompt désormais aussi toute tâche d’arrière-plan sur une tableMergeTreesimple — fusions ordinaires, fusions TTL (DELETE/MOVE/recompression) et fusions de recompression, mutations d’arrière-plan et déplacements de parties de données en arrière-plan — et rejette les commandes de partition qui modifient les données (ATTACH/MOVE/DROP/DROP DETACHED/FETCH/REPLACE PARTITIONetMOVE PARTITION ... TO TABLEvers la table), en plus des insertions, des mutations et deOPTIMIZEqu’il rejetait déjà. Par conséquent, une tabletable_readonlydotée d’un TTL ne libère plus ses données expirées tant que le paramètre est activé. #95079 (matt-metivier).
Efficacité de la mémoire et des ressources
- Réduction de l’utilisation mémoire de
UNLOCK SNAPSHOT: les métadonnées propres à chaque partie de données, inutilisées par le chemin de déverrouillage, ne sont plus chargées, ce qui évite les erreurs de mémoire insuffisante (out-of-memory) pour les snapshots comportant un très grand nombre de parties de données. #111849 (jkartseva). - Réduction des allocations de mémoire lors de la lecture des métadonnées de sauvegarde : chaque entrée de fichier est désormais déplacée dans les maps en mémoire au lieu d’être copiée. #111718 (jkartseva).
Performances des fonctions, des types et des formats
- La mise en forme des valeurs
Decimalen texte est beaucoup plus rapide : jusqu’à 190 fois pour unDecimal256avec une grande échelle, et environ 1,6 fois pour unDecimal64. Sur les processeurs prenant en charge AVX-512 IFMA, la conversion des entiers 64 bits en texte est environ 1,4 fois plus rapide. Correction également de l’arrondi detoDecimalString, qui perdait la retenue provenant de la partie fractionnaire :toDecimalString(toDecimal64('9.995', 3), 2)renvoyait9.00et renvoie désormais10.00. #112457 (thevar1able). - Amélioration des performances de l’algorithme de jointure
partial_mergesur les clésFixedString, en comparant des séquences de valeurs en une seule fois plutôt qu’en effectuant un appel de comparaison par valeur. #105737 (4ertus2). - Les clés LowCardinality de type string non nullables portant sur une seule colonne sont désormais prises en charge nativement dans
HashJoin. #107264 (nickitat). - Amélioration des performances de
replaceAlletreplaceRegexpAlllorsque le motif et le remplacement sont chacun constitués d’un seul caractère (par exemplereplaceRegexpAll(s, ' ', '_')). Ces remplacements ne modifient plus la disposition des string : la colonne est donc copiée une seule fois et les octets correspondants sont réécrits sur place, au lieu d’exécuter une boucle de recherche pour chaque correspondance. #108178 (groeneai). - Accélération de l’analyse de la représentation date-heure canonique
YYYY-MM-DD hh:mm:ssen mode best-effort (date_time_input_format = 'best_effort',cast_string_to_date_time_mode = 'best_effort'), qui est le mode par défaut. Cela corrige une régression des performances d’analyse apparue lors du passage de ces valeurs par défaut debasicàbest_effort. #108187 (groeneai). - Analyse des littéraux de tableaux et de tuples profondément imbriqués en temps linéaire plutôt que quadratique. #108892 (alexey-milovidov).
- La fonction
toStartOfInterval(aliastime_bucket,date_bin) est jusqu’à 5 fois plus rapide pour les intervallesSECOND,MINUTEetHOUR. #109729 (raimannma). - Les fonctions
arraySortetarrayReverseSortsont plusieurs fois plus rapides sur les tableaux numériques (y comprisDecimaletDateTime64) lorsqu’elles sont appelées sans lambda. #109832 (raimannma). - Accélération de
addDays,addWeeks,subtractDaysetsubtractWeekssur les valeursDateTimeetDateTime64dans les time zones à décalage fixe (comme UTC), grâce à un chemin d’exécution rapide purement arithmétique. #109836 (raimannma). - Vectorisation de la décompression du codec
Delta. Le décodage est désormais de 1,5 à 5 fois plus rapide pour les types de données 8/16/32 bits, ce qui accélère jusqu’à 20 % les parcours de colonnes compressées avecDelta. #110189 (raimannma). - Accélération des fonctions de recherche de string (
like,position,match,countSubstrings,hasToken, etc.) sur les colonnesEnumavec une aiguille constante : la recherche porte uniquement sur les noms distincts de l’enum, puis les résultats sont reportés sur chaque ligne, au lieu de parcourir toutes les lignes. #110325 (alexey-milovidov). - Amélioration des performances des fonctions de recherche de sous-chaînes (
position,countSubstrings,multiSearch*,replaceAll/replaceOne, ainsi que leurs variantes insensibles à la casse et UTF-8) avec une aiguille non constante, jusqu’à 1,5x, grâce à l’utilisation, sur le chemin de traitement par ligne, des algorithmes de recherche de chaînes de caractères basés sur SIMD au lieu d’une solution de repli naïve. #110580 (Algunenano). - Amélioration des performances de la consolidation et de la fusion des colonnes
DynamicetObjectcomportant de nombreux variants dynamiques ou chemins JSON. #110583 (cv4g). estimateCompressionRatioplus rapide avec le codecNONE#111107 (rienath).- Accélération du tri et des autres opérations reposant sur la comparaison sur les colonnes
JSONdont les chemins sont stockés dans les données partagées. Auparavant, chaque comparaison de valeurs matérialisait une colonneDynamictemporaire et effectuait une désérialisation binaire complète des deux côtés, ce qui rendaitORDER BYsur ces colonnes extrêmement lent. #111894 (groeneai). - La division des entiers 256 bits (
Int256,UInt256etDecimal256) calcule désormais le quotient par mots de 64 bits, à l’aide d’une boucle de divisions 128 / 64 lorsque le diviseur tient sur 64 bits et de l’algorithme D de Knuth dans le cas contraire, au lieu de procéder bit par bit avec une division longue par décalage et soustraction. Cela concerneintDiv,modulo, l’arithmétiqueDecimal256et la conversion de ces types en texte. #112477 (thevar1able). - La lecture d’une colonne
Nestedà partir d’un type encodé en binaire (Native,RowBinaryavecinput_format_binary_decode_types_in_binary_format) ne reconvertit plus le type en nom de type pour l’analyser à nouveau. De plus, un nom de typeTupleimbriqué mal formé est désormais signalé comme une erreur de syntaxe, au lieu de prendre un temps exponentiel en fonction de sa profondeur d’imbrication et d’échouer avecTOO_SLOW_PARSING. #112560 (alexey-milovidov). - Accélération des requêtes PromQL sur les tables TimeSeries :
timeSeriesIdToGroupréutilise désormais le groupe de la ligne précédente lorsque des lignes consécutives ont le même identifiant de série, ce qui évite la sérialisation de l’identifiant et la recherche par hachage pour chaque ligne. #113580 (nikitamikhaylov).
Autres améliorations des performances
- Implémentation d’un lecteur et d’un rédacteur natifs pour les formats
ArrowetArrowStreamqui n’utilisent pas la bibliothèque Apache Arrow, évitant ainsi des copies et des conversions de données supplémentaires. Ils sont désormais utilisés par défaut (paramètresinput_format_arrow_use_native_readeretoutput_format_arrow_use_native_writer) et sont plus rapides en lecture comme en écriture. #106522 (alexey-milovidov). - Optimisation des prédicats
nullIf(key, sentinel) = constafin de construire des plages de clés et de permettre l’élagage par clé primaire, par partition et par index de saut. #107308 (adityaksolves). - Performances de `INTERSECT ALL` et `EXCEPT ALL` (le mode par défaut de `INTERSECT` et `EXCEPT`) multipliées par plusieurs, grâce à l’indexation du multiensemble sur la valeur de la ligne plutôt qu’au calcul du hachage de chaque ligne avec SipHash. #107649 (Algunenano).
- Accélération des fonctions
match,extract,extractAll,replaceRegexpOneetreplaceRegexpAllpour les expressions régulières simples, grâce à leur compilation en code natif avec LLVM. Ce comportement est contrôlé par le nouveau paramètrecompile_regular_expressions(activé par défaut) ; les motifs ne relevant pas du sous-ensemble pris en charge basculent de manière transparente vers le moteur RE2. #108004 (alexey-milovidov). - Accélération de la décompression ZSTD sur AArch64 (ARM) pour les colonnes présentant de petits décalages de correspondance, comme les colonnes d’entiers à largeur fixe, grâce à la vectorisation avec NEON des copies chevauchantes à faible décalage. Par exemple, la décompression d’une colonne
UInt64est jusqu’à environ 2,3 fois plus rapide sur AWS Graviton 4. #108049 (alexey-milovidov). - Amélioration de la vitesse de décompression LZ4 pour les colonnes de taille fixe à faible cardinalité. #108175 (nickitat).
- Amélioration des performances de
levenshteinDistance(eteditDistance) pour les chaînes de longueur moyenne sur ARM, en évitant les allocations sur le tas pour chaque ligne dans le chemin de code Myers par blocs. #108185 (groeneai). - Accélération de l’analyse des nombres à virgule flottante à partir de texte avec
precise_float_parsing = 1, désormais aussi rapide, voire plus rapide, que l’analyseur par défaut sur presque toutes les entrées. La bibliothèque intégréefast_floatest également mise à jour vers la v8.2.10. #108205 (Algunenano). - Les fonctions d’encodage et de décodage Base64 utilisent désormais
simdutf, ce qui améliore leurs performances. #108333 (thevar1able). - Optimisation de
DISTINCTpour les clés coûteuses à forte cardinalité. #108366 (nihalzp). - Amélioration des performances des fonctions mathématiques grâce à l’activation d’optimisations du compilateur qui ne préservent pas
errno. #108628 (nickitat). - Accélération de
estimateCompressionRatiopour les colonnes encodées enT64, en calculant la taille compressée de manière analytique au lieu d’effectuer la compression. #109054 (rienath). - Les JOIN peuvent désormais utiliser l’index de clé primaire ou l’index de saut de la table de gauche pour élaguer les granules #109085 (shankar-iyer).
- Amélioration des performances des fonctions géographiques H3 (
h3ToGeoBoundary,h3ToGeo,h3CellAreaM2/h3CellAreaRads2,geoToH3) grâce au calcul conjoint des paires sinus/cosinus et à la suppression des appels trigonométriques redondants dans les transformations de coordonnées. Les résultats restent inchangés (identiques bit à bit). #109399 (alexey-milovidov). - Performances jusqu’à 7 fois supérieures pour les comparaisons (
<,>,<=,>=) sur les types entiers larges (Int128,UInt128,Int256,UInt256et les types qui en dérivent, tels queDecimal128), ainsi que pour la conversion des entiers signés enInt256(jusqu’à 7 fois sur des données de signes mixtes), grâce à un code de comparaison et d’extension de signe sans branchement. #109474 (raimannma). - Les fonctions comportant un seul argument
Nullablenon constant partagent désormais la null map de l’argument avec le résultat, au lieu d’en allouer et d’en fusionner une nouvelle. #110151 (raimannma). - Performances des fonctions
arrayMinetarrayMaxsur les tableaux numériques améliorées d’un facteur d’environ 1,3 à 1,5, grâce à une réduction vectorisée qui remplace la boucle de comparaison élément par élément. #110163 (raimannma). - Amélioration des performances de
DISTINCTlorsque le flux d’entrée est trié selon un préfixe des colonnes concernées par leDISTINCT, par exempleSELECT DISTINCT a, b FROM table ORDER BY a. Ces requêtes s’exécutent jusqu’à 2,4 fois plus vite. #110170 (nihalzp). - Chemins de traitement par lots vectorisés pour
groupBitOr/groupBitAnd/groupBitXoret la famille des fonctions de variance (varPop,varSamp,stddevPop,stddevSamp,skewPop,skewSamp,kurtPop,kurtSamp,covarPop,covarSamp,corr) : jusqu’à 4 fois plus rapides avec le combinateur-Ifsur des conditions imprévisibles, et jusqu’à 3 fois plus rapides sans celui-ci pour la famille des fonctions de variance. #110461 (raimannma). - Optimisation de l’analyse de l’index de texte. #110530 (CurtizJ).
- Accélération de l’analyse des valeurs
UUIDà partir de texte (par ex.JSONExtractversLowCardinality(UUID),toUUID,CAST AS UUID) grâce à la validation et à la conversion des chiffres hexadécimaux en une seule passe au lieu de deux. #110625 (groeneai). - Accélération de la décompression ZSTD sur x86_64 pour les colonnes présentant de faibles offsets de correspondance, comme les colonnes d’entiers à largeur fixe, grâce à la vectorisation des copies chevauchantes à offset court avec l’instruction SSSE3
pshufb(pendant x86_64 de l’optimisation AArch64 NEON introduite dans #108049). #110909 (thevar1able). groupUniqArrayjusqu’à 3 fois plus rapide pour les types numériques grâce au hachage CRC32 (comme dansuniqExact) et à l’inlining de l’insertion ligne par ligne. #110917 (raimannma).- Amélioration de l’efficacité des statistiques de colonnes minmax et de base pour les colonnes à virgule flottante. #111221 (cv4g).
- Les requêtes
COUNT()sont désormais renvoyées directement à partir des métadonnées de cardinalité de l’index de texte. #111494 (ahmadov). - Accélération de
minetmaxsur les types 128 bits et 256 bits (Int128,UInt128,Int256,UInt256,Decimal128,Decimal256). Jusqu’à 1,8 fois plus rapide pour les entiers larges et jusqu’à 3,4 fois plus rapide pour les décimaux larges. #111965 (raimannma). - Correction d’une régression de performance lors de l’ingestion dans
system.query_log. La construction des colonnes de type mapSettingsetasynchronous_read_countersétait environ 6 fois plus lente qu’auparavant, ce qui pouvait amenerSYSTEM FLUSH LOGS query_logà dépasser son délai d’expiration de 180 secondes sur les serveurs journalisant de nombreuses requêtes avec de nombreux paramètres modifiés. #112210 (groeneai). - Ajout d’une mise en cache optionnelle des tokens absents des index de texte. #112742 (rorylshanks).
- La journalisation asynchrone utilise désormais une file d’attente bornée sans verrou : les threads qui écrivent des messages de journal ne se bloquent jamais sur un mutex et ne réveillent plus les threads de journalisation. #112803 (alexey-milovidov).
- Utilisation de l’index de clé primaire pour
pointInPolygonlorsque l’argument point est une colonne de clé entière de typePoint(ou un autreTuplede deux éléments numériques), par exemplepointInPolygon(coord, [...])pour une table triée parcoord. Auparavant, seule la formepointInPolygon((x, y), [...])avec deux colonnes de clé scalaires était analysée. #112956 (alexey-milovidov). text_index_posting_list_apply_modea désormais pour valeur par défautlazy: les requêtes sur index de texte décodent ainsi les listes de postings à la demande, à la granularité des blocs compactés et à l’aide d’un curseur, au lieu de les matérialiser immédiatement en bitmaps pour les index de texte dontposting_list_codecest défini. #113521 (CurtizJ).- Accélération des transformations vectorisées de tags TimeSeries grâce au remplacement du remappage par hachage par une indexation directe lorsque les ID de groupes de tags occupent une plage compacte. #114244 (fallintoplace).
- Amélioration des performances des fusions d’index de texte. #114525 (CurtizJ).
- Utilisation de masques de présence compacts pour les opérateurs d’ensemble PromQL. #115224 (fallintoplace).
- L’attachement des tables système ne copie plus deux fois les métadonnées de chaque table, y compris la description complète de ses colonnes, dans le seul but de définir le commentaire de la table. #115490 (thevar1able).
- Accélération des vérifications de séries en double pour les vecteurs de condition PromQL entièrement nuls. #115822 (fallintoplace).
- Accélération de
toUTCTimestamp/to_utc_timestampetfromUTCTimestamp/from_utc_timestampsur les argumentsDateTime64, qui retrouvent le débit qu’elles avaient après les corrections de dépassement antérieures. Les résultats restent inchangés. #115838 (groeneai). - Réduction du coût fixe d’initialisation de la génération de données aléatoires (
rand,rand64,randomString,randomFixedString,generateUUIDv4,generateUUIDv7) sur x86-64. Le gain est sensible lorsque les blocs sont petits ; les valeurs générées restent inchangées. #116158 (Algunenano). - Il est désormais possible d’activer, lors de l’analyse, le repli anticipé par court-circuit des fonctions intégrées
andetorà l’aide du paramètreenable_function_early_short_circuit. Cela permet d’éviter l’exécution de sous-requêtes scalairescount()à une seule ligne devenues inutiles (code mort), tout en préservant l’inférence de type ordinaire et la validation sémantique. #83505 (fhw12345). - Utilisation d’un seul appel IO sur le tampon pour les vecteurs trivialement sérialisables. #89842 (Ergus).
- Activation par défaut de
optimize_or_like_chain. #94517 (alexey-milovidov). - Amélioration des performances lors de la récupération d’un seul enregistrement utilisateur depuis system.users lorsque le serveur compte de nombreux utilisateurs. #96699 (alistairjevans).
Améliorations
Améliorations des requêtes et du SQL
- Les CTE matérialisées référencées depuis plusieurs branches d’une requête
UNIONsont désormais matérialisées une seule fois et partagées entre toutes les branches. Auparavant, chaque branche recevait sa propre copie de la CTE, qui était intégrée (inlined) et évaluée séparément. #102107 (novikd). - Le JOIN runtime filter n’est plus appliqué lorsque le côté sonde est estimé de petite taille. Le nouveau paramètre
join_runtime_filter_min_probe_rows(par défaut1000) contrôle ce seuil #104860 (vdimir). EXPLAIN [PLAN] actions=1, compact=1, pretty=1devient le comportement par défaut. #105036 (Fgrtue).- Réduction de la latence d’annulation pour les formes positives de LIMIT BY (LimitByTransform, LimitBySortedStreamTransform) : KILL QUERY et Ctrl+C interrompent désormais le traitement dès la fin du bloc en cours, au lieu d’attendre la fin de l’étape entière. #106070 (rvasin).
- Les requêtes JOIN sont désormais prises en charge avec les répliques parallèles automatiques. #106073 (nickitat).
- Ajout d’une nouvelle métrique asynchrone UntrackedMemory (visible dans
system.asynchronous_metrics) qui indique la mémoire déjà allouée par les threads mais pas encore comptabilisée dans le compteur global de suivi de la mémoire. Chaque thread accumule localement les petites allocations et les remonte par lots. Cela permet d’expliquer les écarts entreMemoryTrackinget la consommation mémoire réelle du processus. Les messages d’erreurMEMORY_LIMIT_EXCEEDEDindiquent désormais aussi la quantité de mémoire non suivie, ce qui permet de mieux comprendre pourquoi une requête ou le serveur a atteint sa limite de mémoire. #106386 (mstetsyuk). - Lorsqu’un
INSERTéchoue parce que la table cibleTOd’une vue matérialisée rejette l’écriture pendant la construction du pipeline d’insertion (par exemple si la cible est uneViewou ne prend pas en charge les transactions), le message d’erreur mentionne désormais la vue matérialisée et sa table cible, au lieu de se limiter à l’erreur de stockage brute. #107234 (groeneai). ALTER TABLE ... MODIFY COLUMN <col> Tuple(...)sur unTuplenommé ne modifie désormais que les métadonnées lorsqu’il s’agit uniquement d’ajouter des sous-champs, ce qui le rend aussi rapide qu’unADD COLUMNde premier niveau. Fonctionnalité activable viaSET allow_metadata_only_named_tuple_alter = 1. #107305 (amosbird).- Ajout du paramètre
materialized_postgresql_use_extended_date_and_time_types, défini à la création, pour le moteur de base de donnéesMaterializedPostgreSQL. Par défaut (activé), les colonnes PostgreSQLdate/timestampsont inférées enDate32/DateTime64; s’il est défini à0lors duCREATE DATABASE, ce sont les types plus restreintsDate/DateTimequi sont inférés. Ce paramètre ne s’applique pas au moteur de tableMaterializedPostgreSQL. #107428 (alexey-milovidov). EXPLAIN PLANmarque désormais le nombre estimé de lignes produites par une jointure comme approximatif (~~...) lorsque l’estimation provient d’un indice ou d’une valeur de repli aléatoire plutôt que des statistiques de la table, ce qui aide à repérer les plans dépourvus de statistiques fiables pour le réordonnancement des JOIN. #107666 (vdimir).- Un
INSERTdans une tableMergeTreerespecte désormais l’annulation de la requête etmax_execution_timelors de l’écriture de nombreuses parts, au lieu de risquer de se poursuivre longtemps après avoir été interrompu (kill). #107929 (al13n321). arrayFoldrespecte désormais l’annulation des requêtes etmax_execution_time. Auparavant, un repli (fold) sur un tableau très long (par exemplearrayFold(acc, x -> arrayPushFront(acc, x), range(number), emptyArrayUInt64())) s’exécutait entièrement au sein d’un seul appel de fonction et ne pouvait pas être interrompu :KILL QUERYet les limites de temps étaient donc ignorés jusqu’à la fin du repli. #108192 (groeneai).- Ajout de
ProfileEventspour chaque phase de pré-exécution des requêtes :QueryParseMicroseconds,QueryAnalysisMicroseconds,QueryPlanBuildMicrosecondsetQueryPipelineBuildMicroseconds. Ils indiquent où le temps est passé avant l’exécution de la requête (analyse syntaxique, analyse, construction du plan de requête, construction du pipeline) et sont disponibles danssystem.query_logetsystem.events. #108282 (jrdi). - Les opérations
ALTER TABLEqui produiraient des métadonnées de table dépassantmax_query_sizesont désormais rejetées d’emblée, ce qui évite que des tables ne puissent plus être chargées par des composants tels que la distribution DDL ou la récupération des réplicas. #108283 (lockie). - Ajout de
ConstantJoinpour les jointures cartésiennes et les jointures à prédicat constant planifiées par l’analyseur : ces requêtes n’échouent plus à cause d’un paramètrejoin_algorithmincompatible lorsque l’analyseur est utilisé. #108289 (antaljanosbenjamin). - Ajout d’une colonne
sourceàsystem.documentation, contenant le chemin du fichier source où est définie la documentation de chaque entité. La table documente désormais aussi les codecs de compression, les profile events, les métriques courantes, les métriques asynchrones et les tables système elles-mêmes (avec leurs colonnes), et la documentation des paramètres inclut maintenant leur type et leur valeur par défaut. #108346 (alexey-milovidov). - Si vous spécifiez une clause WHERE avec des filtres sur
tableetdatabase,system.iceberg_historyne liste que les bases de données correspondantes. Cela peut faire gagner du temps si le serveur héberge de nombreuses bases de données distantes sans rapport. #108492 (Diskein). - Les paramètres de requête (substitutions
{name:Type}) peuvent désormais servir de valeurs de paramètres, aussi bien dans la clauseSETTINGSd’une requête (commeSELECTouINSERT) que dans des requêtesSETautonomes, par exempleSELECT ... SETTINGS max_threads = {threads:UInt64}etSET max_threads = {threads:UInt64}. #108760 (alexey-milovidov). - Possibilité de calculer le gain combiné des index de saut dans EXPLAIN WHATIF. Le résultat affiche le ratio de données, qui correspond à l’intersection des performances de tous les index hypothétiques adaptés existants. #108934 (yariks5s).
- Une requête comportant une seule CTE est désormais formatée avec les mêmes sauts de ligne et la même indentation qu’une requête comportant plusieurs CTE. Auparavant,
WITH a AS (...)laissait la CTE sur la même ligne queWITH, alors qu’avec deux CTE ou plus,WITHétait placé seul sur sa ligne et chaque CTE indentée. #109092 (groeneai). - Prise en charge du Query Condition Cache pour les fichiers Parquet locaux lus via le moteur de table
File(jusqu’ici réservé au stockage d’objet et aux data lakes). #109247 (alexey-milovidov). - Les entrées du Query Condition Cache pour les fichiers Parquet distants (stockage d’objet) sont désormais indexées par ETag en plus du path, afin que l’écrasement d’un objet sur place ne renvoie plus de résultats obsolètes depuis le cache. #109310 (alexey-milovidov).
- Une référence non qualifiée à une clé d’
INNER JOINmise en égalité dans la conditionON(par ex.SELECT id FROM a INNER JOIN b ON a.id = b.id) n’est plus signalée comme un identifiant ambigu, puisque les deux côtés ont nécessairement la même valeur. #109366 (alexey-milovidov). - Les fonctions de distance transposées sur
QBit(L2DistanceTransposed,cosineDistanceTransposed,dotProductTransposed, ainsi que leurs variantes quantifiéesL2DistanceTransposedQuantized,cosineDistanceTransposedQuantized,dotProductTransposedQuantized) acceptent désormais un vecteur de référence plus long que le nombre de dimensions recherchées, les éléments excédentaires en fin de vecteur étant ignorés. Il est ainsi possible de réutiliser un vecteur de requête complet pour une recherche à dimension réduite (Matryoshka) sans devoir le découper au préalable. #109388 (alexey-milovidov). - Ajout d’une vérification garantissant qu’une requête distribuée transmet toujours une version de client connue : une erreur logique est levée au lieu de transmettre silencieusement une version nulle aux shards distants. Les requêtes initiées par le serveur (opérations de flush en arrière-plan, consommateurs de streaming, rechargements de dictionnaires, vidages des insertions asynchrones) indiquent désormais la version du serveur lui-même comme version de l’initiateur. #109408 (alexey-milovidov).
- Correction de l’utilisation de noms de colonnes qualifiés dans la clause where des mutations sur les moteurs de table de la famille MergeTree. #109491 (Michicosun).
- Prise en charge des fonctions de fenêtre non partitionnées (
OVER (ORDER BY ...)) dans les plans de requêtes distribuées (make_distributed_plan). Auparavant, toute requête comportant une fonction de fenêtre échouait, carWindowStepne pouvait pas être sérialisé pour une exécution distante ; les fenêtres avecPARTITION BYrestent rejetées pour le moment. #109802 (VighneshPath). - Il est désormais possible de modifier certains paramètres d’authentification du catalogue one-lake avec
ALTER DATABASE ... MODIFY SETTING = 'xxx'. #110019 (alesapin). - Une sous-requête placée à droite de
INdont l’unique colonne est un tableau ayant une dimension de plus que l’argument de gauche est désormais interprétée comme l’ensemble des éléments du tableau (comme un littéral de tableau ou une fonction renvoyant un tableau), au lieu d’échouer avec une erreur d’incompatibilité de types peu claire. Par exemple,x IN (SELECT groupArray(x) FROM ...)fonctionne désormais. #110169 (alexey-milovidov). - Les requêtes accélérées par le filtrage dynamique TopK (
ORDER BY ... LIMIT k) tirent désormais mieux parti du cache des conditions de requête : le cache est alimenté même lorsque la matérialisation différée est appliquée, et ces requêtes peuvent réutiliser des entrées précédemment écrites par une requête ordinaire ayant le même prédicatWHERE. #110507 (shankar-iyer). SHOW CREATE TABLE(ainsi queSHOW CREATE VIEW/SHOW CREATE DICTIONARY) suggère désormais, dans le message d’erreur, une table au nom similaire lorsque la table demandée n’existe pas, comme le font les requêtesSELECT. #110633 (alexey-milovidov).- Ajout du modificateur STREAM BOUNDED, qui ne lit que le premier instantané d’une requête de streaming puis se termine, au lieu de s’abonner aux mises à jour. #110653 (SmitaRKulkarni).
- Correction du cache des résultats de requête pour les requêtes PromQL. Le dialecte
promqlcontournait la vérification des fonctions non déterministes et pouvait renvoyer des résultats obsolètes ancrés surnow(), tandis que l’API HTTP de Prometheus (/api/v1/query,/api/v1/query_range) ne stockait jamais aucune entrée de cache. #110887 (nikitamikhaylov). EXPLAIN ANALYZEindique désormais, pour chaque côté d’une jointure, le nombre de lignes, les taux de correspondance, le facteur d’expansion (fanout) ainsi que l’état propre à l’algorithme, comme la mémoire de la table de hachage et le débordement sur disque. Utilisezmatches = 1pour collecter les métriques de correspondance qui nécessitent un suivi supplémentaire. #110892 (Fgrtue).- Correction d’un heap-use-after-free dans l’exécuteur de pipeline, détecté par le fuzzer AST, qui pouvait faire planter le serveur lorsqu’une requête supprime des processeurs à l’exécution (par exemple
FINALavec lectures différées ou tri externe). #111017 (groeneai). - Correction d’un use-after-free (erreur de segmentation) lorsqu’une requête utilisant un snapshot de stockage partagé (paramètre
enable_shared_storage_snapshot_in_query) retire des parties de données du snapshot — par exemple une sous-requête en streaming lisant la même tableMergeTreequ’une autre partie de la requête lit simultanément. #111192 (alexey-milovidov). - Prise en charge des plans de requête distribués (
make_distributed_plan) pour les requêtes dont on peut prouver, dès la planification, que la source ne produit aucune ligne, comme une lecture depuis une tableMergeTreevide. Ces requêtes échouaient auparavant avecSUPPORT_IS_DISABLED. #111941 (groeneai). - Correction du query condition cache, qui n’était pas alimenté pour les granules éliminés par un autre conjoint que le dernier d’une clause
WHEREcomportant plusieurs conditionsAND. #112083 (shankar-iyer). - Réduction du pic de mémoire lors de l’écriture de colonnes JSON avec une sérialisation des données partagées par buckets (map_with_buckets et advanced), grâce à une répartition des données partagées dans les buckets un par un à l’écriture, au lieu de matérialiser tous les buckets simultanément. Cela profite surtout aux colonnes Array(JSON) : pour le JSON scalaire, les données partagées sont réparties par granule (dans la limite de index_granularity_bytes), si bien que le gain reste faible ; en revanche, un seul granule Array(JSON) peut contenir de nombreuses lignes imbriquées, et donc une grande quantité de données partagées, auquel cas la répartition bucket par bucket réduit sensiblement le pic de mémoire #112172 (Avogar).
- L’ordonnancement des réservations de mémoire (expérimental) n’évince plus une allocation lorsqu’une libération de mémoire en attente suffirait à couvrir une augmentation de réservation dépassant la limite : la décision d’éviction attend désormais que les diminutions en cours soient appliquées, ce qui évite d’interrompre inutilement des requêtes en situation de pression mémoire. #112299 (serxa).
SYSTEM DROP FILESYSTEM CACHEsupprime désormais les clés de métadonnées du cache en parallèle, ce qui accélère le vidage des caches du système de fichiers volumineux. Le nouveau paramètredrop_cache_threadsdu cache de fichiers contrôle le nombre de workers de suppression et vaut 16 par défaut ; avec la valeur 1, la suppression s’effectue dans le thread de la requête. #112532 (kssenii).- Les modificateurs d’une déclaration de colonne -
COMMENT,CODEC,STATISTICS,TTL,COLLATE,PRIMARY KEYet lesSETTINGSpar colonne - peuvent désormais être écrits dans n’importe quel ordre dansCREATE TABLE, chacun au plus une fois. Auparavant, un seul ordre fixe était accepté et, par exemple,x UInt64 CODEC(ZSTD) COMMENT 'text'provoquait une erreur de syntaxe. DansALTER TABLE ... ADD COLUMN/MODIFY COLUMN, les modificateurs pris en charge -COMMENT,CODEC,STATISTICS,TTLet lesSETTINGSpar colonne - peuvent également être écrits dans n’importe quel ordre ; lesSETTINGSpar colonne dansADD COLUMNet une clauseSTATISTICSdéclarée dansADD COLUMN/MODIFY COLUMNsont désormais appliqués au lieu d’être supprimés sans avertissement, etCOLLATEetPRIMARY KEYdans ces commandesALTERlèvent désormais une exception au lieu d’être ignorés sans avertissement. #112788 (alexey-milovidov). - Une requête sur une table
Merge(ou la fonction de tablemerge) correspondant à de nombreuses tables réagit désormais àKILL QUERYet àmax_execution_timependant la construction des plans de requête de chaque table, et non plus uniquement une fois la planification de toutes les tables enfants terminée. #113415 (alexey-milovidov). - Un
SELECTsur une tableMergequi dépassemax_execution_timeavectimeout_overflow_mode = 'break'cesse désormais de construire les plans de requête pour les tables correspondantes restantes, au lieu d’effectuer l’analyse complète de la requête pour chaque table correspondante avant de s’arrêter. La requête se termine toujours sans erreur, conformément au comportement documenté de ce mode. #113642 (groeneai). - Lorsque le type déclaré d’une colonne et ses données divergent lors d’une lecture
MergeTree(provenance de types mixte, par exemple après unALTER TABLE ... MODIFY COLUMNdont la mutation n’est pas terminée), le serveur lève désormais une exception explicite indiquant la colonne et les deux structures, au lieu d’effectuer une conversion non vérifiée : les builds de débogage et avec sanitizers s’interrompaient auparavant avec un simpleBad cast from type A to Bsans nommer de colonne, et les builds de production parcouraient silencieusement une mémoire incohérente. #114087 (alexey-milovidov). - Activation de
ie_joinpar défaut : la valeur par défaut dejoin_algorithmest désormaisdirect,parallel_hash,hash,ie_join. UnJOINdont la sectionONne contient que des conditions d’inégalité (deux comparaisons<,<=,>,>=entre des expressions des tables jointes) est désormais exécuté avec l’algorithme IEJoin basé sur le tri plutôt qu’avec unCROSS JOINsuivi d’un filtre, et les jointuresLEFT/RIGHT/FULL/SEMI/ANTIavec de telles conditions sont prises en charge. Commeie_joinfigure en dernière position dans la liste, il n’est utilisé que lorsque les autres algorithmes ne s’appliquent pas. #114327 (vdimir). - Propagation du contexte de trace OpenTelemetry dans les fibres utilisées pour l’établissement asynchrone des connexions et l’exécution des requêtes distantes (requêtes couvertes,
async_socket_for_remote,async_query_sending_for_remote). Les spans des requêtes distantes d’une requête distribuée sont désormais correctement rattachés au spanConnection::sendQueryde l’initiateur, au lieu d’être directement rattachés au contexte de trace fourni par le client, et chaque exécution de tâche asynchrone produit son propre span. #114813 (diegomestre2). DROP DATABASEsupprime désormais les tables dans l’ordre topologique inverse des dépendances de chargement et des dépendances référentielles (auparavant, seules les dépendances de chargement étaient prises en compte), de sorte qu’un plantage en cours deDROP DATABASEne peut plus laisser subsister une table dont les dépendances ont déjà été supprimées. #114952 (alexey-milovidov).- Prise en charge des opérateurs de correspondance d’expression régulière de style PostgreSQL :
~(un alias de la fonctionmatch),~*(correspondance insensible à la casse),!~et!~*(négations). Les commandes\d,\dtet\dvdepsqlfonctionnent désormais lors d’une connexion à ClickHouse via le protocole de compatibilité PostgreSQL, et l’échec d’une requête ne met plus fin à la connexion. #115066 (alexey-milovidov). EXPLAIN WHATIFindique désormais pourquoi l’estimation empirique a été ignorée, dans une nouvelle ligneempirical_reasonaffichée lorsqueempirical_statusvautunsupported. #115140 (yariks5s).- Lorsqu’aucun des algorithmes de jointure activés par le paramètre
join_algorithmne peut exécuter unJOIN, le message d’erreur indique désormais les algorithmes essayés ainsi que la rigueur (strictness) et le type du JOIN en échec, au lieu de signaler uniquement qu’aucun d’entre eux n’a fonctionné. #115226 (elkinal). - Les requêtes de recherche vectorielle peuvent désormais utiliser l’index de similarité vectorielle lorsque le vecteur de référence est un littéral de tableau d’entiers, par exemple
ORDER BY L2Distance(vec, [1, 2]). Auparavant, ces requêtes se rabattaient silencieusement sur un balayage exhaustif. #115255 (rschu1ze). BACKUPne laisse plus de fichier de verrou dans sa destination lorsque la tentative qui l’a créé échoue avant d’avoir écrit quoi que ce soit, que l’échec survienne lors de la réservation de la destination ou lors de l’ouverture d’une archive. Comme aucune sauvegarde ultérieure ne pouvait correspondre à un tel verrou, toute nouvelle tentative vers la même destination échouait tant que le fichier n’avait pas été supprimé manuellement. Les sauvegardes vers des destinationsS3etAzurecréent également le verrou de manière exclusive, et un verrou appartenant à une autre sauvegarde est signalé comme une sauvegarde concurrente plutôt que par l’erreur, quelle qu’elle soit, renvoyée par le stockage. #115387 (jkartseva).- Une trace démarrée par échantillonnage (
opentelemetry_start_trace_probability) est désormais reportée dans les informations client de la requête, de sorte que les requêtes secondaires distantes et distribuées, ainsi que les entrées DDL, rejoignent la même trace au lieu d’en démarrer de nouvelles, disjointes. #115619 (diegomestre2). - Correction de
CREATE TABLEpour les tables Iceberg reposant sur Amazon S3 Tables, qui gère lui-même l’emplacement des tables. #115652 (scanhex12). - L’agrégation
GROUP BYadaptative (enable_adaptive_aggregator) mesure désormais si le report des clés rares est rentable et revient à l’algorithme ordinaire lorsque leurs clés ou leurs arguments d’agrégat sont trop volumineux pour être copiés avec profit, de sorte que les agrégations sur des colonnes de chaînes volumineuses (par exemplemin(URL)par utilisateur) s’exécutent avec la vitesse et la consommation mémoire de l’algorithme ordinaire. Ajouteadaptive_aggregator_freeze_threshold_bytespour limiter en octets la table gelée de chaque thread (la table est gelée dès que l’un des deux seuils, celui-ci ou celui du nombre de clés, est atteint). #115755 (nihalzp). - Ajoute le paramètre
query_plan_aggregation_bucket_top_k(activé par défaut) pour activer ou désactiver l’optimisation du plan qui ne matérialise que lesnmeilleurs groupes de chaque bucket à deux niveaux lorsqu’une agrégation finale alimente unORDER BYsur ses sorties avecLIMIT n. L’optimisation apparaît désormais également dans la sortie deEXPLAIN. #116124 (nihalzp). - Amélioration de la prise en charge des requêtes
DESCRIBEpour les vues paramétrées. Prise en charge des vues paramétrées dans les expressions scalaires avec le nouvel analyseur. #68978 (novikd). - Les requêtes telles que
SELECT * FROM t WHERE idutilisent désormais les index de saut de données sur la colonneid. #89603 (adityachopra29). - Ajout du paramètre
query_plan_merge_expression_into_join, qui permet de fusionner les étapes Expression dans les étapes JOIN lors de l’optimisation par réordonnancement des JOIN. Le réordonnancement des JOIN devient ainsi possible à travers les sous-requêtes qui encapsulent des jointures (par exemple, lorsqu’un JOIN se trouve dans une sous-requête comportant des colonnes calculées), ce qui améliore l’optimisation des arbres de jointures complexes. #98533 (vdimir). - Ajout à la table
system.grantsd’une colonneis_wildcardindiquant si un grant utilise une correspondance de préfixe avec caractère générique (par exempleGRANT SELECT ON db*.*). Auparavant, il était impossible de distinguer danssystem.grantsles grants avec caractère générique des grants exacts portant sur le même nom. #98577 (il9ue).
Fonctions et types de données
- Ajout d’un nouveau paramètre
allow_lossy_numeric_supertype(désactivé par défaut). Lorsqu’il est activé,if,multiIf,coalesce,ifNull,arrayetmapappliqués à des arguments numériques dépourvus de type commun sans perte (par exemple unDecimalet unFloat64, ou unInt64et unFloat64) sont résolus vers le supertype numériqueFloat64au lieu d’unVariant, ce qui permet d’utiliser le résultat avec des fonctions d’agrégation commesum,avg,minetmax. Le nom du paramètre est désormais mentionné dans les messages d’erreur des fonctions d’agrégation concernées. #107236 (groeneai). - Le quantificateur de tableau
SOME/ALL(expr OP SOME(array)/expr OP ALL(array)) prend désormais également en charge les prédicats de comparaison par mots-clésIS DISTINCT FROMetIS NOT DISTINCT FROM, ainsi que les prédicats de recherche dans les chaînesLIKE,ILIKE,NOT LIKE,NOT ILIKEetREGEXP, réécrits enarrayExists/arrayAll. #107454 (alexey-milovidov). - Ajout du paramètre
input_format_json_max_object_sizepour limiter la taille des objets JSON lors de l’analyse. #107669 (Avogar). - Correction d’une fuite de mémoire survenant en cas d’échec de l’ouverture d’une base de données SQLite (par exemple, lorsque la fonction de table
sqliteou le moteur de base de donnéesSQLitereçoit un chemin impossible à ouvrir). #107807 (alexey-milovidov). - Prise en charge de la fonction
lengthpour le type de donnéesQBit. Elle renvoie la dimension du vecteur sous forme de constante. #108071 (alexey-milovidov). - Prise en charge du
CASTd’unQBitvers unArray, qui reconstruit le vecteur d’origine. Il s’agit de l’opération inverse de la conversion existante d’ArrayversQBit. #108072 (alexey-milovidov). - Le moteur de base de données, le table engine et la fonction de table
MySQLassocient désormais les types de colonnes spatiaux de MySQL (LINESTRING,POLYGON,MULTILINESTRING,MULTIPOLYGONet le type génériqueGEOMETRY) aux types géométriques ClickHouse correspondants au lieu deString. Ce comportement est contrôlé par le nouvel indicateurgeometrydu paramètremysql_datatypes_support_level, activé par défaut.POINTest toujours converti enPoint, comme auparavant. La colonne génériqueGEOMETRYest associée au type englobantGeometry; la lecture d’une valeur dont le sous-type n’a pas d’équivalent dans ClickHouse (MULTIPOINT,GEOMETRYCOLLECTION) lève une exception au moment de la lecture. #108944 (alexey-milovidov). - Utilisation par défaut de l’algorithme d’analyse précis des nombres à virgule flottante (valeur représentable la plus proche) et application du paramètre
precise_float_parsingaux formats d’entrée (CSV, TSV, JSON, VALUES, …) et aux littéraux numériques, et non plus uniquement àtoFloat*/CAST. Définissezprecise_float_parsing = 0pour retrouver l’ancien comportement, parfois plus rapide mais moins précis. #109086 (Algunenano). - Prise en charge de
reinterpretd’unArrayd’éléments de taille fixe enString, opération inverse dureinterpretexistant d’unString/FixedStringenArray. #109383 (alexey-milovidov). - Autorisation de
CASTentre des typesQBitdont le type d’élément et/ou le stride diffèrent, tant que la dimension reste identique (par exempleCAST(x AS QBit(Float64, N))à partir d’unQBit(Float32, N)). Les modifications portant uniquement sur le stride sont sans perte ; les modifications du type d’élément suivent la sémantique de conversionArraycorrespondante (par exemple, la conversion deFloat32versBFloat16peut entraîner une perte de précision, etaccurateCast/accurateCastOrNullrejettent les lignes qui ne sont pas exactement représentables). #109387 (alexey-milovidov). - Les fonctions
quantizeBFloat16ToInt8etdequantizeInt8ToBFloat16acceptent désormais aussi des argumentsArrayetQBit, en plus des surcharges scalaires existantes : elles appliquent alors le codec de Lloyd-Max à l’ensemble du vecteur et renvoient unArray/QBitdu type d’élément correspondant. #109398 (alexey-milovidov). - Le spécificateur de format de style MySQL
%fdansparseDateTime/parseDateTime64(et leurs variantesOrZero/OrNull) accepte désormais entre 1 et 6 chiffres fractionnaires, interprétés comme des microsecondes alignées à gauche, à l’instar deSTR_TO_DATEde MySQL, au lieu d’en exiger exactement 6. Correction également de l’alignement des tableauxPrettyCompactdans les exemples de la documentation des fonctions intégrées. #109421 (alexey-milovidov). - La sous-statistique
NullCountdes statistiquesbasicest renommée enDefaultCount: au lieu de compter les lignesNULLd’une colonneNullable,buildcompte désormais les lignes égales à la valeur par défaut intrinsèque du type de colonne viaIColumn::getNumberOfDefaultRows. #109977 (hanfei1991). - Réduction de la taille du binaire d’environ 10,5 Mo : les opérations de comparaison et arithmétiques sur des paires de types mixtes rarement utilisées (
Decimalface à un entier de largeur différente, et paires impliquantInt128/UInt128/Int256/UInt256) passent désormais par une conversion vers un type commun, au lieu de recourir à un kernel compilé dédié pour chaque combinaison de types. Les paires de même type, les paires couramment utilisées et les opérationsplus/minus/multiply, limitées par la mémoire, conservent leurs kernels dédiés ; les résultats, les types de résultat et les cas exceptionnels restent inchangés. #110131 (alexey-milovidov). - La lecture depuis un table engine
SQLiteou la fonction de tablesqlitene monopolise plus un cœur CPU entier en attente active lorsque la base de données SQLite est verrouillée par une autre connexion. La lecture reste désormais inactive en attendant le verrou, tout en restant annulable. #110248 (groeneai). - Arrondi à trois chiffres des valeurs de temps écoulé, de débit et de ratio dans les messages de journal et d’exception, afin que des nombres comme
1.345844286 sec.ne soient plus affichés en pleine précision. #110277 (alexey-milovidov). - Correction des lectures
MergeTreede colonnesStringdotées d’un flux de tailles séparé lorsque les premières lignes sont ignorées, ce qui pouvait renvoyer des données erronées ou entraîner une lecture hors limites dans le cache des sous-flux. Correction également de possibles données erronées lorsque des lectures concurrentes ou répétées accèdent à un sous-objetJSONstocké avec la sérialisation map des données partagées. #110471 (alexey-milovidov). - Prise en charge de la clause
SETTINGSpour le table enginePostgreSQLet la fonction de tablepostgresql(par exempleSETTINGS postgresql_connection_pool_size = 50), à parité fonctionnelle avec le moteurMySQL. #110614 (alexey-milovidov). - Les fonctions
bitmaskToArrayetbitmaskToListprennent désormais en charge les arguments(U)Int128et(U)Int256. Pour les arguments de type grand entier, la fonctionbitPositionsToArrays’exécute désormais en un temps proportionnel au nombre de bits à 1, et non plus à la position du bit à 1 le plus élevé. #110743 (raimannma). - Correction de la gestion par le codec GCD des valeurs signées à largeur fixe comportant des nombres négatifs. Auparavant, le diviseur était calculé directement à partir des valeurs signées, ce qui pouvait empêcher de trouver le diviseur commun et réduire considérablement l’efficacité de la compression pour les colonnes d’entiers signés et de décimaux. Le diviseur est désormais calculé à partir des valeurs absolues pour les types signés, tandis que le comportement existant est conservé pour les types non signés et pour la décompression. #113798 (kshcherbatov).
- Les fonctions de fenêtrage avec
PARTITION BYfonctionnent désormais avecmake_distributed_plan. Lorsque la structure du plan le permet, la fenêtre est exécutée en parallèle sur plusieurs buckets, chacun recevant des partitions complètes. #114111 (VighneshPath). - Une fonction de hachage 64 bits est désormais utilisée pour les méthodes d’agrégation externes sur des valeurs nullable à largeur fixe (ce qui évite une explosion des collisions lors d’agrégations à très forte cardinalité). #114210 (nickitat).
x IN (subquery)sur une colonneLowCardinalityrenvoie désormaisLowCardinality(UInt8), soit le même type quex IN (literal list). Auparavant, les deux formes renvoyaient des types différents, et les plans distribués comportant un telINnécessitaient un traitement particulier lors de la vérification des types du plan. #114229 (davenger).- Prise en charge de l’analyse des entiers dépassant la plage 64 bits dans le type de données
JSON,JSONExtractetisValidJSON. Ces valeurs sont lues dans des types d’entiers étendus tels queInt128/UInt256, au lieu d’entraîner le rejet du document entier. #114379 (Avogar). - Ajout de
keywordcomme alias du tokenizerarrayde l’index de texte, pour une meilleure compatibilité avec OpenSearch, Elasticsearch, SolR et Lucene. #115507 (rschu1ze). - Les fonctions
toDateOrNull,toDateTimeOrNullettoDateTime64OrNullacceptent désormais des arguments entiers de tous les types d’entiers natifs (interprétés de la même manière que partoDate,toDateTimeettoDateTime64, avec un argument facultatif de fuseau horaire), et renvoientNULLpour les valeurs hors de la plage du type de résultat. Par exemple,toDateTimeOrNull(1583851242, 'Asia/Shanghai')renvoie2020-03-10 22:40:42ettoDateTimeOrNull(4294967296)renvoieNULL. #79791 (jitendra1411).
Stockage, lacs de données et stockage d’objet
- Ajout de métriques Prometheus optionnelles pour l’activité d’éviction du cache du système de fichiers (
filesystem_cache_evictions_total,filesystem_cache_evicted_bytes_total,filesystem_cache_evicted_segment_hits,filesystem_cache_evicted_segment_size_bytes, ainsi que leurs variantes par utilisateur étiquetées avecuser_id), exposées pour chaque cache viasystem.dimensional_metrics,system.histogram_metricset l’endpoint Prometheus. Elles sont contrôlées par les paramètres de configuration du disque de cacheexpose_prometheus_eviction_metricsetexpose_prometheus_eviction_metrics_per_user(tous deux désactivés par défaut), qui peuvent être activés ou désactivés à chaud viaSYSTEM RELOAD CONFIG. #105020 (sacheendra). - Le moteur
Aliasprend désormais en charge la lecture avec répliques parallèles lorsque la table cible utilise un moteur de la familleMergeTree. #107830 (nauu). - Limitation à max_inflight_parts_for_one_file du nombre de parties préparées simultanément lors de la copie par lecture puis écriture dans Azure Blob Storage (utilisée par les sauvegardes lorsque la copie native n’est pas disponible), afin d’éviter une consommation excessive de mémoire lorsque de nombreux fichiers volumineux sont copiés en parallèle. #108232 (SmitaRKulkarni).
- Prise en charge de la colonne virtuelle
_etagpour le stockage HDFS #108255 (zhangyifan27). - Ajout des colonnes
settingsetengine_settingsàsystem.backupsetsystem.backup_log.settingsexpose les paramètres propres à la sauvegarde/restauration demandés pour une opération (par exempleallow_s3_native_copy,deduplicate_files,structure_only), etengine_settingsexpose les paramètres réellement utilisés par le lecteur/l’écrivain du moteur de sauvegarde (par exemple les paramètres de requête S3 tels queallow_native_copy, qui peuvent différer de ceux demandés une fois fusionnés avec la configuration de l’endpoint). Il est ainsi possible de savoir avec quels paramètres une opérationBACKUP/RESTOREs’est réellement exécutée. #108334 (jkartseva). - Ajout de
system.s3_queue_metadataetsystem.azure_queue_metadatapour inspecter l’état Keeper des tablesS3QueueetAzureQueueenregistrées, notamment le nombre de fichiers traités, en cours de traitement et en échec. #108522 (kssenii). - Consommation mémoire du cache des en-têtes d’index de texte divisée par 2 à 2,5. Le cache peut ainsi contenir davantage d’en-têtes de parts (paramètre
text_index_header_cache_size), ce qui réduit les lectures sur disque pour les requêtes de recherche textuelle. #109332 (CurtizJ). - Ajout de colonnes de compatibilité MySQL aux vues
INFORMATION_SCHEMA:SCHEMATA.DEFAULT_COLLATION_NAMEetDEFAULT_ENCRYPTION;TABLES.ENGINEet les colonnes MySQL associées ; ainsi queCOLUMNS.COLUMN_KEY,PRIVILEGES,GENERATION_EXPRESSION,SRS_ID. Les clients compatibles MySQL peuvent ainsi exécuter leurs requêtes d’introspection du catalogue sans se heurter à l’erreurUNKNOWN_IDENTIFIER. #109351 (alexey-milovidov). - Réduction de la consommation mémoire des tables
MergeTreecomportant de nombreuses parts : les métadonnées par part dérivées du schéma (liste des colonnes, descriptions des colonnes, sérialisations et sous-flux des colonnes) sont désormais partagées entre les parts d’une même table au lieu d’être copiées dans chacune d’elles. Le gain est particulièrement important pour les tables larges comportant de nombreuses petites parts. #109816 (Algunenano). - Ajout d’un nouveau paramètre
use_projection_index_in_read_pools(désactivé par défaut). Lorsqu’il est activé, les plages de marques entièrement exclues par un index de projection sont supprimées dans les pools de lectureMergeTreeavant la création des tâches de lecture correspondantes, au lieu d’être ignorées granule par granule pendant la lecture. Cela évite de créer des tâches de lecture et d’initialiser des lecteurs pour des données qui ne seront pas lues, et permet de mesurer la taille des tâches de lecture en marques restantes. #110291 (KochetovNicolai). - Réduction de la verbosité des diagnostics de recherche binaire sur la clé primaire par partie de données dans
MergeTree, qui passent de la journalisation de niveau trace au niveau test. #110324 (alexey-milovidov). - Correction de reconnexions intempestives des connexions HTTP keep-alive mises en pool via TLS (HTTPS, S3). La vérification des connexions obsolètes utilisait
pollsur le socket, qui signale à tort comme fermée une connexion sécurisée active contenant un enregistrement TLS post-handshake non lu (un ticket de session ouKeyUpdate) ; elle utilise désormais unMSG_PEEKnon bloquant sur les sockets non chiffrés etSSL_peek/SSL_has_pendingsur les sockets TLS, ce qui permet également de détecter correctement une fermeture TLS ordonnée ainsi qu’un enregistrement TLS arrivé seulement en partie. #110402 (alexey-milovidov). - Les catalogues OneLake peuvent désormais utiliser des refresh tokens OAuth pour renouveler les access tokens. #110413 (alesapin).
- Ajout du ProfileEvent
DuplicationDataHashComputations, qui compte les calculs de hachage de données par colonne effectués lors de la déduplication des blocs insérés (INSERT) dans les tables*MergeTree. #111173 (valerypetrov). - Le SST de l’index UNIQUE KEY est désormais écrit directement dans la partie de données via l’abstraction de stockage, au lieu de transiter par un fichier temporaire local. #111189 (JingYanchao).
- Prise en charge des écritures concurrentes dans les tables Iceberg sur un disque local :
LocalObjectStorageimplémente désormais les écritures conditionnelles, de sorte que l’opération compare-and-swap qui publie un nouveau snapshot viaversion-hint.texty fonctionne et que des écrivains concurrents ne peuvent plus écraser mutuellement leurs mises à jour. #112556 (alexey-milovidov). - Le cache de région des buckets du client
S3fonctionne désormais aussi pour les catalogues de data lake ; auparavant, chaque requête vers ces catalogues résolvait de nouveau la région. #113330 (scanhex12). - Les défaillances réseau côté client Azure (connexion réinitialisée/refusée, erreurs DNS et TLS) font désormais l’objet de nouvelles tentatives en tant qu’erreurs de transport au lieu de remonter sous la forme d’une erreur
500synthétique, comme pour le client S3. #115269 (arsenmuk).
Formats et ingestion
- Prise en charge de la compression snappy dans l’interface HTTP (
Accept-Encoding: snappy) et ajout du paramètresnappy_mode, qui permet de choisir entre le format de bloc snappy Hadoop et le format de tramage snappy pour les E/S snappy génériques viafile/url. #100752 (alexey-milovidov). - Ajout du paramètre
input_format_csv_missing_nullable_as_empty_string(désactivé par défaut). Lorsqu’il est activé, une valeur manquante de typeNullable(String)dans une entrée CSV est lue comme uneStringvide au lieu deNULL, quelle que soit la valeur deinput_format_csv_empty_as_default. #107577 (alexey-milovidov). - Lors du traitement de messages Protobuf avec
input_format_protobuf_oneof_presence, une correspondance exacte des balises n’est plus exigée, afin de permettre les modifications de schéma. #109174 (ilejn). - Suppression de l’ancien lecteur ORC (legacy) basé sur Apache Arrow. Le format d’entrée ORC utilise désormais systématiquement le décodeur natif de ClickHouse (qui était déjà utilisé par défaut). Le paramètre
input_format_orc_use_fast_decoderest obsolète (il est toujours accepté, mais n’a plus aucun effet). #110074 (alexey-milovidov). - Le moteur Hive lit désormais les métadonnées des fichiers ORC (index min/max, nombres de lignes) à l’aide du lecteur ORC natif de ClickHouse, et non plus de l’adaptateur ORC d’Apache Arrow. #110086 (alexey-milovidov).
Sécurité, accès et observability
- Ajout d’une nouvelle colonne
skipping_indices_typesà la tablesystem.tables. Elle contient les différents types d’index de saut de données définis pour chaque table. #106388 (CurtizJ). - La valeur automatique de
max_threadset des paramètres similaires s’affiche désormais danssystem.settingssous la formeauto(8)au lieu de'auto(8)'; les guillemets simples qui l’entouraient étaient un artefact de longue date intégré à la valeur. La compatibilité entre versions est préservée : l’ancienne forme entre guillemets (legacy) reste acceptée lors de l’analyse des paramètres reçus de serveurs plus anciens. #108657 (alexey-milovidov). - Une valeur par défaut de paramètre vide s’affiche désormais sous la forme string vide dans
system.documentationau lieu de backticks vides. #108708 (alexey-milovidov). - La documentation d’un paramètre dans
system.documentation(affichée par la page intégrée/docset par la commandehelp) inclut désormais l’historique des modifications de sa valeur par défaut : la version dans laquelle le paramètre a été introduit et chaque modification ultérieure de sa valeur par défaut, avec l’ancienne valeur, la nouvelle valeur et la raison de la modification. #112177 (alexey-milovidov). - La documentation de tous les statements SQL (par exemple nom, syntaxe, description, exemples) peut désormais être consultée dans la table système
system.statements. #115341 (rschu1ze).
Paramètres et configuration
- Ajout d’un nouveau paramètre serveur
memory_worker_rss_speculative_reserve_ratio(par défaut1.0, ou0dans les constructions avec sanitizer) qui amène le memory tracker global à réserver de manière spéculativeratio * min(resident - previous_resident, resident - tracked)en plus du RSS observé, à chaque cycle deMemoryWorker. Le tracker est ainsi biaisé à la hausse lorsque le RSS croît plus vite que sa comptabilité entre deux échantillons : les allocations reçoiventMEMORY_LIMIT_EXCEEDEDplus tôt, et l’OOM-killer du noyau a moins de risques de se déclencher en premier. Définissez le ratio à0pour désactiver la spéculation. Les constructions avec sanitizer utilisent0par défaut, car l’écartresident - trackedy est principalement dû à la mémoire fantôme (shadow memory) du sanitizer. #104976 (alexey-milovidov). - Le mode d’application différée des posting lists de l’index de texte n’est plus expérimental et peut être sélectionné avec
text_index_posting_list_apply_mode = 'lazy'sansallow_experimental_text_index_lazy_apply. Le paramètre de seuil de densitétext_index_density_thresholda été renommé entext_index_lazy_intersection_density_threshold. #108814 (CurtizJ). - Le paramètre
merge_selector_enable_heuristic_to_lower_max_parts_to_merge_at_onceest désormais activé par défaut : le sélecteur de fusion réduit automatiquement le nombre maximal de parties de données à fusionner simultanément en fonction du taux de remplissage de la partition. #110726 (Michicosun). - Les commandes de nettoyage PostgreSQL
RESET,UNLISTENetDISCARDsont désormais acceptées comme des opérations sans effet dans le PostgreSQL wire protocol, au lieu d’échouer avec une erreur de syntaxe. La compatibilité est ainsi améliorée avec des pilotes tels que Skunk, qui envoientRESET ALLetUNLISTEN *lors de l’établissement et du nettoyage de la connexion. #110780 (alexey-milovidov). - Les fonctions de texte IA (
aiGenerate,aiClassify,aiExtract,aiTranslate) rejettent désormais les réponses du fournisseur tronquées ou incomplètes pour toute autre raison (par exemple lorsque le modèle atteint la limitemax_tokens), au lieu de renvoyer silencieusement une sortie partielle. Le comportement est régi par le paramètreai_function_throw_on_error. #111830 (george-larionov). - Amélioration des versions en précision réduite de
L2DistanceTransposedQuantized,cosineDistanceTransposedQuantizedetdotProductTransposedQuantized, grâce à la reconstruction des codesp < 8QBit(Int8)à l’aide de centroïdes de préfixe fondés sur la moyenne conditionnelle gaussienne. La pleine précision (p = 8) reste exacte au bit près ; les distances approximatives en précision réduite peuvent changer, et les gains en rappel et en latence dépendent de la charge de travail. #111867 (skuznetsov). - Le paramètre
write_snapshot_versionpeut désormais être rechargé à chaud. #112150 (alesapin). - Ajout de l’observability des piles des fibres, utilisées pour la communication asynchrone avec les répliques distantes : profile events
FiberStackAllocs,FiberStackAllocBytes,FiberStackAllocNanoseconds,FiberStackFreeNanoseconds, et métriquesFiberStacks,FiberStackBytes. #114541 (alexey-milovidov). - Le protocole Prometheus remote-write prend désormais en charge les insertions asynchrones : les données de plusieurs requêtes remote-write simultanées sont regroupées avant la formation des parties de données, selon le paramètre
async_insert(activé par défaut ; ajoutezasync_insert=0à l’URL du gestionnaire pour conserver le comportement synchrone). Une requête n’est acquittée qu’une fois les données vidées vers toutes les tables internes de la tableTimeSeriescible. #115688 (nikitamikhaylov).
Autres améliorations
- Ajout de deux paramètres,
shrink_over_allocated_columns_min_waste_ratioetshrink_over_allocated_columns_min_waste_bytes, qui permettent aux INSERT de réduire les colonnes surallouées (dont la mémoire réservée dépasse la mémoire utilisée en raison de la croissance par puissances de deux des colonnes de longueur variable) à leur taille réelle avant la materialization et l’écriture des parties de données, ce qui réduit le pic d’utilisation de la mémoire. Désactivés par défaut. #112161 (Avogar). - L’étape de lecture des données est désormais entièrement ignorée pour les fusions
TTLDropafin d’éviter une consommation excessive de mémoire, notamment liée aux allocations des tampons de lecture/préchargement. #105859 (Avogar). - Ajout de la prise en charge de
BFloat16dansdotProductet amélioration des performances du produit scalaire grâce au traitement par lots du chemin SIMD. #106569 (nickitat). - Les paramètres
max_named_collection_num_to_throw,max_table_num_to_throw,max_replicated_table_num_to_throw,max_view_num_to_throw,max_dictionary_num_to_throwetmax_database_num_to_throwpeuvent désormais être modifiés sans redémarrer le serveur. #106821 (UberDever). - L’écriture dans les tables
DeltaLake, contrôlée parallow_experimental_delta_lake_writes, passe au statut Beta. #107034 (kssenii). - Ajout du type de statistiques de colonne
uniq_v2, une alternative légère àuniqreposant sur le sketchuniqCombined64. #107863 (hanfei1991). - Ajout des ProfileEvents
DistributedPlanRemoteTasks,DistributedPlanLocalExecutionetDistributedPlanHostsUsedpour suivre l’exécution de make_distributed_plan. #107985 (shankar-iyer). - Les requêtes envoyées aux catalogues de data lake REST tels que OneLake incluent désormais un en-tête
User-AgentClickHouse. #108117 (scanhex12). MVTEncodeGeomaligne désormais la géométrie sur la grille de pixels entiers avant le découpage et découpe les polygones avecwagyu: le résultat découpé est ainsi valide (les anneaux auto-intersectants sont réparés) et aligné sur les bords, conformément àST_AsMVTGeomde PostGIS. #108248 (saarthak2002).- Les trois caches d’index de texte sont désormais activés globalement ; auparavant, ils n’étaient activés qu’au niveau des requêtes. Par ailleurs, la taille du cache des listes de postings est désormais nulle (ce qui revient de fait à le désactiver à nouveau), car les listes de postings sont volumineuses et leur mise en cache est trop coûteuse. #108274 (rschu1ze).
- L’endpoint Prometheus (pour les configurations limitées aux métriques) et la collecte asynchrone des métriques démarrent désormais avant le chargement des tables, afin que les métriques soient observables pendant la phase de chargement des métadonnées, potentiellement longue. #108402 (cwurm).
- Prise en charge de BFloat16 dans les fonctions mathématiques binaires #108442 (zhangyifan27).
- Les fonctions de distance vectorielle transposées
L2DistanceTransposed,cosineDistanceTransposedetdotProductTransposedappliquent désormais l’optimisation de lecture partielle des plans de bits aux colonnesNullable(QBit), en ne lisant que les plans de bits demandés au lieu de la colonne entière. #109358 (alexey-milovidov). - Prise en charge de
arraySum,arrayAvgetarrayProductpour les tableaux deBFloat16. #109420 (alexey-milovidov). - Les fonctions
L1Normalize,L2Normalize,LinfNormalizeetLpNormalize(ainsi que leurs alias) fonctionnent désormais avec les tableaux, et plus seulement avec les tuples, par cohérence avecL2Normet les fonctions de distance. #110052 (alexey-milovidov). - Les connexions du pool ne sont plus soumises à un ping avant chaque utilisation. Cela supprime l’aller-retour
Ping-Pongajouté à chaque réutilisation d’une connexion, ce qui réduit la latence des requêtes distribuées et declickhouse-benchmark. Une connexion du pool devenue obsolète est détectée au moyen d’un poll à délai d’expiration nul (une vérification non bloquante qui n’ajoute aucun aller-retour), puis rétablie par reconnexion. #110068 (alexey-milovidov). - Envoi des grandes listes de parts pour l’analyse d’index distribuée sous forme de scalaires (évite d’éventuels échecs dus à max_ast_elements/max_query_size et supprime le surcoût d’analyse de l’AST) #110419 (azat).
- Un clic sur le logo cloud dans le Playground ouvre désormais le site web de Clickhouse dans un nouvel onglet, afin que vous ne perdiez pas votre progression pendant l’exécution des requêtes. #110422 (williamhatcher).
- La valeur par défaut de
auto_statistics_typespasse debasic, uniqàbasic, uniq_v2#110878 (hanfei1991). - Lorsqu’une assertion de réentrance de
RWLockImpl::getLock()se déclenche (RWLock is already locked in exclusive mode/Cannot acquire exclusive lock while RWLock is already locked), le message d’erreur indique désormais les autresquery_idqui détiennent actuellement le verrou, ainsi que le nombre de verrous déjà détenus par lequery_iddemandeur, afin de faciliter le diagnostic de ces erreurs d’ordre d’acquisition des verrous. #110971 (groeneai). randomHadamardTransformcalcule désormais une transformation exacte, préservant la longueur, pour toute longueur de vecteur dont le plus grand facteur impair est inférieur ou égal à 64 (par exemple3584 = 512 * 7, fréquent dans les modèles d’embedding), ce qui étend les familles précédemment prises en charge2^N,2^k * {12, 20}et2^k * 9. Une transformation complète d’une longueur qui ne peut pas être représentée exactement lève désormais une exception, au lieu de compléter silencieusement par des zéros jusqu’à un vecteur plus long ; passezoutput_dimspour calculer une projection tronquée de longueur arbitraire. #111006 (alexey-milovidov).- Renvoi du code HTTP
403 Forbidden(au lieu de500 Internal Server Error) pour les exceptionsACCESS_DENIEDvia l’interface HTTP. #111043 (Schum-io). UTMToGeoaccepte désormais comme quatrième argument la lettre de bande de latitude MGRS renvoyée pargeoToUTM(en plus de l’indicateur entier d’hémisphère), de sorte qu’un résultat degeoToUTMpeut être directement reconverti avecUTMToGeo. #111521 (alexey-milovidov).MaterializedPostgreSQLconserve désormais les valeurs PostgreSQLTOASTinchangées lors des mises à jour, au lieu de les remplacer par des valeurs par défaut. #111552 (OrpheusAgent).- Ajout des paramètres
text_index_max_processed_tokens_before_flushettext_index_max_memory_usage_before_flushpour contrôler le moment où les générateurs d’index de texte effectuent le vidage des segments temporaires. #111573 (rorylshanks). - Ajout du modificateur STREAM UNORDERED : ignore le tri par ordre de commit propre à chaque snapshot #111794 (SmitaRKulkarni).
- Désormais,
make_distributed_plan=1désactive les fonctionnalités qui ne sont pas encore prises en charge.. #112463 (alesapin). - Les séquences d’échappement ANSI ne sont plus écrites dans INTO OUTFILE lorsque stdout est un tty #113252 (azat).
allow_experimental_delta_kernel_rsa été renommé enallow_delta_kernel_rs. L’ancien nom est conservé comme alias. #113476 (kssenii).- Ajout des paramètres
enable_alp_codec,enable_sz3_codec,enable_zxc_codecetenable_quantized_codecpermettant d’activer individuellement chaque codec de compression expérimental. #113824 (rienath). - Signalement d’un débordement de pile au lieu d’un arrêt silencieux : les handlers des signaux fatals s’exécutent désormais sur la pile de signaux alternative, de sorte que
SIGSEGV,SIGABRT,SIGILL,SIGBUS,SIGSYS,SIGFPEetSIGTRAPproduisent une stack trace même lorsque le thread à l’origine de l’erreur a épuisé sa pile. #113927 (groeneai). - Prise en charge du paramètre lookback_delta de l’API HTTP de Prometheus pour les requêtes instantanées et par intervalle. #113971 (fallintoplace).
- Les tables QueryRunner démarrent désormais leurs worker threads à la demande et les libèrent une fois inactifs, au lieu d’occuper des threads pendant toute la durée de vie de la table. #114522 (mstetsyuk).
- Avec cette modification, lors de l’utilisation des index WHATIF, la référence fournie par la projection signale
not_applicablepour chaque candidat au lieu de faire échouer le statement. #114846 (yariks5s). - Optimisation des chaînes AND comportant plusieurs conditions de comparaison sur la même expression : détection des contradictions (par ex.
a < 3 AND a > 5→false) et suppression des conditions redondantes (par ex.a = 3 AND a < 5→a = 3). #99736 (wudidapaopao).
Corrections de bogues
Correctifs liés à MergeTree, à la réplication et au stockage
- Correction d’une condition de concurrence entre
ALTER TABLE ... RENAME COLUMNet unOPTIMIZE TABLE ... FINALsimultané (ou toute fusion en arrière-plan) dansMergeTree, qui pouvait remplacer silencieusement les données de la colonne renommée par des valeurs par défaut. La fenêtre de concurrence entre la publication des nouvelles métadonnées en mémoire et l’enregistrement de la mutation de renommage danscurrent_mutations_by_versionest désormais éliminée :currently_processing_in_background_mutexest maintenu pendant les deux opérations. #104822 (groeneai). - Correction de résultats de requête incorrects lors de l’utilisation de GROUP BY avec ORDER BY et
arrayJoindans la projection. #101775 (Onyx2406). - Les paramètres de taille de téléversement Azure invalides (par exemple
azure_min_upload_part_size = 0ouazure_max_blocks_in_multipart_upload = 0) sont désormais rejetés en amont avec une erreur explicite, au lieu de déclencher une exception interne (second_size > 0) au plus profond du chemin d’écriture. Cela s’applique à la fois aux paramètres de requête et à la configuration de disque Azure. #103394 (statxc). - Levée de
BAD_ARGUMENTSau lieu deLOGICAL_ERRORlorsqueALTER TABLE ... MOVE/REPLACE/ATTACH PARTITIONest exécuté entre deux tablesMergeTreedont les paramètres de granularité sont incompatibles (l’une adaptative, l’autre non). #103881 (groeneai). - Correction d’une erreur
LOGICAL_ERROR« Expected one block from input stream » levée parKILL QUERY/KILL MUTATION/KILL PART_MOVE_TO_SHARD/KILL TRANSACTIONlorsque leur clauseWHEREcontient une sous-requête évaluée ligne par ligne, ou lorsquemax_block_sizeest suffisamment petit pour que leSELECTinterne sur la tablesystem.*concernée produise plus d’un bloc. #104927 (groeneai). - Correction d’une fuite dans les vues matérialisées actualisables (
MATERIALIZED VIEW ... REFRESH ...) : la table interne temporaire que la tâche de rafraîchissement écarte viaEXCHANGE TABLESne pouvait pas être supprimée si sa taille dépassait la valeurmax_table_size_to_dropdu serveur. Chaque rafraîchissement ultérieur créait alors une nouvelle table interne temporaire sans parvenir à nettoyer les précédentes, ce qui faisait croître le répertoire de données de la vue jusqu’à saturation du disque. La suppression interne effectuée par la tâche de rafraîchissement ignore désormaismax_table_size_to_dropetmax_partition_size_to_drop; ces garde-fous restent appliqués lorsque l’utilisateur exécute lui-même unDROP TABLEsur la vue. #105106 (groeneai). - Correction d’une erreur
DATA_TYPE_CANNOT_BE_USED_IN_KEYinattendue sur les requêtesALTERqui ne peuvent pas modifier la clé de tri (paramètres, commentaires, codecs, ajout d’une colonne hors clé, etc.) pour les tablesMergeTreedont la clé de tri contient unSimpleAggregateFunction(ou un autre type autorisé uniquement avecallow_suspicious_primary_key = 1). #105111 (groeneai). - Un
OPTIMIZE ... DRY RUNinterrompu par un dépassement du délai de requête (max_execution_timeavectimeout_overflow_mode = 'break') renvoie désormaisTIMEOUT_EXCEEDEDau lieu d’une erreur logique concernantrows_sources(qui faisait planter le serveur dans les builds debug et sanitizer). #107114 (groeneai). - Correction de l’erreur
NOT_FOUND_COLUMN_IN_BLOCKlors de la lecture de fichiers partitionnés au format Hive avecuse_hive_partitioning=1et une clauseWHERE/PREWHEREfiltrant une colonne réelle (non virtuelle) alors qu’une colonne de partition Hive est également sélectionnée. #107505 (groeneai). - Correction de résultats de requête erronés dus à un élagage incorrect par clé primaire et par partition lorsque
toStartOfDay,toStartOfISOYear,toDaysSinceYearZero,toRelativeSecondNum,toRelativeMinuteNum,toRelativeHourNum,toRelativeWeekNum,toRelativeDayNum,toMonthNumSinceEpochoutoYearNumSinceEpochest appliquée à une colonne de cléDate32contenant des dates hors de la plage que la fonction peut représenter (en particulier des dates antérieures au1970-01-01). Ces fonctions se déclarent monotones auprès de l’index primaire, mais leur résultat débordait auparavant pour de tels arguments, si bien que l’index pouvait élaguer des granules contenant pourtant des lignes correspondantes. Elles saturent désormais aux bornes de leur type de résultat et restent monotones sur toute la plageDate32, ce qui garantit un élagage correct. #108018 (nihalzp). - Correction de
CREATE TABLE dst AS src SETTINGS ...(et des variantes similaires avecORDER BY/PARTITION BYmais sansENGINEexplicite), qui perdait silencieusement le moteur, les clauses de stockage (telles que leTTLde table et les clés) et les paramètres de la table source. Le moteur et les clauses de stockage non redéfinies sont désormais hérités de la table source, et les paramètres spécifiés sont fusionnés par-dessus ceux de la table source. #108085 (alexey-milovidov). - Correction de l’échec des
INSERTdans les tablesMergeTreeavec l’erreurfilesystem error: in rename: Permission deniedsur les systèmes de fichiers reposant sur Windows (WSL, CIFS/SMB, montages bind de Docker Desktop). Ce problème était dû au module d’écriture des parties de données, qui laissait des descripteurs de fichiers ouverts pendant le renommage du répertoire de la partie de données. #108089 (alexey-milovidov). - Correction d’un blocage sur une table MergeTree rattachée avec un ancien index de saut
hypothesis(un type d’index supprimé, conservé uniquement pour la compatibilité avecATTACH). Auparavant, unDELETEléger, unOPTIMIZE, un simpleINSERTou unSELECTfiltré sur une telle table échouait avecILLEGAL_INDEX(“Index of type ‘hypothesis’ is no longer supported”), et la mutationDELETEétait relancée indéfiniment. L’index obsolète est désormais traité comme inerte : il est conservé tel quel lors des fusions et mutations, ignoré lors de l’insertion et de la planification des requêtes, et peut toujours être supprimé avecALTER TABLE ... DROP INDEX. #108217 (groeneai). - Correction de l’erreur
NOT_FOUND_COLUMN_IN_BLOCK(par ex.Column _part not found) lors de la sélection de colonnes virtuelles d’une tableMergeTreeavec des réplicas parallèles, y compris viaSELECT *avecasterisk_include_virtual_columns = 1. #108451 (groeneai). - Correction de
ATTACH PARTITION ... FROM, qui rejetait des tables dont les clés primaires sont équivalentes mais déclarées différemment (l’une par unPRIMARY KEYexplicite, l’autre implicitement viaORDER BY). #108590 (jordiori). join_any_take_last_rowest désormais respecté par tous les chemins de jointure par hachage pris en charge, y compris les jointures avec déversement automatique sur disque. #108936 (antaljanosbenjamin).- Correction de l’erreur
NOT_FOUND_COLUMN_IN_BLOCKlorsquequery_plan_optimize_lazy_finalest activé en même temps qu’un filtreWHEREpartiellement déplacé versPREWHERE(viaoptimize_move_to_prewhere_if_final). L’optimisation FINAL différée ne demande plus au stockage les colonnes de prédicat calculées par prewhere. #109073 (groeneai). - Correction de
ALTER TABLE ... ADD PROJECTIONsur une colonneALIASdéfinie au niveau de la table, qui rendait la table inutilisable (lesINSERTsuivants échouaient avecUNKNOWN_IDENTIFIER, “Missing columns”) lorsque la session utilisaitoptimize_respect_aliases = 0. #109091 (groeneai). - Correction d’une assertion de pointeur nul (
px != 0dansTreeRewriter::analyzeSelect, qui interrompait le serveur dans les builds de débogage et avec sanitizers) lors de l’exécution deORDER BY ALL(ouGROUP BY ALL) sur une table utilisant le moteurMergejointe à une autre table avec l’ancien analyseur (allow_experimental_analyzer = 0). #109139 (groeneai). - Correction d’un résultat erroné des sous-requêtes
EXISTScorrélées et des sous-requêtes scalaires lorsque la corrélation n’apparaît que dans la projection de la sous-requête, associée à une clauseWHEREnon corrélée (la sous-requête pouvait être évaluée à false /NULLpour chaque ligne). Corrige https://github.com/ClickHouse/ClickHouse/issues/105760. #109186 (novikd). - Correction d’un bogue où la fusion d’une table
MergeTreecomportant des projections, lorsque le paramètreenable_block_number_columnouenable_block_offset_columnétait activé, produisait des parts de projection contenant une colonne_block_number/_block_offsetsuperflue. La part de projection fusionnée ne correspondait alors plus à la définition de la projection ni aux parts de projection produites par insertion, si bien queCHECK TABLEetOPTIMIZE ... DRY RUNla signalaient comme corrompue (CORRUPTED_DATA). #109284 (groeneai). - Correction de l’erreur
UNKNOWN_IDENTIFIERlors de l’exécution deALTER TABLE ... RENAME/ADD/MODIFY COLUMNsur une table MergeTree disposant d’un index min-max implicite sur les colonnes virtuelles persistantes_block_numberou_block_offset(activé paradd_minmax_index_for_block_number_column/add_minmax_index_for_block_offset_column). #109428 (groeneai). - Correction de la suppression des index de saut d’une part de données (ou de l’échec de
CHECK TABLEavecUNEXPECTED_FILE_IN_DATA_PART) après une mutation réécrivant entièrement la part, telle queALTER TABLE ... DROP COLUMNsur une colonneMATERIALIZED, appliquée à une partWide. #109616 (groeneai). - Correction d’index de saut (
text,bloom_filter, etc.) et de projections obsolètes après la matérialisation de mises à jour légères avecALTER TABLE ... APPLY PATCHES. Auparavant, les fichiers d’index et de projection dépendant d’une colonne mise à jour par patch restaient inchangés, de sorte que les requêtes qui les utilisaient pouvaient renvoyer des résultats erronés (par exemple,hasTokenomettant une ligne mise à jour, ou une projection renvoyant des agrégats obsolètes une fois la part de patch déjà appliquée supprimée). #109709 (groeneai). - Correction d’une mutation faisant référence à la colonne virtuelle
_sample_factor, qui échouait en cours d’exécution avecUnexpected const virtual column: _sample_factoret restait bloquée. Une mutation lit désormais cette colonne comme valant1, soit la valeur renvoyée par une requête sansSAMPLE. #109813 (groeneai). - Correction de deux erreurs levées lorsqu’une requête avec
GROUP BY GROUPING SETS(ou une sous-requête scalaire ou de mutation en contenant une) s’exécute avecforce_aggregation_in_order = 1:Trying to get name of not a column: ExpressionListavec l’ancien analyseur (enable_analyzer = 0), etMemory bound merging of aggregated results is not supported for grouping sets.pour une requête distribuée avecenable_memory_bound_merging_of_aggregation_results = 1sous le nouvel analyseur. #109862 (groeneai). - Correction de trois problèmes liés à
use_constant_folding_in_index_analysis: une erreur logiqueInvalid partition key sizepouvant interrompre unSELECTutilisant une projection ordinaire lorsque la table définitpart_minmax_index_columns = 'with_block_number_offset'; des résultats erronés (lignes supprimées silencieusement) pour un filtre sur une clé de partition modulo telle quePARTITION BY id % 200; et un plantage (condition de concurrence sur les données) lorsqu’un indextextdoté d’un tokenizersparseGramsest interrogé avec un prédicatLIKEsur de nombreuses partitions avecmax_threads > 1. #109896 (groeneai). - Correction de résultats erronés lorsqu’un index de saut
minmaxest construit sur une colonneLowCardinality(Nullable(...)): les prédicatsWHERE/PREWHERE/HAVING ... IS NULLtransmis au stockage éliminaient auparavant tous les granules et renvoyaient 0 ligne, alors même que la colonne contenait des valeurs NULL. #110061 (groeneai). - Correction de la lenteur des requêtes
ORDER BY ... LIMITsur les tablesDistributedlorsqueprefer_localhost_replicasélectionne une réplique locale. #110136 (EmeraldShift). - Correction d’une exception (
UNION mode UNION_DEFAULT must be normalized) lorsqu’une mutationDELETEouALTER UPDATEutilisait une opération ensembliste (UNION/UNION ALL/UNION DISTINCT/EXCEPT/INTERSECT) dans une sous-requête de sa conditionWHEREou dans une affectationUPDATE. #110196 (alexey-milovidov). - Correction de la lenteur de l’arrêt du serveur et de l’absence de réponse de
KILL MUTATIONlorsqu’une mutation avecx IN (subquery)construisait le set de la sous-requête pendant l’analyse de la clé primaire ; la construction du set est désormais annulée sans délai. #110198 (alexey-milovidov). - Correction d’une condition de concurrence entre
KILL TRANSACTIONetALTER TABLE ... UPDATE/DELETEexécuté au sein d’une transaction : un rollback survenant entre l’enregistrement de la mutation dans la transaction et son enregistrement dans la table laissait une entrée de mutation orpheline, ce qui provoquait une erreur logique (Cannot find transaction ... that has started mutation ...) dans les tâches d’arrière-plan et bloquait toutes les mutations ultérieures des parts concernées jusqu’au redémarrage du serveur. #110226 (tiandiwonder). - Correction de
system.tablespour une base de donnéesDataLakeCatalog(Iceberg/Glue) : la requête était entièrement interrompue, ou des tables disparaissaient silencieusement, dès que les métadonnées d’une seule table ne pouvaient pas être résolues. Une telle table reste désormais listée par son nom, avec des valeurs par défaut/NULL pour les colonnes nécessitant l’objet de stockage ouvert (engine,total_rows, etc.), quelle que soit la valeur dedatabase_datalake_require_metadata_access. L’accès direct à la table défaillante signale toujours l’erreur. #110242 (groeneai). - L’estimation de la cardinalité pour l’ordre des jointures agrège désormais les statistiques de colonnes sur les parts restantes après l’élagage par partition/clé primaire, plutôt que sur toutes les parts actives. Auparavant, une requête restreinte à une petite partition était planifiée à partir des statistiques de la table entière (une surestimation d’un facteur 2500 du nombre de lignes a été observée, inversant le côté de construction de la jointure par hachage), et la désactivation des statistiques produisait paradoxalement un meilleur plan. Également corrigé : le FINAL paresseux était silencieusement désactivé pour les relations MergeTree sous une JOIN, car le résultat mémoïsé de l’analyse d’index de l’optimiseur d’ordre de jointure était pris à tort pour une projection appliquée. #110283 (skuznetsov-clickhouse).
ALTER TABLE ... MOVE/REPLACE PARTITIONentre deux tables MergeTree dont les granularités sont incompatibles (l’une adaptative, l’autre non) lève désormaisBAD_ARGUMENTSau lieu deLOGICAL_ERROR. Cette situation pouvant être provoquée par l’utilisateur, elle ne doit pas se manifester comme une erreur interne (qui interrompt le serveur dans les constructions debug/sanitizer). #110535 (groeneai).- Correction d’un
TTL ... DELETE WHERE <cond>qui ne supprimait jamais les lignes devenues conformes à<cond>à la suite d’unALTER TABLE ... UPDATEsur une colonne référencée dans la clauseWHERE. La mutation recalcule désormais le TTL de ligne, de sorte que les lignes expirées nouvellement conformes sont supprimées au lieu d’être conservées silencieusement. #110648 (groeneai). - Correction d’une
LOGICAL_ERROR“Invalid partition key size: 0” susceptible d’interrompre unINSERTdans une tableMergeTreepartitionnée avecnon_replicated_deduplication_windowactivé, lorsqu’un lot d’insertion asynchrone n’était que partiellement dédupliqué (certainsinsert_deduplication_tokenétant des doublons et d’autres nouveaux). #110651 (groeneai). - Correction du constant folding avec le nouvel analyseur, qui modifiait silencieusement le type d’une valeur
Geometryconstante.Geometryest unVariantnommé dont les alternatives peuvent partager la même disposition de stockage (LineString/Ring,MultiLineString/Polygon, ainsi que les valeurs vides) ; deux constantes évaluées qui ne différaient que par leur alternative étaient donc fusionnées en une seule : par exemple, une constanteMULTIPOLYGON EMPTYdevenaitLINESTRING(). #110709 (groeneai). - Correction d’un résultat erroné (fusion mal ordonnée) pour les requêtes avec lecture ordonnée lorsque
distinct-in-orderouaggregation-in-orderétend la lecture à un préfixe de clé de tri plus long que celui pour lequelORDER BYavait configuré la virtual row de lecture ordonnée. Les colonnes de tri supplémentaires de la virtual row étaient remplies avec des valeurs par défaut, ce qui pouvait perturber l’ordre duMergingSortedTransform(et provoquer un arrêt avec uneLOGICAL_ERRORdans les builds de débogage/sanitizer). #110725 (groeneai). - Propagation des rôles actifs d’une requête (SET ROLE / role=) vers les nœuds distants lors des lectures en répliques parallèles et Distributed sur un cluster utilisant un secret interserveur ; auparavant, les rôles par défaut de l’utilisateur étaient utilisés à la place, si bien que les politiques de ligne étaient évaluées de manière incohérente par rapport à l’initiateur. #110867 (evillique).
- Correction d’une condition de concurrence rare dans laquelle un
ALTERne portant que sur un commentaire ou des paramètres d’une tableReplicatedMergeTreepouvait supprimer silencieusement une colonne ajoutée par unALTER ... ADD COLUMNconcurrent, laissant une réplique avec une structure de la table obsolète. #111029 (tiandiwonder). - Correction de l’erreur
NUMBER_OF_COLUMNS_DOESNT_MATCHpour unGROUP BYavec une agrégation sur une tableMergeencapsulant une tableDistributed, lorsque la clé de regroupement est une fonction d’une colonne et qu’une agrégation lit cette même colonne (par exempleSELECT toString(g), min(g) FROM merge_over_distributed GROUP BY toString(g)). #111334 (groeneai). - Correction d’un résultat erroné d’un
FULL JOINsur une table à moteurJoin(StorageJoin) avecUSINGlorsque la clé de gauche estNullableet que la clé de stockage ne l’est pas : une ligne de gauche sans correspondance avec une cléNULLrenvoyait0au lieu deNULL. #111371 (groeneai). ALTER TABLE ... DETACH PARTITION/PARTeffectue désormais un fsync de la copie qu’il crée sousdetached/(la sous-arborescence de la partie de données ainsi que la chaîne de répertoires jusqu’à la racine du disque) lorsque le paramètrefsync_part_directoryde la table est activé, aussi bien pour le stockage des parties de données Full (répertoire) que Packed. Auparavant, la copie n’était jamais synchronisée par fsync, contrairement à la partie de données couvrante vide qui retire les lignes de l’ensemble actif ; une coupure de courant survenant juste après l’acquittement pouvait donc détruire les données détachées sur btrfs (les entrées de répertoire non synchronisées de la copie étaient annulées, ce qui laissaitdetached/vide et ne laissait rien àATTACH). Ce comportement dépend du paramètre existantfsync_part_directory; le comportement par défaut reste inchangé. #111426 (groeneai).- Une colonne
Nullable(Nothing)(ou de tout autre type non autorisé dans les tables) est désormais rejetée dès leCREATE TABLElorsque le schéma est déduit du stockage (par exemple, une tableremote()/Remote/Distributedsans colonnes reposant sur une vue qui exécuteSELECT NULL), au lieu de persister des métadonnées dont le chargement échoue au redémarrage suivant du serveur et bloque le chargement de tables sans rapport. #111487 (groeneai). - Correction d’une
LOGICAL_ERROR(Got read request from replica N for unknown stream ...) susceptible d’interrompre le serveur lors d’une lecture avec répliques parallèles, lorsque la requête est entièrement résolue sur l’initiateur par une optimisation de projection (exact-count, minmax-count, ou projection d’agrégation ou ordinaire stockée ne sélectionnant aucune plage). #111689 (groeneai). - Correction de l’
INSERTpartitionné DeltaLake (allow_experimental_delta_lake_writes=1) qui corrompait les valeurs de partition contenant des caractères de chemin et rejetaitNULL. Une valeur commea/bétait silencieusement validée sous la formea,%produisait un fichier de données illisible, et une valeur de partitionNULLéchouait avecNOT_IMPLEMENTED. Les valeurs de partition sont désormais encodées en pourcentage (percent-encoding) dans un seul segment de chemin, la valeur réelle est stockée danspartitionValuesau lieu d’être réextraite du chemin, et une valeur de partitionNULL(ou une chaîne vide) est écrite sous la forme__HIVE_DEFAULT_PARTITION__avec une entréepartitionValuesnulle. #111793 (groeneai). - Correction des erreurs logiques
Expected UInt64 column for __grouping_set, got BLOBetColumnBLOB should be converted to a regular column before usagesurvenant lors d’une requête distribuée exécutée sur un shard avecenable_parallel_blocks_marshalling(activé par défaut), par exemple avecGROUP BY GROUPING SETSsur un cluster disposant d’une réplique locale, ou lors de la lecture d’une tableMergecouvrant une table locale et une table distribuée.BlocksMarshallingStepn’est plus ajouté aux plans dont les blocs sont consommés dans le même processus. #111997 (groeneai). - Correction d’une
LOGICAL_ERROR(Type mismatch when building statistics for column) lors d’une mutationMergeTreesur une table dont le type d’une colonne dotée de statistiques a été modifié par unALTER MODIFY COLUMNportant uniquement sur les métadonnées (par exemple,Enum8versInt8ouDateTimeversUInt32). La mutation ne recalcule désormais que les statistiques des colonnes qu’elle réécrit effectivement et conserve les autres telles quelles ; une colonne réécrite parMATERIALIZE COLUMN, par unUPDATEd’une colonne dont dépend une colonneMATERIALIZED, ou parCLEAR COLUMNvoit désormais ses statistiques recalculées au lieu de conserver un contenu obsolète. #112009 (groeneai). - Corrige la disparition silencieuse de lignes lorsqu’une requête filtre sur
intDiv(constant, key)oudivide(constant, key). L’analyse de la clé primaire et des partitions indiquait un sens de monotonie erroné pour une constante divisée par une colonne de clé : des granules correspondants étaient donc élagués et la requête renvoyait moins de lignes sans la moindre erreur. Corrige égalementintDivavec un dividende constant non signé dont le bit de poids fort est positionné, cesse de déclarer une monotonie lorsqu’un opérandeDecimalfait calculer la division dans la largeur native du décimal, et empêche l’analyse de clé de leverCannot compare DB::IPv4 with longpour une requête valide qui divise une constanteIPv4/IPv6par une colonne de clé. #112156 (groeneai). - Corrige le classement comme vue ordinaire d’une vue paramétrée dont le corps
SELECTutiliseINTERSECT/EXCEPT, ou une chaîneUNIONmêlantUNION DISTINCTetUNION ALL. Une telle vue était créée sans erreur, mais ses métadonnées ne pouvaient pas être relues : son chargement levaitInvalid storage definition in metadata file, ce qui rendait la vue définitivement impossible à charger et faisait échouer au démarrage un serveur de débogage ou instrumenté (sanitizer). Par ailleurs,system.tables.parameterized_view_parametersn’indiquait aucun paramètre pour ces vues. #112211 (groeneai). - Corrige la non-prise en compte de
max_execution_timeet deKILL QUERYpendant qu’une requête évaluegeohashesInBox. Une telle requête développait chaque ligne d’un bloc avant de pouvoir être interrompue, si bien que l’annulation ne prenait effet que plusieurs minutes plus tard ; la fonction vérifie désormais la limite de temps de la requête au fil du parcours des lignes. Les évaluations au sein d’une expression de table persistée, comme une clé de tri, un index de saut ou unPARTITION BY, ne sont pas couvertes et font l’objet d’un suivi distinct. #112273 (groeneai). - Corrige une erreur logique lorsque PREWHERE est utilisé sur une table Merge reposant sur une autre table Merge ou sur une vue matérialisée dont le type de colonne diffère. Corrige également le fait qu’une politique de ligne était ignorée silencieusement sur les tables qui lisent depuis des serveurs distants (une table Distributed, ou une table qui en encapsule une), ce qui pouvait exposer des lignes que la politique devait masquer ; ces requêtes sont désormais rejetées avec une erreur ILLEGAL_PREWHERE. Définissez plutôt ces politiques sur les tables locales sous-jacentes de chaque serveur distant ; notez qu’une telle politique n’est toujours pas appliquée aux lectures transmises avec
serialize_query_plan = 1, ce qui constitue un bogue distinct et préexistant. #112326 (PedroTadim). - Corrige la lecture d’un index secondaire (de saut) obsolète après un changement de type via
ALTER TABLE ... MODIFY COLUMNdont la mutation n’a jamais été exécutée, par exemple parce queKILL MUTATIONl’a supprimée : les granules sur disque étaient écrits avec l’ancien type mais décodés avec le nouveau, ce qui levaitLOGICAL_ERROR, provoquait des demandes d’allocation de plusieurs exaoctets ou renvoyait silencieusement un résultat erroné. Corrige également un résultat erroné renvoyé par un index portant sur une expression dont la signification change alors que chaque octet stocké reste identique, si bien qu’aucune mutation n’est créée : unMODIFY COLUMNqui ne modifie que le fuseau horaire d’unDateTime, ou uniquement un nom de type personnalisé, commeUInt8versBool. Un tel index est désormais ignoré pour la partie de données concernée. #112484 (groeneai). - Corrige une
LOGICAL_ERROR(Cannot add transform Resize to Pipes because it has no outputs) survenant lorsqu’une requête d’agrégation sur un cluster s’exécute avecserialize_query_plan = 1et des répliques parallèles basées sur le plan, l’étape de fusion redimensionnant le pipeline à zéro flux. #112506 (groeneai). - Corrige une
LOGICAL_ERROR(“Part … contains column … that is absent in table …”) survenant lorsqu’une répliqueReplicatedMergeTreeapplique une mutation à une partie de données récupérée depuis une autre réplique avant d’appliquer son propreALTER ... ADD COLUMNen attente. Une telle mutation est désormais reportée jusqu’à l’application de la modification des métadonnées. #112510 (groeneai). - Corrige les compteurs de lecture (
read_rows,read_bytes,ProfileEvents['SelectedRows'],ProfileEvents['SelectedBytes']) ainsi que les quotasREAD_ROWSetREAD_BYTES, qui étaient surfacturés pour les requêtes dont l’ORDER BYdéverse sur disque. Les lignes relues depuis les fichiers temporaires du tri externe étaient comptabilisées une seconde fois comme des lectures de la source : une requête avec déversement surestimait donc le volume lu et pouvait être rejetée avecQUOTA_EXCEEDEDalors même qu’elle respectait son quota. #112645 (groeneai). - Corrige la sous-estimation, par
ProfileEvents['JoinResultRowCount'], de la taille du résultat d’uneJOINqui déverse sur disque. Les lignes émises depuis les buckets différés n’étaient comptabilisées que dansJoinDelayedJoinedTransformRowCountet manquaient dans le total. Le résultat de la requête a toujours été correct ; seul l’événement de profil était erroné. #112673 (groeneai). - Corrige un problème qui rendait
max_execution_timeetKILL QUERYsilencieusement inopérants pour une requête distribuée en cours d’établissement de connexions vers des répliques. Une telle requête s’arrête désormais à la tentative de connexion suivante au lieu de passer par toutes les répliques et tentatives restantes. #112689 (groeneai). - Correction d’un problème qui permettait d’appliquer un
ALTERsur des tablesMergeTreealors qu’une mutationRENAME COLUMNinachevée était encore en cours. Cela pouvait modifier les métadonnées de stockage de manière incompatible et bloquer complètement les mutations ultérieures. #112783 (Michicosun). - Correction de résultats erronés d’
ORDER BYlors de la lecture d’une tableMergereposant sur des tablesDistributed: les lignes pouvaient être renvoyées dans le désordre, et des lignes censées figurer dans le résultat pouvaient manquer lorsqueLIMITétait utilisé. #112931 (alexey-milovidov). - Correction de résultats erronés lorsque le prefetch de lecture du système de fichiers est activé et qu’une colonne
Nestedest lue en même temps qu’une sous-colonne supprimée puis rajoutée, sur des tables oùshare_nested_offsetsest activé (comportement par défaut). Une telle requête pouvait renvoyer des valeurs par défaut pour une colonne physiquement présente que lesALTERn’avaient jamais modifiée. Sur le stockage d’objet, oùremote_filesystem_read_prefetchvaut1par défaut, le problème survient sans modifier aucun paramètre ; sur les disques locaux, il nécessitelocal_filesystem_read_prefetch = 1. Un autre défaut, indépendant du prefetch, corrompt encore ces lectures lorsqu’une plage s’étend sur plusieurs blocs ; il n’est pas traité ici. #112997 (groeneai). - Correction d’une erreur logique
Pipeline stuckdans les requêtes qui répartissent les données par partition, comme une window function avecPARTITION BYou une jointure avecjoin_algorithm = 'parallel_full_sorting_merge', lorsque la partie aval d’un shard se terminait alors qu’un bloc n’était que partiellement distribué. #113190 (groeneai). - Correction d’un blocage des statements
ALTER,OPTIMIZE,TRUNCATEet de manipulation de partitions avecalter_sync = 2surReplicatedMergeTreelorsque la table commence à s’arrêter pendant que le statement attend une autre réplique, par exemple en raison d’unDROP DATABASE ... SYNCconcurrent. Un tel statement échoue désormais avecUNFINISHEDet respecte égalementmax_execution_timeetKILL QUERY. #113228 (groeneai). - Correction de l’erreur
Cannot insert element into Set(NOT_IMPLEMENTED) lorsqueread_in_order_use_virtual_rowest activé et qu’une requête de lecture ordonnée surMergeTreecombineWITH FILL ... INTERPOLATEavec un filtreINouhas. #113264 (groeneai). - Correction d’une erreur logique (exception)
Chunk info was not set for chunk in MergingAggregatedTransformlorsque le paramètreinject_random_order_for_select_without_order_byest activé et qu’une requête d’agrégation lit depuis une tableMergecontenant un enfantDistributed: l’enveloppe aléatoireORDER BY rand()n’est plus injectée dans les requêtes planifiées uniquement jusqu’à une étape intermédiaire. #113266 (alexey-milovidov). - Correction d’un problème qui empêchait toute suppression de lignes lorsqu’une table
MergeTreepossède au moins deux règlesTTL ... DELETE WHEREdont l’expression temporelle est identique et qui ne diffèrent que par la conditionWHERE. Après une fusion de suppression TTL, la valeurrows_where_ttl_infode la partie de données était réinitialisée à zéro : aucune autre fusion TTL n’était donc plus jamais planifiée pour celle-ci, et les lignes expirées étaient conservées indéfiniment, sans erreur ni message de journal. #113384 (groeneai). - Correction d’un problème où
max_execution_timeetKILL QUERYétaient ignorés pendant qu’une requête évaluegeohashesInBox,arrayFold,sleep,base58Decode,h3PolygonToCellsouh3PolygonToCellsWithContainmentau sein d’une expression stockée dans les métadonnées de la table, telle qu’une clé de tri, un index de saut ou une cléPARTITION BY. #113456 (groeneai). - Correction d’une erreur
LOGICAL_ERROR(Reading from materialized CTE '...' before its materialization completed - DelayedPortsProcessor gate is missing in the query plan) levée lorsqu’une tableMergecomportant plusieurs enfants lit une CTE matérialisée référencée par la requête externe. #113558 (alexey-milovidov). - Correction de l’erreur
Logical error: 'Required output position N is out of range for pass-through inputs'dansEXPLAIN ANALYZEsur une tableMergecomportant plusieurs enfants, avec unPREWHEREportant sur une simple colonne et unWHEREdistinct. #113725 (groeneai). - Correction d’une erreur logique (
Unexpected return type) lorsqu’un filtre sur une vue dont le type de colonne diffère de celui du stockage sous-jacent (par exempleinformation_schema.tables, oùengineest de typeNullable(String), construite sursystem.tables, où il est de typeString) est poussé vers le stockage. #113984 (alexey-milovidov). - Correction de l’erreur
Not-ready Set is passed as the second argument for function 'in'lorsqu’une mutation dont le prédicat contientIN (subquery)est annulée, par exemple viaKILL MUTATIONouDETACH DATABASE, alors que le set de la sous-requête est encore en cours de construction. #114463 (groeneai). ALTER TABLE ... DROP COLUMNsur une colonne utilisée dans la clé de tri, la clé primaire ou la clé de partition échoue désormais avecALTER_OF_COLUMN_IS_FORBIDDENaccompagné d’une explication, comme c’est déjà le cas pourALTER TABLE ... CLEAR COLUMN. Auparavant, l’opération échouait avec une erreur déroutanteUNKNOWN_IDENTIFIER: Missing columnsissue du recalcul des expressions de clé. Il en va de même pour la suppression ou l’effacement d’un groupeNestedentier via son préfixe commun lorsqu’une colonne du groupe est utilisée dans une clé ; auparavant, cela pouvait détruire silencieusement les données du groupe ou laisser une mutation qui ne se terminait jamais. La suppression d’une colonne utilisée uniquement dans une expressionTTLindique désormais également quelle expression TTL elle invalide #114468 (m7kss1).- Correction d’un problème où une colonne renommée, supprimée puis ajoutée à nouveau dans un même
ALTERrenvoyait les valeurs de la colonne supprimée au lieu de sa propre valeur par défaut tant que la mutation était en attente. #114601 (tiandiwonder). - Correction de la lecture d’une sous-colonne (
.size0,.null, un élément de tuple,String.size) via une tableMergelorsque la table sous-jacente déclare la colonne parente commeALIAS. Une telle lecture renvoyait la valeur par défaut du type et, lorsque la colonne parente était sélectionnée dans la même requête, elle pouvait renvoyer la valeur d’une colonne sans aucun rapport. #114673 (groeneai). - Correction de lignes manquantes dans le résultat d’un
SELECTfiltré parpointInPolygonsur une clé primaire MergeTree lorsque l’argument polygone est un littéral constant invalide et quevalidate_polygons = 0. L’analyse de la clé primaire déduisait l’élagage des granules d’un polygone qu’elle n’avait jamais validé, et écartait ainsi des granules contenant des lignes correspondantes. #114710 (groeneai). - Correction du formatage de
ALTER TABLE ... MATERIALIZE INDEX,MATERIALIZE STATISTICSetMATERIALIZE PROJECTION, qui omettait la clauseIF EXISTS: la requête formatée ne correspondait donc pas à la requête analysée. Sont également rejetées quatre charges utiles JSON d’ASTALTER ... STATISTICSque l’analyseur SQL ne peut pas produire et dont le formatage donnait une commande différente. #115099 (groeneai). - Correction d’une lecture hors limites des hachages de dictionnaire mis en cache lors d’une agrégation ou d’une jointure sur une clé
LowCardinality(String)dont le dictionnaire grossit en cours d’agrégation, situation pouvant se produire viaTTL ... GROUP BY. Cela pouvait produire un hachage erroné, ainsi qu’un heap-buffer-overflow signalé dans les constructions avec sanitizer. #115604 (groeneai). CREATE TABLEetALTER TABLErejettent désormais les codecs avec perte, tels queSZ3, sur une colonne utilisée dans la clé de partitionnement. #115626 (groeneai).- La lecture via une table
Mergecorrespondant à une tableAliasdont la cible est une vue paramétrée ne déclenche plusLOGICAL_ERROR: Table has no columns.(qui provoque l’arrêt du serveur dans les constructions de débogage et avec sanitizer). Une telle table signale désormaisSTORAGE_REQUIRES_PARAMETER, soit la même erreur que la vue paramétrée elle-même. Toute autre table correspondante incapable de fournir des colonnes signale désormaisUNSUPPORTED_METHODau lieu d’une erreur interne. #115896 (groeneai). - Correction de l’aperçu à la volée d’une mutation en attente dont l’expression fait référence à
_sample_factor. Avecapply_mutations_on_fly = 1et une clauseSAMPLE, l’expression était évaluée avec le facteur d’échantillonnage de la requête de lecture au lieu de la valeur persistée par la matérialisation en arrière-plan. Les lignes prévisualisées différaient donc du résultat matérialisé final, et unALTER TABLE t DELETE WHERE _sample_factor > 1en attente pouvait amener une lectureSAMPLEà ne renvoyer aucune ligne. La colonne_sample_factorpropre à la requête reste inchangée. #115906 (groeneai). - Les fichiers de statistiques dont la version de format est
V3sont désormais lus au lieu d’être rejetés avecILLEGAL_STATISTICS. Ces fichiers n’ont été produits que par des constructions demastersur une courte période, mais les parties de données qui les contenaient étaient totalement illisibles et, sur un disque en lecture seule,ALTER TABLE ... MATERIALIZE STATISTICSne peut pas les régénérer. #116030 (alexey-milovidov). - Correction de l’erreur
Invalid number of columns in chunk pushed to OutputPort(LOGICAL_ERROR) lorsqu’une requêteSELECT ... FROM t STREAM ... ORDER BY ... LIMIT nlisait une table comportant unePROJECTION. La matérialisation différée n’est plus appliquée aux lecturesSTREAM. #116187 (groeneai). ALTER TABLE ATTACH PARTITION FROMn’est plus répliqué pour les bases de données répliquées. #94835 (MikhailBurdukov).- Correction d’un arrêt brutal du serveur (dans les builds avec sanitizer) et d’une perte silencieuse de données au démarrage d’une table lorsqu’une part MergeTree transactionnelle annulée (rolled back) chevauche une part validée (committed).
PartLoadingTree::addidentifie désormais correctement laquelle des deux parts qui se chevauchent a été annulée, l’évince et rattache ses enfants orphelins à la part validée, dans le bon ordre. #100992 (tuanpach). - Correction de
indexOfAssumeSorted, qui renvoyait des résultats incorrects pour les colonnesArray(LowCardinality(String))dans les tables MergeTree. #101771 (Onyx2406). - Correction d’exceptions
LOGICAL_ERRORlors de la lecture de tables de data lakeIcebergouDeltaLakevia des chemins susceptibles d’atteindre le pipeline de lecture sansdatalake_table_stateépinglé, par exemple lors de mises à jour concurrentes des métadonnéesIcebergou de lecturesmergesur des tablesDeltaLake. #102033 (groeneai). - Correction de l’erreur
Logical error: Parsed partition value: ... doesn't match partition value for an existing part with the same partition ID: ...levée parOPTIMIZE TABLE ... PARTITION ...(et par d’autres requêtes qui résolvent une valeur de partition viaconvertFieldToTypeImpl) sur les tables dont la clé de partition est de typeTime. #106202 (groeneai). - Correction d’un problème qui faisait marquer à tort une part de données comme ayant une projection corrompue lorsqu’un lightweight delete ne laissait aucune part de projection — soit parce que la projection était reconstruite sans aucune ligne en sortie, soit parce qu’elle était supprimée (
lightweight_mutation_projection_mode = 'rebuild'/'drop'). Cet état corrompu désactivait jusqu’ici l’optimisation par projection pour les requêtes portant sur cette part. #106273 (tiandiwonder). - Correction des avertissements de surcharge mémoire/CPU/mutations dans
system.warnings, qui accusaient un cycle de retard sur les métriques asynchrones (et étaient absents lors du premier cycle). #108035 (alexey-milovidov). - Correction d’une exception
LOGICAL_ERROR(ScatterExchangeStep should have one source shard, got 8) et de lignes dupliquées lors de l’interrogation d’une tableMergereposant sur des tablesDistributedou des vues avec le paramètre expérimentalmake_distributed_plan = 1. #108401 (groeneai). - Correction d’un arrêt brutal du serveur (
Sort order of blocks violated) pendant une fusion, ainsi que de lectures incorrectes, lorsqu’un élémentLowCardinalitynon nullable d’une colonneNullable(Tuple(...))est utilisé comme sous-colonne (par exemple comme clé de tri). #108679 (groeneai). - Correction d’un crash dans la fonction
Base64Decodedu SDK Azure intégré, déclenchable viaazureBlobStorage()(et les fonctions de table/stockages Azure associés) lorsque la clé du compte n’est pas un Base64 valide. Un octet>= 0x80provoquait une lecture hors limites de la table de décodage, et tout octet invalide entraînait un décalage à gauche indéfini d’une valeur négative (arrêt brutal sous sanitizers). Les clés invalides sont désormais rejetées proprement. #108716 (groeneai). - Correction d’une erreur
LOGICAL_ERROR(“New empty part is about to materialize but the directory already exist”) susceptible d’arrêter brutalement le serveur dans les builds de débogage et avec sanitizer lorsqu’une opérationDROP/DETACH/MOVE/REPLACE PARTITIONsur une table MergeTree s’exécutait après l’interruption d’une opération similaire antérieure (par exemple une transaction annulée ou un crash) ayant laissé derrière elle un répertoire obsolètetmp_empty_<part>. Ce répertoire obsolète est désormais réutilisé au lieu de provoquer un échec. #108879 (groeneai). - Correction d’une projection qui renvoyait la valeur par défaut du type d’une colonne (par ex.
0) au lieu de sonDEFAULTdéfini dans le DDL (par ex.-1) après l’expiration duTTLde la colonne sur une part au format large. #109013 (tiandiwonder). - Correction de l’échec des requêtes
ALTERsur les tablesMergeTreecréées avec un paramètrediskpersonnalisé (SETTINGS disk = disk(...)). #109199 (Michicosun). - Correction de l’apparition de lignes obsolètes et supprimées lors de la lecture des tables d’une base de données
MaterializedPostgreSQLvia une tableMerge. #109339 (vdimir). - Correction de la lecture des tables Paimon partitionnées par une colonne
BIGINTdont la valeur ne tient pas dans unInt32. Ces valeurs de partition étaient tronquées (par exemple,9223372036854775807devenait-1), ce qui produisait un chemin de partition erroné et entraînait une erreur du système de fichiers. #109510 (groeneai). - Correction d’une erreur logique (“Cannot determine row level filter; 0 columns deleted, 0 columns added”) lors de la lecture d’une table
Mergedont une table enfant possède une politique de ligne dont le filtre se réduit à une colonne existante (par exemple,CREATE ROW POLICY ... USING flag). #109843 (groeneai). - IcebergLocal indiquait à tort Azure comme type de stockage. #109872 (PedroTadim).
CHECK TABLEsignale désormais la corruption réelle d’une part de projection dont le chargement des métadonnées a échoué, au lieu d’une erreur trompeuseColumns doesn't match ... Expected: 0 columns. #110262 (Algunenano).- Correction de l’échec du démarrage du serveur pour les tables
MergeTreesur des disques de stockage d’objet lorsqu’un fichier résidueltxn_version.txt.tmpprésente des métadonnées corrompues au niveau du disque. #110519 (alexey-milovidov). - Correction d’un problème qui empêchait définitivement de rattacher une table MergeTree comportant une projection
_part_offsetou d’ordre de commit lorsqueallow_part_offset_column_in_projectionsouallow_commit_order_projectionavait été désactivé, puis que la table avait été détachée ou le serveur redémarré. Ces deux paramètres ne s’appliquent qu’au moment du CREATE et ne sont donc plus revérifiés lors de l’ATTACH. #110570 (groeneai). - Correction d’une
LOGICAL_ERRORrare (“Unexpected number of parts to remove from parts_queue”) susceptible d’interrompre le serveur sur une tableReplicatedMergeTreelorsque deux opérations sur des partitions (par exemple, deux requêtesMOVE PARTITION/REPLACE PARTITION, ou l’une d’elles en concurrence avec unDROP_RANGEen arrière-plan) annulaient simultanément la vérification en arrière-plan des parts sur des plages qui se chevauchent. #110738 (groeneai). - Correction d’une erreur logique
Hash is not set for serializationpouvant survenir lorsqu’une colonne utilisant un codecQuantized(...)était imbriquée dans une sérialisation poolable, par exemple une tableMergeportant sur des sources dont la colonne de même nom a des types différents (fusionnés en unVariant). #110776 (groeneai). - Correction d’une
std::length_error(LOGICAL_ERROR) lors de la lecture d’une table MergeTree avec une valeur aberrante demax_streams_for_merge_tree_reading(proche du maximum deUInt64) combinée àallow_asynchronous_read_from_io_pool_for_merge_tree = 1. Ce paramètre est désormais plafonné à la même limite quemax_threads. #110936 (groeneai). - Correction d’une erreur logique
Cannot calculate columns sizes when columns or checksums are not initializedlors de la fusion d’une tableMergeTreeà colonne unique dont la seule colonne possède unTTLde colonne expirant entièrement (avecmin_bytes_for_wide_part = 1). #111169 (groeneai). - Les fichiers d’index de texte d’une part fusionnée ou matérialisée sont désormais synchronisés via fsync lorsque
min_rows_to_fsync_after_merge/min_compressed_bytes_to_fsync_after_merge/fsync_part_directorysont définis. Auparavant, ces fichiers étaient les seuls de la part à ne pas être synchronisés : une coupure de courant juste après une fusion pouvait donc laisser une part validée mais corrompue et entraîner une perte de données. #111335 (groeneai). - Correction de
OPTIMIZE TABLE ... MANIFESTpour les tablesIceberglorsque les tuples de partition du manifest ne correspondent pas à leur spécification de partition #111368 (SmitaRKulkarni). - Correction d’une lecture hors limites (en release) / erreur logique (en debug) dans l’optimisation de matérialisation paresseuse, ainsi que d’une erreur logique dans
Pipe::unitePipespour les tablesMerge, lorsque l’optimisation de lecture directe depuis l’index de texte laisse une colonne virtuelle d’index inutilisée dans l’en-tête de lecture d’une tableMergeTreecomportant plusieurs indextext. #111467 (groeneai). - Correction d’une
LOGICAL_ERROR(“Part level Min-Max index was constructed from unexpected columns set”) susceptible d’interrompre une fusion en arrière-plan dans les constructions debug/sanitizer après l’abaissement depart_minmax_index_columns(par exemple dewith_block_number_offsetàpartition_key_only). #111511 (groeneai). - Correction d’un plantage lors de l’exécution d’une lecture
STREAM(enable_streaming_queries = 1) sur une table comportant plus d’une partition et dotée d’une politique de lignes. Dans les constructions debug et sanitizer, l’opération échouait avec l’erreur logiqueFilter column ... not found in DAG outputs; dans les constructions release, elle pouvait provoquer une erreur de segmentation. #111572 (groeneai). - Correction d’une
LOGICAL_ERROR(Cannot create part with type Compact and storage type Full because table does not support polymorphic parts) levée lorsqu’une tableMergeTreecharge une partCompactpréexistante alors que ses paramètres actuels désactivent les parts polymorphes (granularité non adaptative). Cela pouvait se produire, par exemple, lorsqu’une table en lecture seule partage un chemin sur disque avec une autre table et recharge ses parts viaSYSTEM RESTART DISKou au démarrage du serveur. Dans les constructions debug et sanitizer, l’exception provoque l’arrêt brutal du serveur. #111626 (groeneai). - Avec
fsync_part_directory = 1, le renommage d’un répertoire de part de son nom temporaire vers son nom définitif est désormais lui-même rendu durable par un fsync du répertoire parent (et, pour les déplacements entre parents différents, également du parent source). Auparavant, seul le répertoire déplacé était synchronisé : une coupure de courant juste après la validation d’une part pouvait donc faire disparaître cette part du disque alors que ses fichiers étaient déjà écrits, entraînant la perte de lignes malgré l’activation du paramètre. #111861 (groeneai). - Correction de résultats erronés et d’une
LOGICAL_ERRORlorsqu’une colonneNullable(Tuple(...))est sélectionnée en même temps que l’une de ses sous-colonnes d’élément pouvant contenir des NULL (Variant,DynamicouLowCardinality) depuis une tableMergeTree. La lecture de la sous-colonne marquait les lignesNULLdans le tuple parent commeNULLdans une colonne déjà partagée via le cache des sous-flux, si bien que la lecture de la colonne entière renvoyait des valeurs décalées. #111949 (groeneai). - Correction des jointures par hachage qui perdaient leurs optimisations post-construction (conversion en table de hachage fixe, runtime filter partagé, réordonnancement de la table de droite) dès qu’un seuil de déversement automatique sur disque était configuré, ce qui est le cas par défaut depuis la version 26.5. #111972 (alexey-milovidov).
- Correction de résultats erronés (lignes manquantes sans avertissement) pour
hasAllTokenset les autres recherches multi-jetons sur l’indextextdans les builds qui n’utilisent passimdcomp(toutes les cibles sauf Linux x86_64, par exemple aarch64) lorsquetext_index_posting_list_apply_mode = 'lazy'. Le décodeur de bitpacking portable n’écrivait pas les zéros décodés pour un bloc dont la largeur en bits est nulle, si bien qu’une entrée de liste de postings située dans un segment à entrée unique était ignorée. Le format sur disque reste inchangé et les données existantes sont correctement lues après la correction. #112178 (groeneai). - Les opérations échouent désormais lors du chargement de statistiques MergeTree corrompues, au lieu d’ignorer l’erreur. #112201 (skuznetsov-clickhouse).
- Correction de la perte silencieuse d’écritures Iceberg acquittées sur HDFS : un commit Iceberg publie chaque nouveau fichier de métadonnées au moyen d’une écriture conditionnelle, mais
HDFSObjectStorageignorait la condition et effectuait un simple écrasement, de sorte que tous les rédacteurs concurrents étaient acquittés alors que l’instantané de l’un d’eux devenait inaccessible. HDFS refuse désormais les écritures conditionnelles ; les écritures Iceberg gérées par le stockage sur HDFS, y comprisCREATE TABLE ... ENGINE = IcebergHDFS(...)avec une liste de colonnes explicite, échouent donc désormais. Les lectures ne sont pas affectées. #112437 (groeneai). - Correction de
DELETEsur les tablesKeeperMap, qui ne supprimait que lesmax_block_sizepremières lignes correspondantes tout en signalant la mutation comme terminée avec succès. Correction également du manque d’atomicité deDELETEaveckeeper_map_strict_mode = 1: l’opération pouvait basculer vers des suppressions non versionnées et supprimer des lignes mises à jour simultanément, et elle appliquait les lignes correspondantes bloc par bloc, si bien qu’un conflit pouvait laisser la suppression partiellement appliquée. #112777 (alexey-milovidov). - Correction d’une erreur transitoire d’Azure Blob Storage sur le chemin de lecture ou de fusion — un
403 Forbiddenlié à la propagation des autorisations RBAC, un échec d’authentification des identifiants ou un délai de connexion dépassé remonté sous forme de408— qui était classée à tort comme ne pouvant pas donner lieu à un réessai et signalée commePOTENTIALLY_BROKEN_DATA_PART(Code 740), déclenchant une fausse alerte critique pour une partie de données pourtant saine. Ces échecs transitoires sont désormais considérés comme pouvant donner lieu à un réessai, et un échec réellement persistant remonte sous la forme d’une simple erreur Azure plutôt que d’une partie de données prétendument endommagée. #112871 (arsenmuk). - Correction de
listObjectssur un disque Azure Blob Storage avec endpoint préfixé, qui renvoyait des noms de blob erronés sur toutes les pages suivant la première, car la pagination contournait le wrapper client chargé de retirer le préfixe de l’endpoint. La pagination repasse désormais par le wrapper via le jeton de continuation, de sorte que les noms de blob sont corrects sur chaque page. #112872 (arsenmuk). - Correction de la perte, après un rechargement de la table, de l’index minmax par partie de données sur
_block_numberet_block_offsetlorsque la partie avait été produite par une mutation qui ne réécrit pas la partie entière. #112878 (alexey-milovidov). - Correction d’une exception (dans les builds de production, une erreur empêchant le démarrage du serveur) lorsqu’un prédicat de mutation utilise la fonction de table
mergesans nom de base de données explicite. La base de données de la table mutée est désormais utilisée, comme c’est déjà le cas pour les noms de table. #113185 (alexey-milovidov). - Correction de résultats erronés et d’une erreur
LOGICAL_ERRORlors de la lecture d’une sous-colonne d’un membreNestedsupprimé puis rajouté, conjointement avec un membre présent du même groupe, sur une tableMergeTreeavecshare_nested_offsets = 1. Les membres présents renvoyaient des valeurs provenant d’un bloc ultérieur dès que la lecture couvrait plus d’un bloc. #113225 (groeneai). - Correction d’une exception arithmétique dans les builds de débogage et avec sanitizers lors de la lecture d’une table
Mergeavec une valeur très élevée demax_streams_to_max_threads_ratio: le nombre de flux était tronqué à 32 bits, de sorte que les multiples de2^32devenaient nuls. Une erreurPARAMETER_OUT_OF_BOUNDest désormais levée au lieu de provoquer un comportement indéfini lorsque la multiplication du nombre de flux pour une tableMergedépassesize_t. Un dépassement est également évité lors de la limitation du nombre de fluxMergeTreeen fonction du volume de données, et toute lecture de tableMergedont le nombre total de sources dépasserait 65536 est désormais rejetée. #113382 (alexey-milovidov). - Correction des écritures sur le disque
hdfs: elles échouaient avecParent directory doesn't exist, car les clés d’objet générées contiennent un préfixe de répertoire imbriqué ; or, contrairement aux stockages blob, HDFS possède de véritables répertoires et ne crée pas le répertoire parent manquant lors de la création d’un fichier. #113396 (alexey-milovidov). - Correction de l’erreur signalée lorsque les fonctions de table
remote/remoteSecureou les moteurs de tableRemote/RemoteSecurereçoivent une collection nommée inexistante accompagnée d’une surchargekey = value. Un tel appel était silencieusement réanalysé comme un appel positionnel : la surcharge était alors interprétée comme une expression de données, et l’erreur signalée portait sur un élément sans rapport (par exemple Function with namemergedoes not exist pourremote(collection, database = merge(...))). C’est désormais l’absence de la collection nommée qui est signalée. #113510 (groeneai). - Correction d’une boucle infinie dans les fusions en arrière-plan et
OPTIMIZElorsquemerge_max_block_size_bytesétait défini en dessous dubyteSize()d’une colonne vide. Une colonneLowCardinalityvide contient toujours son dictionnaire : la limite en octets pouvait donc être atteinte avant même la fusion d’une seule ligne ; la fusion produisait alors indéfiniment des blocs vides, consommant 100 % d’un cœur CPU sans jamais libérer son emplacement dans le pool d’arrière-plan. #113585 (groeneai). - Correction d’une mutation d’une part Compact qui produisait un résultat différent selon que les informations de sérialisation de la part étaient encore en mémoire ou avaient été rechargées depuis
serialization.json, lorsque la table utiliseserialization_info_version = 'basic'. AvecReplicatedMergeTree, deux répliques détenant une part source identique octet par octet écrivaient ainsi des parts mutées différentes, et la mutation échouait avecCHECKSUM_DOESNT_MATCH. #113588 (groeneai). - Les sauvegardes signalent désormais l’erreur sous-jacente d’accès au fichier de verrou, au lieu d’indiquer à tort une sauvegarde concurrente, lorsque le stockage de destination ne parvient pas à lire le fichier .lock. #113637 (kirillshokhin).
- Correction d’une condition de concurrence entre les tâches en arrière-plan d’une table
MergeTree(rafraîchissement des statistiques, rafraîchissement des parts, chargement des parts obsolètes/inattendues) et la destruction de la table. #113722 (alexey-milovidov). - Correction de
UPDATEet duDELETEléger, qui lisaient les mauvaises tables lorsque la base de données de la table mise à jour différait de celle de la session. L’expression de la mutation est désormais canonicalisée par rapport à la base de données de la table mise à jour, aussi bien pour la fonction de tablemerge, qui utilise implicitement la base de données courante, que pour les identifiants de table non qualifiés. Auparavant, ces noms étaient résolus par rapport à la base de données de la session, si bien que l’instruction mettait à jour ou supprimait silencieusement des lignes sélectionnées dans une autre table. #113748 (groeneai). - Correction d’une exception lors de la lecture d’une table
MergeTreepar couches de plages de clé primaire lorsqu’une couche produit un pipe vide. #114177 (alexey-milovidov). BACKUP,RESTOREetENGINE = Backupvérifient désormais l’emplacement de la sauvegarde par rapport aux privilègesSOURCESde l’utilisateur, comme le fonts3(),file()etazureBlobStorage(). Auparavant, un utilisateur disposant deBACKUPmais pas deSOURCESpouvait écrire une sauvegarde vers n’importe quel emplacement accessible au serveur, ou en lire une depuis cet emplacement. L’écriture d’une sauvegarde nécessite désormais la directionWRITEsur la source de la destination (WRITE ON S3,WRITE ON AZURE,WRITE ON FILE) et sa lecture nécessiteREAD; les destinationsDisk(...)restent limitées uniquement parbackups.allowed_disk. #114405 (groeneai).- Correction de la lecture d’une table pendant qu’une mutation est en cours : une colonne
MATERIALIZEDpouvait renvoyer une valeur obsolète, et la sélectionner conjointement avec une colonne mise à jour pouvait provoquer une erreur. #114561 (tiandiwonder). - Correction d’une erreur logique (
Block structure mismatch) lors de la lecture d’une tableMergeavecmake_distributed_planactivé, lorsque les tables enfants comportent des opérations ensemblistes internes. #114753 (alexey-milovidov). OPTIMIZE TABLEsur une table de stockage objet dont le moteur n’implémente pas la compaction signalait un succès sans rien faire. Une erreur est désormais levée, comme pour tout autre moteur ne prenant pas en charge cette instruction. Cela concerneDeltaLake,Paimon,Hudiet les moteurs de stockage objet simples (S3,GCS,COSN,OSS,AzureBlobStorage,HDFSetURLadossé à un stockage objet) ;Iceberg, qui implémente bien la compaction, n’est pas concerné. #114805 (groeneai).- Correction de l’erreur
BAD_DATA_PART_NAME(« Trying to get part name in new format for old format version ») sur une tableReplicatedMergeTreecréée avec la syntaxe positionnelle obsolète viaallow_deprecated_syntax_for_merge_tree. Une mutation pouvait être signalée comme terminée sur une réplique qui ne l’avait pas appliquée, et la table pouvait rester en lecture seule après un redémarrage. #114980 (groeneai). - Correction de l’erreur
Found patch part ... that intersects mutation with version ...(LOGICAL_ERROR) sur les tables utilisant la mise à jour légère. Une fusion de patch parts pouvait produire un patch dont la plage de versions de données englobait la version de données d’une partie de données existante ; ce patch ne pouvait alors être ni appliqué ni ignoré, si bien que toute opération ultérieure sur la partition échouait et que la file d’attente de réplication se bloquait. De telles fusions ne sont plus planifiées. #115064 (alexey-milovidov). - Correction de l’échec du démarrage du serveur lorsqu’un moteur de base de données
Backupfait référence à une sauvegarde devenue indisponible (par exemple, lorsque ses fichiers ont été supprimés ou que le stockage sous-jacent est inaccessible). La base de données est désormais chargée sans tables au lieu d’empêcher le démarrage de l’ensemble du serveur. #83188 (orloffv). - Correction de la reprise de la journalisation après une erreur de disque plein. Auparavant, lorsque le disque des journaux était plein, ClickHouse passait dans un état d’échec et inondait continuellement syslog de messages d’erreur (jusqu’à plus de 100 Go par heure), sans jamais se rétablir, même après la libération d’espace disque. Désormais, le système de journalisation se rétablit automatiquement dès que de l’espace disque redevient disponible, sans qu’un redémarrage du serveur soit nécessaire. #93127 (jaehanbyun).
- Correction d’un plantage dans le visiteur de schéma du stockage DeltaLake. #97112 (kssenii).
Corrections relatives aux lacs de données et au stockage externe
- Correction d’un échec transitoire
Code: 499 ... InvalidPart(S3_ERROR) lors des téléversements multipart S3 (par exempleINSERT INTO ... hits_s3). MinIO peut brièvement signaler comme manquante une partie de données tout juste téléversée lors deCompleteMultipartUploadᅠ; cette erreur donne désormais lieu à de nouvelles tentatives, comme l’erreurNoSuchKeydéjà prise en charge, dans la limite fixée pars3_max_unexpected_write_error_retries. #109364 (groeneai). - Les requêtes
ALTER TABLE ... DELETEetALTER TABLE ... UPDATEsur les tables Iceberg dont le format de fichier de données n’est pasParquetsont désormais rejetées avec une erreur expliciteNOT_IMPLEMENTED, au lieu de faire planter le serveur ou de corrompre silencieusement la table. #105893 (groeneai). - Correction de l’erreur
Cannot add column ...: column with this name already existslors d’unINSERT SELECTdepuis une fonction de table telle quefile,s3ouinput, lorsque la même colonne source est sélectionnée plusieurs fois. #105982 (crakjie). - Les valeurs sensibles transmises comme paramètres de chaîne de requête HTTP (par exemple via la liaison de paramètres de requête
param_*, commeparam_secret_key/param_aws_secret_access_key, le paramètrepasswordou les paramètressignaturede type S3) ne sont plus écrites en clair danssystem.text_logni dans les spans OpenTelemetry. La ligne de journalRequest URImasque désormais les valeurs des paramètres dont le nom semble sensible, en les remplaçant par[HIDDEN]. #108475 (groeneai). - Correction de la colonne virtuelle
_etagpour les moteurs de tableS3QueueetAzureQueueᅠ: elle était déclarée mais jamais renseignée, si bien queSELECT _etagrenvoyait toujours une chaîne vide. Elle renvoie désormais l’ETag de l’objet, comme le moteurS3et la fonction de tables3(). #108625 (groeneai). - Une requête de lecture ou d’écriture sur S3 annulée (par exemple via
KILL QUERY) pendant qu’une requête S3 est en cours est désormais signalée comme annulée, et non plus par une erreur réseau/S3 trompeuse. En particulier, une sauvegarde ou une restauration vers S3 annulée indique désormaisBACKUP_CANCELLED/RESTORE_CANCELLEDdanssystem.backups. #108673 (jkartseva). - Correction de la colonne virtuelle
_tagspour le moteur de tableS3Queueᅠ: elle était déclarée mais jamais renseignée, si bien queSELECT _tagsrenvoyait toujours une map vide. Elle renvoie désormais les balises de l’objet, comme le moteurS3et la fonction de tables3(). #108676 (groeneai). - Correction de SHOW TABLES et SELECT … FROM system.tables, qui renvoyaient des résultats différents pour les bases de données de catalogue de data lakeᅠ: les tables que ClickHouse ne peut pas lire sont désormais masquées de manière cohérente dans les deux cas. #109273 (SmitaRKulkarni).
- Correction d’un arrêt brutal du serveur (ou, dans les builds release, d’un fichier de données silencieusement non finalisé) lorsqu’un
INSERTdans une table Delta Lake (DeltaLakeLocal/deltaLake) échoue alors que le sink a déjà commencé à écrire, par exemple lorsque la requête source lève une exception en cours d’insertion ou que la requête est annulée. #109328 (groeneai). - Correction de
Not found column or subcolumn c.null in block(et deBad cast from ColumnConst to ColumnNullabledans les builds debug/sanitizer) lors de l’exécution deWHERE col IS NULL/IS NOT NULLsur une colonne Iceberg ajoutée par évolution de schéma après l’écriture de fichiers de données plus anciens, avecoptimize_functions_to_subcolumns=1(valeur par défaut). #109515 (groeneai). - Correction de l’erreur
Host is empty in S3 URIlorsqu’une sous-requête scalaire est utilisée comme argument URL de la fonction de tables3(ou comme argument de toute autre fonction de table) dans des requêtesCREATE TABLE ... AS SELECT: les sous-requêtes scalaires figurant dans les arguments des fonctions de table sont désormais évaluées lors de l’analyse de requêtes. #110254 (CheSema). - Correction d’une erreur logique (arrêt du serveur dans les builds debug/sanitizer) lorsqu’un
ALTERmulti-commandes tel queUPDATE ..., DELETE ...était exécuté sur une table Iceberg. Ce type de mutation est désormais rejeté avec une erreurNOT_IMPLEMENTEDexplicite. #110347 (groeneai). - Correction d’un problème où les tables Iceberg produisaient des ID de champ en double après
ALTER TABLE ... ADD COLUMNlorsque le schéma initial contenait des champs imbriqués (Tuple/Array/Map).last-column-idenregistre désormais l’ID de champ maximal attribué, enfants imbriqués compris : une colonne ajoutée ultérieurement ne réutilise donc plus l’ID d’un champ imbriqué, et les lectures n’échouent plus avecICEBERG_SPECIFICATION_VIOLATION(Duplicate field id). #110884 (groeneai). - Correction d’un problème où
DELETE/UPDATEsur une table Iceberg supprimait silencieusement les mauvaises lignes (ou levaitNOT_FOUND_COLUMN_IN_BLOCK) lorsque la table contenait des fichiers de données écrits à la fois avant et aprèsALTER TABLE ... ADD COLUMNet queoptimize_move_to_prewhereétait activé. #111693 (groeneai). - Correction de
made_current_atdanssystem.iceberg_history, qui prenait la valeur1970-01-01pour un snapshot conservé aprèsALTER TABLE ... EXECUTE expire_snapshotssur une table Iceberg. Correction également desystem.iceberg_history, qui ne renvoyait aucune ligne pour une table dont les métadonnées ne contiennent pas desnapshot-log. #111781 (groeneai). - Correction d’une corruption de données lors de l’insertion dans une table Iceberg via une
MATERIALIZED VIEW. Le fichier de données était écrit selon les types de colonnes de la cible définis au moment duCREATE, et non selon son schéma Iceberg actuel : une valeurDateTimeétait ainsi stockée comme un simpleintAvro et relue comme des microsecondes, tandis qu’avecDateTime64(0)ouDateTime64(9), le fichier devenait totalement illisible. En conséquence,INSERT INTO <materialized view>vers une cible dont le schéma Iceberg est plus large que les colonnes déclarées de la vue lève désormaisTYPE_MISMATCHau lieu d’écrire une ligne corrompue. #112359 (groeneai). - Correction de l’écriture des tables Iceberg dont le schéma contient un tuple imbriqué dans un autre tuple. Les métadonnées de table publiées remplaçaient les noms de champs du tuple interne par des noms positionnels
1,2, … : avec le format par défautParquet, l’INSERTéchouait avecINCORRECT_DATA, et avecAvro, la colonne ne pouvait pas être relue. #112480 (groeneai). - Correction d’un interblocage qui bloquait définitivement une base de données
FilesystemouHDFSlorsque deux requêtes résolvaient simultanément le même nom de table. Toute requête ultérieure sur cette base de données restait alors bloquée indéfiniment, sans pouvoir être interrompue, et seul un redémarrage du serveur permettait d’en sortir. #112495 (groeneai). - Correction d’un problème où les tables
DeltaLakerenvoyaient trop peu de lignes lorsque le prédicatWHEREcontenait, sous unNOT, une sous-expression que le traducteur de prédicats de delta-kernel ne sait pas traiter. Une telle sous-expression est désormais signalée à delta-kernel comme un prédicat inconnu explicite, et non plus comme la fin de l’itérateur enfant, ce qui avait pour effet de tronquer silencieusement la conjonction englobante. #112652 (groeneai). - Correction de
ALTER TABLE ... EXECUTE remove_orphan_files, qui supprimait un fichiermetadata/version-hint.textactif d’une table Iceberg. Son entrée dans l’ensemble des fichiers joignables était construite par concaténation de strings en supposant une barre oblique finale sur une valeur qui n’en comporte jamais : le véritable fichier d’indice n’était donc jamais reconnu comme joignable et était supprimé dès qu’il dépassait le seuilolder_than. Aveciceberg_use_version_hint = 1, la table devenait alors totalement illisible. #113548 (groeneai). - Correction d’une erreur
LOGICAL_ERRORlors du filtrage d’une colonne Iceberg rendueNullableparALTER TABLE ... MODIFY COLUMN. #114521 (groeneai). - Correction d’un cas où
ATTACH TABLEavec une définitionENGINE = URL(...)ne vérifiait pas le privilègeTABLE ENGINEdu moteur vers lequel le schéma d’URL route la requête. Un utilisateur ne disposant que deTABLE ENGINE ON URLpouvait rattacher puis lire une table reposant surFile,S3,AzureBlobStorageouHDFS, ce queCREATE TABLErefuse à juste titre. #115914 (groeneai). - Correction des requêtes HTTP sortantes (par ex. `aiGenerate`, la fonction de table `url`, S3) qui échouaient avec `No route to host` sur les hôtes annonçant à la fois des adresses IPv4 et IPv6 lorsqu’une seule famille d’adresses est routable. Le pool de connexions HTTP bascule désormais sur l’adresse résolue suivante lorsque la première échoue en raison d’une erreur réseau, au lieu de propager l’erreur dès la toute première requête. #103786 (alexey-milovidov).
- Possibilité de lire un
arrayAvro d’enregistrements{key, value}à deux champs dans une colonne ClickHouseMap. Il s’agit de l’encodage produit par Iceberg et Spark pour unMAP<K, V>dont la clé n’est pas une string (les maps natives Avro n’acceptent que des clés de type string). Auparavant, un tel fichier pouvait être lu en tant queArray(Tuple(key, value)), mais pas en tant queMap(K, V), ce qui échouait avec l’erreurType Map(...) is not compatible with Avro array. #109289 (groeneai). - Correction de la lecture d’une table Iceberg dont un fichier de métadonnées porte un numéro de version entièrement numérique mais dépassant la plage des entiers 32 bits (par exemple
v99999999999999999999.metadata.json). Un tel nom produisait auparavant une erreur opaquestd::out_of_range(STD_EXCEPTION) au lieu d’une erreur expliciteBAD_ARGUMENTS. #109619 (groeneai). - Correction du nom des fichiers de métadonnées Iceberg compressés avec gzip. ClickHouse les écrivait sous la forme
v{N}.gzip.metadata.json(le jeton HTTPContent-Encoding), alors que la spécification Iceberg attend l’extensiongz, soitv{N}.gz.metadata.json. Par conséquent, Spark et les autres lecteurs de catalogue Hadoop ne trouvaient pas les métadonnées écrites par ClickHouse. ClickHouse écrit désormaisv{N}.gz.metadata.jsonet continue de lire l’ancien nomgzippour assurer la rétrocompatibilité. #109812 (groeneai). - Correction d’une table Iceberg au format d’écriture
Avroqui sérialisait comme obligatoire un champ déclaré"required": falsede typelist,mapoustruct, sans union["null", T]: le schéma propre au fichier de données divergeait alors des métadonnées de la table, et les autres lecteurs Iceberg voyaient un champ obligatoire. Un tel champ est désormais écrit sous la forme de l’union["null", T]que la spécification Iceberg utilise pour un champ facultatif. #112648 (groeneai). - Correction de
made_current_atdanssystem.iceberg_history, qui indiquait le premier instant où un snapshot est devenu courant au lieu du dernier, lorsque le mêmesnapshot-idapparaît plusieurs fois dans lesnapshot-logd’Iceberg (comme c’est le cas après un rollback). #113598 (groeneai). - Correction d’un blocage pouvant durer jusqu’à une heure dans
BACKUP/RESTORE ... TO S3, les disques GCS et la fonction de tables3lorsque la collection nommée définithttp_client = 'gcp_oauth'et que l’endpoint de jeton OAuth2 de Google accepte la connexion sans jamais répondre. La requête d’obtention du Bearer token n’hérite plus du délai d’expiration des requêtes de transfert de données de l’appelant ; l’attente de sa réponse est plafonnée à 10 secondes, comme pour la requête STSAssumeRole. #115531 (groeneai). - Correction d’une erreur logique dans le cache du système de fichiers (
Expected file ... not to exist) qui pouvait survenir lorsqu’un téléchargement en arrière-plan vers le cache échouait avec une exception autre queErrnoException(par exemple lors d’unOPTIMIZEsur une table Iceberg), laissant derrière lui un fichier de cache orphelin vide. #110549 (groeneai). - Correction des caches dimensionnés par un nombre maximal d’entrées (politique
SLRU), qui cessaient silencieusement d’accepter de nouvelles entrées dès que ce nombre d’entrées avait été consulté au moins deux fois. Sont notamment concernés les caches de fichiers de métadonnées Iceberg et Paimon, le cache de métadonnées Parquet, les caches d’index de texte, le cache d’index de similarité vectorielle, le cache d’expressions compilées et le cache d’état des fichiers ObjectStorageQueue. #115517 (groeneai). - Correction des lectures de tables Paimon qui pouvaient échouer lorsque l’indice mutable
snapshot/LATESTétait remplacé de manière concurrente. En cas d’indice invalide ou obsolète, la lecture bascule désormais de manière sûre vers le listage des snapshots. #112010 (JiaQiTang98). - Remontée de l’exception sous-jacente réelle lorsqu’une archive zip ne peut pas être décompressée parce que le tampon d’entrée (par exemple un tampon de lecture S3 avec
restricted_seek = true) refuse un déplacement (seek) ou une lecture demandés par minizip. Auparavant, l’erreur réelle était masquée par le message génériqueCouldn't unpack zip archive: Code = -100/Couldn't open zip archive. #105103 (groeneai). - Correction de l’écriture Iceberg pour les métadonnées sans refs #106896 (AVMusorin).
- Correction d’une exception lors de l’insertion dans une table Iceberg dont les métadonnées ont été créées par un moteur externe et omettent les tableaux facultatifs
snapshots,metadata-logousnapshot-log. Ces insertions aboutissent désormais au lieu d’échouer. #107473 (tiandiwonder). - Correction d’une erreur
ReadBuffer is canceled. Can't read from it.qui pouvait survenir lorsqu’un téléversement vers S3 (par exemple une sauvegarde) était relancé après une erreur de lecture transitoire. #108573 (groeneai). - Correction d’une
std::future_error(« The associated promise has been destructed prior to the associated state becoming ready ») qui pouvait survenir, et provoquer l’arrêt du serveur dans les builds debug/sanitizer, lorsque la planification de la tâche asynchrone finale de complétion d’un téléversement multipart S3/Azure échouait (par exemple en cas d’épuisement du pool de threads). C’est désormais l’erreur de planification réelle qui est signalée. #108730 (groeneai). - Correction de la lecture des timestamp ORC au-delà de l’année ~2262 dans une colonne
DateTime64dont la scale est inférieure à 9. Le lecteur ORC natif convertissait auparavant chaque timestamp via un intermédiaire fixeDateTime64(9), ce qui provoquait un dépassement de capacité deInt64à l’échelle de la nanoseconde et rejetait ces valeurs avecVALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE, même lorsque la scaleDateTime64demandée (par exempleDateTime64(6), telle que produite par Iceberg) permettait de représenter la valeur. Les timestamp sont désormais lus directement à la scale demandée, etdate_time_overflow_behaviorest respecté lorsque même la scale cible ne peut pas contenir la valeur. #109302 (groeneai). - La lecture d’une table Paimon dont le schéma contient un type imbriqué non pris en charge (par exemple un champ
ROW) renvoie désormais une erreurBAD_ARGUMENTSexplicite indiquant le type en cause, au lieu d’un simpleDB::Exception. (OK)avec le code d’erreur 0 et sans message. #109762 (groeneai). - Correction de la lecture des tables Iceberg partitionnées plusieurs fois selon la même colonne source (par exemple
PARTITIONED BY (hours(ts), ts)). Ces tables échouaient auparavant avecCannot add column ...: column with this name already exists (ILLEGAL_COLUMN). #109895 (groeneai). - Les fichiers de données écrits par ClickHouse dans des tables Iceberg intègrent désormais les identifiants de champ Iceberg pour les formats Avro (
field-id) et ORC (attributs de typeiceberg.id/iceberg.required), et les colonnes ORCStringsont écrites en tant questringORC plutôt qu’en binaire. Auparavant, seul Parquet intégrait les identifiants de champ : les lecteurs conformes à la spécification (par ex. Spark/iceberg-java) renvoyaient donc silencieusement des NULL pour les lignes Avro écrites par ClickHouse après le renommage d’une colonne, et étaient totalement incapables de lire les fichiers ORC écrits par ClickHouse. #109994 (groeneai). - Correction d’une erreur logique
ChunkInfoRowNumbers does not existlors d’unOPTIMIZE TABLEsur une table Iceberg contenant un fichier de données dans un format autre que Parquet (par ex.ORC) plus récent que tous les fichiers de suppression par position. #110107 (alexey-milovidov). - Correction de la lecture de fichiers
Parquetvolumineux depuis des entrées zipSTOREDnon compressées vias3etfile. #110495 (Gudauu). - L’échec du démarrage d’un pool de planification en arrière-plan (par exemple le pool
iceberg, en cas d’épuisement du Global Thread pool) n’interrompt plus le serveur : l’erreur est désormais une exception récupérable. Par ailleurs, la lecture desystem.background_schedule_poolne crée plus ces pools comme effet de bord. #111209 (groeneai). - Correction de l’authentification DLF dans le REST catalog Paimon : la signature de requête était calculée une seule fois puis réutilisée, si bien que toutes les requêtes au catalogue après la première échouaient avec une erreur HTTP 401 et que SHOW TABLES renvoyait une liste vide. Correction également de la détection des erreurs HTTP 404 lors des vérifications d’existence de table. #112015 (JiaQiTang98).
- Correction d’une
LOGICAL_ERROR(partitions_count > 0) lors du partitionnement de fragments de donnéesIcebergvidés par des suppressions par position, par ex. lors du compactage d’une tableIcebergpartitionnée contenant des fichiers de données entièrement supprimés. #112432 (PedroTadim). - Correction de la suppression d’objets par batch sur Azure, qui n’enregistrait aucun événement Delete dans
system.blob_storage_loglorsque la requête de batch elle-même échouait, si bien que le batch entier n’était pas journalisé. Un événement Delete est désormais enregistré pour chaque objet en cas d’échec au niveau du batch. #112873 (arsenmuk). - Correction de la lecture des tables
Paimonpartitionnées par une colonneTIMESTAMPdont la précision est supérieure à la milliseconde, qui échouait avec l’erreurscale 6 is not supported, only support scale <= 3. #113401 (JiaQiTang98). - Correction d’un plantage lors de la lecture d’une table de data lake dont le schéma déclare une colonne au nom vide. Les métadonnées Iceberg malformées sont rejetées avec
ICEBERG_SPECIFICATION_VIOLATION, tandis qu’un schéma fourni par un catalogue, Delta Lake ou Paimon est rejeté avecAMBIGUOUS_COLUMN_NAME. La vérification étant inconditionnelle, une table Iceberg qui se contente de conserver un ancien schéma inutilisé contenant un nom de champ vide devient elle aussi illisible, au lieu de provoquer un arrêt brutal dès la lecture de ce schéma. #114394 (groeneai). - La lecture d’une table Iceberg dont les métadonnées décrivent une évolution du schéma interdite par la spécification Iceberg ne provoque plus l’arrêt brutal du serveur. Quatre violations de la spécification dans
IcebergSchemaProcessorétaient signalées en tant queLOGICAL_ERROR, traitée comme un échec d’assertion, ou aboutissaient sans contrôle à une assertion fatale ; elles lèvent désormaisICEBERG_SPECIFICATION_VIOLATION. #114518 (groeneai). - Correction de la colonne virtuelle
_timedes fonctions de tableurl/urlCluster, qui valait toujoursNULLsur les builds basés sur musl en raison d’une analyse non portable de l’en-tête HTTPLast-Modified. #111619 (thevar1able). - Correction d’un problème empêchant le serveur de démarrer après la création d’une table avec
CREATE TABLE ... AS url('http://host/**/', ...)alors queallow_experimental_url_wildcard_from_index_pagesétait activé. Lors du chargement des métadonnées d’une telle table, la vérification de la fonctionnalité expérimentale était réévaluée et échouait avecSUPPORT_IS_DISABLED, ce qui interrompait le démarrage. #115095 (groeneai). - Une table du moteur de base de données
URLne révèle plus l’existence d’un fichier local à un utilisateur ne disposant pas du grant de lecture de la source : niEXISTS TABLE, qui ne requiert que le privilègeSHOW TABLES, ni la résolution d’une table n’interrogent plus le système de fichiers avant que le grant ne soit confirmé. #113029 (alexey-milovidov). - Application de
query_masking_rulesaux messages ajoutés viaException::addMessage, afin que les identifiants encodés dans l’URL figurant dans les suffixes(in file/uri ...)des erreurs dejdbc()/odbc()ne soient pas divulgués lorsque des règles de masquage sont configurées. #106916 (gaurav0107).
Corrections relatives aux formats et à l’ingestion
- Les lectures sans schéma de
time32/time64Arrow (par ex.SELECT * FROM file(..., 'Arrow')) infèrent désormaisTime64au lieu deDateTime64. Auparavant, le type inféré étaitDateTime64. Tout traitement en aval qui s’appuie sur l’ancien type inféré cessera de fonctionner après la mise à niveau. Ajoute également la prise en charge de l’export deTime/Time64vers Arrow, le type temporel Apache Arrow approprié étant choisi en fonction de la précision. #104316 (Maoyao233). - Correction de résultats potentiellement erronés ou de lectures hors limites lorsqu’un
INSERTest annulé après une erreur survenue en cours de lot (par exemple dans les tablesBuffer, les insertions asynchrones ou les moteursKafka/RabbitMQ/FileLog) alors que la réplication différée des colonnes (enable_lazy_columns_replication) est activée. #108935 (groeneai). - Correction d’une incohérence du parseur : la liste de colonnes d’un
INSERTacceptait un sélecteur de colonnes qualifié écrit sous la formet.* LIKE '<pattern>'/t.* ILIKE '<pattern>', mais rejetait sa forme canoniquet.COLUMNS('<regexp>'), ce qui cassait l’aller-retour de formatage de la requête (et faisait planter le serveur dans les builds de débogage/sanitizer). #109176 (groeneai). - Correction de l’échec de
INSERTdans une tableDataLakeCatalogMicrosoft Fabric / OneLake avec l’erreurIncorrectEndpointError(HTTP 400) : les écritures ADLS Gen2 (DFS) sont désormais acheminées vers l’hôte d’endpoint.dfsau lieu de l’hôte.blob. Remarque : avecremote_url_allow_hosts, les hôtes Fabric.blob(lecture) et.dfs(écriture) doivent tous deux figurer dans la liste d’autorisation pourINSERT. #110290 (zlareb1). - Correction des écritures via les fonctions de table de data lake (par ex.
INSERT INTO FUNCTION icebergS3(...)) qui produisaient des fichiers Parquet dont les colonnes de type String perdaient l’annotation de typeString, rendant les données écrites illisibles pour des lecteurs externes tels que Spark. Ces écritures utilisent désormais les mêmes paramètres de format que les écritures via le table engine. #110465 (tiandiwonder). - Correction de
system.session_log, qui devenait illisible après une connexion Arrow Flight : la colonneinterfaceest de typeEnum8, mais la valeurArrowFlightétait absente de son énumération ; une connexion via le protocole Arrow Flight écrivait donc la valeur brute10, et toutSELECTlisant une telle ligne levait l’exceptionUnexpected value 10 in enum. #110758 (alexey-milovidov). - Correction de l’inférence de schéma pour la famille de formats
TSV, qui inféraitStringpour une valeur décimale écrite avec un zéro initial, comme0.0ou0.5, alors queCSVinfère correctementFloat64. De plus, une première ligne contenant de telles valeurs était interprétée comme en-tête par la détection automatique d’en-tête deTSVet disparaissait du résultat. Corrige égalementTSKV, qui inférait un type numérique pour une valeur écrite à l’aide d’une séquence d’échappement, commex=1\x2E5, dont l’analyse échouait ensuite. Les valeurs dont le zéro initial sert de remplissage pour un entier, comme007, restent inférées commeString, car le parseur de valeursTSVne peut pas les relire. #112226 (groeneai). - Correction de l’inférence de schéma qui proposait un type numérique pour des valeurs textuelles que le parseur de valeurs ne peut pas relire. L’inférence acceptait un exposant incomplet (
1e+), une mantisse manquante (.) ou un signe répété (++inf), quereadFloatTextPreciserejetait ensuite avecCANNOT_PARSE_NUMBERlors de la lecture du schéma inféré ; sur une colonneDynamic, cela provoquait une erreur au moment de l’INSERT. L’inférence valide désormais le nombre avec le parseur réellement utilisé par le lecteur. Cela supprime également un cas où le type inféré dépendait demax_read_buffer_size, et permet aux formes d’exposant valides avec zéro initial, telles que0e5, d’être inférées enFloat64en TSV, comme c’est déjà le cas en CSV. Les formes d’exposant mal formées sont également corrigées. #112453 (groeneai). - Correction de
KILL QUERYetmax_execution_time, qui pouvaient être ignorés pendant plusieurs minutes lorsqu’un format d’entrée orienté lignes analysait un bloc. Les formats d’entrée orientés lignes vérifient désormais l’annulation de la requête toutes les 8192 lignes : une insertion interrompue (en particulier un vidage d’insertion asynchrone en arrière-plan, qui analyse jusqu’àmax_insert_block_sizelignes par bloc) s’arrête donc rapidement au lieu de se poursuivre jusqu’à la fin du bloc. #112646 (groeneai). - Correction du type de colonne inféré qui dépendait de l’ordre des requêtes précédentes pour une source dont le schéma est mis en cache. Les paramètres modifiant un type inféré étaient absents de la clé du cache d’inférence de schéma, de sorte que la valeur de la première requête déterminait le type vu par toutes les requêtes suivantes :
input_format_try_infer_exponent_floats,max_parser_depth,input_format_json_infer_array_of_dynamic_from_array_of_different_types, ainsi que, pourParquet,input_format_parquet_local_time_as_utc,input_format_parquet_allow_geoparquet_parser,input_format_parquet_skip_columns_with_unsupported_types_in_schema_inferenceetschema_inference_make_json_columns_nullable. Enregistre également la fonction d’obtention de clé de cache manquante pourFormet fait en sorte que celle deTemplateutilise la règle d’échappement de son propre format de ligne. #113533 (groeneai). - Correction du formatage d’un argument de sous-requête des fonctions de table
viewetviewIfPermittedlorsque la requête englobante se termine par une clauseSETTINGS. Une telle requête était formatée enview((SELECT ...)), forme impossible à réanalyser, si bien que la requête échouait à la vérification interne formatage-analyse-formatage et levaitInconsistent AST formatting. #114658 (groeneai). - Correction de données JSON détectées à tort comme TSKV lors de la détection automatique du format. #106009 (Avogar).
- L’export vers le format
Arrowde valeursTime/Time64ne correspondant pas à une heure de la journée valide (négatives ou>= 24h) est désormais rejeté avec une erreur explicite, au lieu de produire des données Arrowtime32/time64invalides. #107179 (tiandiwonder). - Correction de la lecture des fichiers
Arrow,ArrowStreametORCbasés sur Arrow dont la colonne d’horodatage a pour fuseau horaire un décalage UTC numérique fixe (par ex.+05:30,-08:00,00:00) ou le marqueur non IANAfixed, qui échouait auparavant avecCannot load time zone ...(BAD_ARGUMENTS). #108633 (groeneai). - Sérialisation d’une colonne
Nullable(Tuple(...))en un seul champ CSV au lieu de l’aplatir en colonnes distinctes. Auparavant, une valeur non nulle était écrite sous forme de plusieurs champs CSV tandis qu’unNULLdonnait un unique\N, ce qui produisait un nombre de colonnes variable selon la ligne et cassait les en-têtesCSVWithNames/CSVWithNamesAndTypesainsi que les allers-retours. #108959 (groeneai). - Correction d’une allocation mémoire excessive lors de l’inférence de schéma du format
MsgPack: une entrée corrompue ou générée par fuzzing dont l’en-tête array/map/string/binary déclare un nombre d’éléments gigantesque ne déclenche plus une allocation unique de plusieurs gigaoctets (elle est désormais rejetée comme entrée malformée). Cela corrige un arrêtallocation-size-too-bigsous les sanitizers ainsi qu’une saturation de la mémoire dans les builds de production. #109019 (groeneai). - Correction d’une erreur
LOGICAL_ERRORlors de l’écriture d’une colonneLowCardinality(Time)au formatArrowavecoutput_format_arrow_low_cardinality_as_dictionary = 1. #109730 (groeneai). - Correction de la lecture d’un flux corrompu au format
Nativedont le nombre de typesDynamicou le nombre de cheminsJSON/Objectest proche deSIZE_MAX: une telle entrée malformée est désormais rejetée avec une erreurINCORRECT_DATAexplicite au lieu d’une exceptionstd::length_errornon interceptée. #110590 (alexey-milovidov). - Correction d’une erreur
LOGICAL_ERROR: Cannot sum Bools(arrêt du serveur dans les builds debug/sanitizer) lors de la fusion d’états d’agrégationsumMap/sumMapWithOverflow/sumMapFilteredcontenant des valeursBoolsérialisées dans l’ancien format d’état (version 0). Cette correction résout également deux cas de résultats erronés silencieux avec des étatsBoolen version 0 : les clés de map de typeBooln’étaient pas dédupliquées entre les états, et le compactage des valeurs nulles supprimait les mauvaises entrées. #110922 (groeneai). - Correction de la fonction de table
format, qui levaitNOT_FOUND_COLUMN_IN_BLOCKlorsque l’analyse des données d’entrée ne produisait aucune ligne (par exemple un JSON vide, ou uneFeatureCollectionGeoJSON sans aucune feature). Elle renvoie désormais un résultat vide avec les bonnes colonnes. #111428 (groeneai). - Il est désormais possible de lire des fichiers GeoParquet, Arrow et ArrowStream dont la colonne de géométrie encodée en WKT utilise un mot-clé de type qui n’est pas entièrement en majuscules (
point(1 2)) ou un conteneur vide (LINESTRING EMPTY,POLYGON(),POLYGON(())). L’importation de ces fichiers échouait auparavant avecBAD_ARGUMENTSouCANNOT_PARSE_NUMBER, alors que ces mêmes chaînes sont correctement analysées par la fonctionreadWKT. Cela corrige également la relecture d’un fichier contenant la sortie dewktpour une géométrie vide, qui s’écritLINESTRING(). #112020 (groeneai). - Correction de l’erreur
Unknown compression methodlevée pour les indications de compressionautoetnonelorsqu’elles n’étaient pas écrites entièrement en minuscules, par exemplefile('data.csv.gz', 'CSV', 'x String', 'AUTO'). Les noms de codecs tels queGZIPétaient déjà acceptés sans tenir compte de la casse ; ces deux indications spéciales se comportent désormais de la même manière. #113631 (groeneai). - Correction de la lecture d’une colonne
Tupledont le premier élément estNULLdans les formatsCustomSeparated,RegexpetTemplateavec la règle d’échappementCSV. Dans ces formats, unTuplenu occupe un champ par élément ; le champ\Ninitial correspond donc à cet élément et non à la colonne entière. Auparavant, il était interprété comme la colonne entière, ce qui décalait les champs des éléments restants vers les colonnes suivantes :CustomSeparatedne pouvait donc pas relire sa propre sortie. #114471 (groeneai). - Correction du format d’entrée
Regexp, qui ignorait silencieusement le reste non analysé d’un champ correspondant et stockait ainsi une valeur tronquée ou fabriquée au lieu de signaler une erreur :v=-1dansUInt64donnait0, etv=2020-01-01junkdansDatedonnait1975-07-14avec la règleJSON. Les champs mal formés sont désormais rejetés avec les règlesEscaped,CSVetJSON, conformément au comportement documenté des formats correspondants. AvecRaw, un champ correspondant contenant une tabulation est désormais lu en entier au lieu d’être tronqué à la tabulation. #114520 (groeneai). - Correction d’une erreur logique
Inconsistent AST formatting(arrêt du serveur dans les constructions debug et sanitizer) pour les expressionsCREATE INDEX/CREATE HYPOTHETICAL INDEXqui ne résistaient pas à un aller-retour formatage-analyse-formatage, par exempleCREATE HYPOTHETICAL INDEX i0 ON t0 ((a())) TYPE aetCREATE INDEX i0 ON t0 ((a, b).1) TYPE minmax. #109175 (groeneai). - Correction d’une erreur logique (
Logical error: 'KeyCondition uses PREWHERE output') dans le lecteur Parquet v3, qui survenait lorsqu’une condition de clé au niveau du format faisait référence à une colonne non lue depuis le fichier Parquet. #109267 (groeneai). - Correction d’une exception dans un gestionnaire HTTP prédéfini en cas d’en-tête absent #108324 (vitlibar).
- Correction d’une possible erreur
Logical error: 'ReadBuffer is canceled. Can't read from it.'lorsqu’un format d’entrée orienté lignes (par ex.TSV/CSV) ne parvenait pas à analyser l’entrée alors que la lecture sous-jacente avait déjà été annulée (par exemple en cas de chunk HTTP mal formé ou de corps tronqué). La construction des diagnostics d’analyse détaillés ne lit plus depuis un tampon annulé. #109708 (groeneai). - Le format
Valuesn’enregistre plus d’erreurs d’analyse danssystem.errorsetsystem.error_loglorsque l’analyse en flux bascule avec succès vers l’analyse d’expressions SQL. #111141 (pamarcos). - Correction de
SYSTEM REFRESHsur une tableRabbitMQarrêtée, qui ne parvenait parfois pas à consommer les messages en attente. Un REFRESH accorde exactement un cycle de streaming hors séquence, mais ce cycle pouvait se terminer immédiatement sans aucune ligne, car la boucle de livraison AMQP venait tout juste d’être démarrée de manière asynchrone : l’unique autorisation était alors gaspillée et les messages restaient non consommés jusqu’au prochainSYSTEM START. #111480 (groeneai). - Correction d’un problème où une table
NATSavecnats_streamdéfini cessait silencieusement de consommer des messages après le redémarrage du serveur NATS. L’abonnementJetStreamest désormais rétabli automatiquement, sans qu’il soit nécessaire d’exécuterDETACH TABLEpuisATTACH TABLE. #112828 (groeneai). - Rejet d’une valeur démesurée de
kafka_num_consumersavec une erreur explicite, au lieu d’un échec d’allocation dans le table engineKafka. Auparavant, aveckafka_disable_num_consumers_limitactivé, une telle valeur provoquait une exceptionstd::length_error. #114764 (alexey-milovidov). - Serveur Arrow Flight : acceptation des identifiants d’authentification
Basicencodés en Base64 sans remplissage, tels qu’envoyés par les clients Flight écrits en Go comme le pilote ADBC Flight SQL, et renvoi d’une véritable erreur d’authentification au lieu de l’erreur génériqueUnexpected error in RPC handlinglorsque l’en-têteauthorizationest mal formé. #115085 (alexey-milovidov). - Serveur Arrow Flight : rejet des identifiants d’authentification Basic mal formés dépourvus de séparateur entre le nom d’utilisateur et le mot de passe. #115347 (alexey-milovidov).
Corrections relatives aux types de données, aux fonctions et à la sérialisation
- Correction d’une erreur logique
Stream <col>.variant_discr ... is not found(arrêt du serveur dans les builds de débogage et avec sanitizers) lorsqueALTER TABLE ... MODIFY COLUMNconvertit une colonne vers un type comportant des sous-colonnes dynamiques (par exempleVariantenDynamic) sur une table avec des parts Wide, et que la part est ensuite lue ou fusionnée. #110204 (groeneai). - Correction de la lecture d’une sous-colonne d’une colonne
Nullable(Tuple(...))dont l’élément est unLowCardinality(T)non nullable, lorsque la même requête lit également la sous-colonne parente. Sur une part Compact, la sous-colonne parente renvoyait des valeurs erronées, la requête échouait avecUnexpected return type from assumeNotNull, ou encore le serveur était tué par une assertion de durcissementstring_view, car la sous-colonne extraite était désérialisée dans un tamponLowCardinality(Nullable(T))dont les sous-flux étaient ensuite partagés avec la lecture de la sous-colonne parente. #112232 (groeneai). - Correction d’une erreur
LOGICAL_ERROR« Not-ready Set is passed as the second argument for functionglobalNullIn» et de la perte du véritable message d’erreur de la requête, qui pouvaient survenir lorsque l’élagage des parts basé sur les statistiques exécutait de manière spéculative une sous-requêteIN/GLOBAL INpendant l’analyse d’index et que cette sous-requête échouait. #114121 (groeneai). - Correction de l’erreur
Cannot read all data of type FixedStringlors de la lecture de la sous-colonneproduct_quantization_codebookd’une colonne utilisant un codecQuantized('product', ...). Le dictionnaire de codes propre à chaque part étant écrit après les données de tous les granules, il n’est pas délimité par des marques : une lecture dont la plage de marques se terminait avant la dernière marque de la part pouvait donc le lire de façon incomplète. #112818 (alexey-milovidov). - Les parts dont la disposition
Mapcontredit leurs propres métadonnées ne sont plus écrites, pour une valeurMapcontenue dans une colonneDynamic. Les tables ne différant que parmap_serialization_versionpartageaient un même objet de sérialisation en cache : une part pouvait ainsi recevoir la disposition Mapbasicalors que ses métadonnées déclaraientwith_buckets, et sa lecture ultérieure échouait avecLOGICAL_ERROR: Stream ...buckets_info ... is not found. Les parts déjà écrites de cette manière par une version antérieure restent illisibles et doivent être supprimées. #113514 (groeneai). - Correction de l’omission, par
ALP,FPCetGCD, de leur paramètre dérivé du type dans le hachage du codec. Dans une part Compact, l’écrivain partage un flux compressé par hachage de codec distinct ; deux colonnes de largeurs de valeur différentes utilisant le même codec entraient donc en collision et partageaient un même objet codec portant une largeur erronée. Des insertions valides étaient alors rejetées avecCANNOT_COMPRESSlorsque les largeurs différaient, et l’une des colonnes était sinon moins bien compressée qu’elle n’aurait dû l’être. #114189 (groeneai). - Correction d’un élagage d’index incorrect lorsque la clé de tri d’une table encapsule une colonne
DatedanstoDateTime(par exempleORDER BY toDateTime(date_column)) et qu’une requête filtre sur la colonne d’origine avec une comparaison telle queWHERE date_column >= '...'.toDateTime(Date)déborde pour les valeursDatesituées au-delà de la plage deDateTime(après le2106-02-07) ; la clé stockée n’est donc pas monotone. ClickHouse n’utilise plus l’élagage par clé primaire pour cette combinaison clé/prédicat, car il risquerait d’écarter des granules contenant des lignes correspondantes. #101814 (nihalzp). - Correction de l’échec de
ALTER MODIFY COLUMNlors de la conversion d’une colonneNullablevers un autre type avec unDEFAULT(par exempleNullable(UInt8)→String,LowCardinality(String)ouArray(UInt8)). #102156 (il9ue). - Correction de l’échappement incorrect des littéraux SQL dans
StorageSQLiteet la fonction de tablesqlite()lors de la transmission des prédicatsWHEREà SQLite : les guillemets simples et les caractères de contrôle (\n,\r,\t,\) étaient échappés avec des antislashs, que SQLite n’interprète pas, ce qui provoquait des erreurs de syntaxe ou des résultats de requête erronés. Correction également de l’échappement des littéraux de type string transmis à PostgreSQL : les strings imbriquées dans des listesINconservaient l’échappement propre à ClickHouse, et les caractères de contrôle étaient envoyés sous forme de séquences d’antislash que PostgreSQL interprète comme des octets différents. #104217 (tiandiwonder). - Correction de l’exception
NOT_FOUND_COLUMN_IN_BLOCKdans les requêtesINNER JOIN ... ON arrayJoin(...) = ...lorsquequery_plan_convert_join_to_inest activé et que le SELECT référence la colonne du tableau source. #104809 (tiandiwonder). - Correction des expressions IN et NOT IN dont l’opérande de droite, non constant, référence des colonnes de la ligne en cours, et alignement du traitement des tuples en opérande de droite par le nouvel analyseur sur la sémantique IN existante de ClickHouse. Avec l’ancien analyseur, une colonne source seule en opérande de droite (
x IN (arr)) est toujours résolue comme un nom de table et reste hors de portée. #104993 (niyue). - Correction des
JOINsur les tablesEmbeddedRocksDB,RedisetKeeperMap, qui pouvaient renvoyer silencieusement zéro ligne lorsqueDirectKeyValueJoinétait utilisé avec des clésStringouNullable(String). #105253 (vdimir). - Correction d’une erreur
LOGICAL_ERROR(“Unexpected expression in JOIN ON section. Expected boolean (UInt8), got ‘Nothing’”) lorsqu’un prédicatJOIN ... ONde non-égalité référence une colonne de typeNothing, comme celle produite parARRAY JOIN []. #106981 (groeneai). - Correction d’une erreur logique
Inconsistent AST formattingpouvant faire planter le serveur dans les builds de débogage et avec sanitizers lorsqu’une lambda avec alias était utilisée comme opérande d’un opérateur d’accès (élément de tuple.Nou élément de tableau[]) ailleurs qu’en première position d’une liste d’expressions, par exempleSELECT 1, ((p0, p1) -> p0 AS a7).4[3] FROM t. #107092 (groeneai). - Une fonction de table de cluster (
urlCluster,fileCluster,s3Cluster, …) imbriquée dans une autre requête distribuée, commeclusterAllReplicas(..., urlCluster(...)), est désormais rejetée avec une erreurBAD_ARGUMENTSau lieu d’échouer avec une erreur logique (Distributed task iterator is not initialized). #107107 (groeneai). - Correction de l’échec de la fonction de table
valuesavecARGUMENT_OUT_OF_BOUNDlors de l’utilisation d’un littéral décimal non représentable exactement dans une colonne à virgule flottante de faible précision (comme0.1pour une colonneFloat32), par exempleSELECT * FROM values('x Float32', 0.1). Ces valeurs sont désormais acceptées et converties en la valeur représentable la plus proche, comme le fontCASTetINSERT ... VALUES. #108055 (alexey-milovidov). - Correction de
mapFilter,mapSort(et ses variantes) etmapConcat, qui supprimaientLowCardinalitydes types de clé et de valeur d’uneMap. Auparavant,mapFilterappliqué à une colonneMap(LowCardinality(String), String)renvoyaitMap(String, String), ce qui pouvait corrompre les métadonnées d’une table créée viaCREATE TABLE ... AS SELECTet faire échouerCHECK TABLE. #108057 (alexey-milovidov). - Correction d’un
INSERTannulé ou interrompu parKILLqui continuait à s’exécuter longtemps pendant la construction d’un index de saut (par exemple un indexset(0)non borné sur une colonne à forte cardinalité). La construction de l’index s’arrête désormais rapidement lorsque la requête est annulée. #108351 (tiandiwonder). - Correction d’un
SELECTsur la fonction de tableprimesqui ne réagissait pas à l’annulation : avec une valeur élevée destep(ou delimit), la requête pouvait continuer à s’exécuter longtemps après unKILL QUERYou un dépassement de délai. Elle s’arrête désormais rapidement. #108353 (tiandiwonder). - Correction de l’analyse des noms de types de données contenant la sous-chaîne
INT(par exemple un nom de type fonction tel quequantileInterpolatedWeightedutilisé à l’emplacement d’un type de données). Ces noms étaient pris pour des types entiers MySQL, et leur premier groupe d’arguments(...)était silencieusement consommé comme modificateur de largeur d’affichage, ce qui pouvait casser l’aller-retour de formatage de la requête. #108354 (groeneai). - Correction d’une incohérence : un
ARRAY JOINmal formé suivi d’une virgule et d’une liste de tables entre parenthèses était analysé à tort comme une jointure croisée au lieu d’être rejeté. #108365 (Algunenano). - Correction d’une exception
LOGICAL_ERROR(“Invalid action query tree node …”) survenant lorsqu’une requête distribuée dédupliquait des colonnesALIASen double structurellement identiques tout en référençant une fonction de table avec un argument de collection nomméekey = value(par exempleoss(s3_conn, filename = '...')). #108435 (groeneai). - Correction d’une erreur logique (une exception dans les builds de production, un arrêt brutal du serveur dans les builds de débogage et avec sanitizers) pouvant survenir lors d’un appel de fonction comportant plus d’un argument
LowCardinalitysur une table distribuée, par exempleconcatAssumeInjective((SELECT toLowCardinality('p')), s)utilisé comme clé deGROUP BYavecremote(). Les messages d’erreur étaientDefault functions implementation for LowCardinality is supported only with a single LowCardinality argumentouExpected the argument ... to have N rows, but it has M. #108871 (groeneai). - Correction de
use_client_time_zone, qui était ignoré pour les littéraux stringDateTime/DateTime64interprétés sur le serveur (INSERTasynchrone, littéraux deSELECT). Le client transmet désormais son fuseau horaire local en tant quesession_timezonelorsqueuse_client_time_zoneest activé, afin que l’analyse côté serveur soit identique à celle du cheminINSERTsynchrone. #109051 (groeneai). - Correction de
max_execution_time(avectimeout_overflow_mode = 'throw') qui, dans certains cas, n’annulait jamais une requête : lorsque le surveillant interne des délais attendait déjà une requête dont l’échéance était plus tardive, une requête enregistrée ensuite avec une échéance plus proche pouvait passer totalement inaperçue et s’exécuter bien au-delà de sa limite de temps. #109792 (tiandiwonder). - Correction de l’erreur
NOT_FOUND_COLUMN_IN_BLOCKlorsqu’une requête sur une tableDistributedutilise_shard_num(oushardNum()) devenuNullable(par exemple avecFULL JOINetjoin_use_nulls = 1) conjointement avecORDER BY, l’analyseur étant activé. #109798 (groeneai). - Correction de l’erreur
NOT_IMPLEMENTED(“Method getDataAt is not supported for Nullable(String)”) qui pouvait être levée par une jointure avecenable_join_runtime_filters = 1(activé par défaut depuis la version 26.2) lorsque la clé de jointure côté construction était de typeLowCardinality(Nullable(...))et contenait des NULL, et que le filtre d’exécution se rabattait sur son filtre de Bloom. #109824 (groeneai). - Correction d’un plantage du serveur lorsqu’une expression lambda était passée là où une fonction d’ordre supérieur attend une valeur concrète (par exemple l’accumulateur de
arrayFold, comme dansarrayFold(lambda, arr, another_lambda)). Lorsqueenable_analyzer = 0, ces requêtes sont désormais rejetées avecILLEGAL_TYPE_OF_ARGUMENTau lieu de provoquer un plantage. #109840 (groeneai). - Rejet de l’alias
unnestdearrayJoindans les filtres de politique de ligne, ce qui comble une faille par laquelle une telle politique pouvait déclencher une erreur logiquecolumn->size() == num_rowslors de la lecture. #109973 (Algunenano). - Correction des index de saut définis sur des sous-colonnes
Tuple, qui n’étaient pas utilisés lorsque l’on accédait au champ viatupleElement(t, 'name'),tupleElement(t, N)out.Nalors que le tuple complet était également lu dans la même requête (par ex.SELECT *). Toutes ces formes élaguent désormais les granules de la même manière que l’accès par sous-colonne nomméet.name. #110056 (groeneai). - Correction de l’erreur
BAD_GETlors de la comparaison d’une colonneArray(String)avec un littéral de tableau (arr = ['x']) lorsque la colonne dispose d’un index de sauttext,tokenbf_v1oungrambf_v1. L’index traite désormais une telle comparaison comme un parcours complet au lieu de faire échouer toute la requête. #110057 (groeneai). - Correction d’une erreur
ILLEGAL_COLUMNintempestive renvoyée parALTER TABLE ... ADD COLUMN IF NOT EXISTSlorsque la colonne existe déjà au moment de l’application. Ce problème survenait lorsque la même colonne était ajoutée deux fois avecIF NOT EXISTSdans une même instruction, ou lorsqu’unALTERconcurrent ajoutait la colonne entre les phases de préparation et d’application. #110080 (groeneai). - Correction d’une erreur
LOGICAL_ERROR(Bad cast from type ColumnLowCardinality to ColumnString) lorsqueidentity()(ou le résultat d’une sous-requête scalaire) encapsule une valeur contenant unLowCardinalityimbriqué et que la requête utiliseWITH TOTALS/WITH ROLLUP. #110138 (groeneai). - Correction d’une erreur
NOT_FOUND_COLUMN_IN_BLOCKlors de l’utilisation deGROUP BY ALLsur une expression de tuple combinée àORDER BY. #110206 (alexey-milovidov). - Correction d’une erreur
NOT_FOUND_COLUMN_IN_BLOCKlors d’unINSERTdans une table comportant une contrainteCHECKqui fait référence à une sous-colonne (commex.nulld’une colonneNullableouarr.size0d’unArray). #110208 (alexey-milovidov). - Correction de résultats de requête erronés produits par l’optimisation optimize_and_compare_chain (activée par défaut) : une condition déduite par transitivité de a < b AND b < c pouvait appliquer une sémantique de comparaison différente de celle des conditions d’origine lorsque la chaîne mélangeait des types soumis à des règles de conversion propres à chaque paire (par ex. Enum et String, Decimal et Float64, FixedString de largeurs différentes). Les conditions transitives ne sont désormais déduites qu’au sein de groupes de types partageant un même ordre de comparaison. #110621 (yariks5s).
- Correction de
optimize_injective_functions_in_group_by, qui modifiait le résultat de la requête pourGROUP BY GROUPING SETSetGROUP BY ... WITH TOTALS. Ce paramètre est censé préserver les résultats, mais l’élimination d’une fonction injective appliquée à une clé de regroupement produisait une valeur erronée (ou supprimait une ligne) pour les lignes où cette clé est absente de l’ensemble agrégé (un set non membre deGROUPING SETS) ou pour la ligneWITH TOTALS. La valeur erronée pouvait coïncider avec une valeur de clé réelle, rendant une ligne de super-agrégat impossible à distinguer d’un groupe réel dans le même jeu de résultats. #110721 (groeneai). - Correction d’un blocage du serveur lors de la multiplication d’un état de fonction d’agrégation
median/quantile(reposant sur ReservoirSampler) par une très grande constante entière (par exemplemedianState(x) * 18446744073709551615). La requête ne répondait plus aux demandes d’annulation et pouvait s’exécuter indéfiniment. #110779 (groeneai). - Correction d’un plantage (déréférencement d’un pointeur nul lors de l’analyse de requêtes) lorsque
getSubcolumnest appelé sur un argumentJSONavec un nom de sous-colonne interne d’indication de type, c’est-à-dire commençant par un marqueur de type sous forme d’accent grave. #110940 (groeneai). - Correction de
map[key], qui renvoyait la valeur d’une occurrence ultérieure d’une clé dupliquée au lieu de la première. Lorsqu’une colonneMapcontenait des clés dupliquées, le résultat demap[key]pouvait dépendre des lignes précédentes du même bloc et du paramètreoptimize_functions_to_subcolumns, de sorte qu’unSELECTet unWHEREportant sur la même ligne pouvaient donner des résultats divergents. #111246 (groeneai). - Correction d’une erreur logique
!rhs_literal->getValue().isNull()dans l’optimiseur d’expressions logiques lorsqu’une chaîneANDcompare une colonne à une constante de valeur NULL d’un type nonNullable(par exemple unVariantde valeur NULL) avecuse_variant_default_implementation_for_comparisons = 0. #111292 (groeneai). - Correction de résultats erronés lorsqu’une requête comporte un index de saut
setet un prédicat de la forme(x AND <null-value>) OR y, où la valeur NULL est produite par une fonction (par exempletoInt64OrNull('x'),nullIf(1, 1),CAST(NULL AS Nullable(Int64))). Une telle valeur était encapsulée par__bitWrapperFuncet propageaitNULLau lieu du masque « inconnu », si bien que l’index set pouvait élaguer des granules pourtant correspondants et que la requête renvoyait moins de lignes que prévu. #111604 (groeneai). - Correction de
CREATE TABLE/ALTER TABLEavec l’analyseur, qui acceptait une expressionDEFAULT/MATERIALIZEDde colonne faisant référence à une colonne virtuelle telle que_tableou_database. L’insertion dans une telle table échouait avecNOT_FOUND_COLUMN_IN_BLOCK, et une colonneMATERIALIZED(qui ne peut pas être fournie explicitement) rendait toute insertion dans la table définitivement impossible. Ces expressions sont désormais rejetées dès la définition, comme c’est le cas sans l’analyseur. Les colonnesALIAS(évaluées à la lecture) etEPHEMERAL(entrées d’insertion non stockées) portant sur des colonnes virtuelles continuent de fonctionner. #111776 (groeneai). - Correction de l’erreur
UNKNOWN_QUERY_PARAMETERlorsqu’une vue paramétrée est appelée avec un argument issu d’une sous-requête de typeArray,TupleouLowCardinality, par exempleSELECT * FROM v(param = (SELECT groupArray(x) FROM t)). #111790 (groeneai). - Correction de trois bogues dans les réécritures de l’analyseur qui transforment une chaîne de comparaisons en
IN/NOT IN(x = c1 OR x = c2 OR ...,x != c1 AND x != c2 AND ...ethas(const_array, x)). Pour une expressionVariantavecuse_variant_default_implementation_for_comparisons = 0, la réécriture faisait passer le type de résultat de l’expression deUInt8àNullable(UInt8), ce qui déclenchait une erreurLOGICAL_ERRORlors de la validation de l’arbre de requête dans les builds de débogage et les builds avec sanitizers. Pour une expression à structure dynamique (Dynamic,Array(Dynamic),JSON), la réécriture faisait échouer une requête pourtant fonctionnelle avecIllegal type ... of argument of function in, carINrejette ce type d’arguments. Dans les deux sens, des résultats erronés étaient également renvoyés lorsqu’une constante ne pouvait pas être convertie sans perte vers le type de l’expression, par exemple une constanteDateTimecomportant une heure comparée à une colonneDate. #111924 (groeneai). - Correction de
quantileDeterministic,quantilesDeterministicetmedianDeterministic, qui renvoyaient des résultats différents pour les mêmes données à chaque exécution lorsque la requête utilisait les répliques parallèles, une table distribuée ou l’agrégation externe, ou lorsque les états étaient stockés dans une table (y compris à l’intérieur d’une valeurDynamic). Les états écrits avant cette version sous l’ancienne notation de type non versionnée conservent le comportement précédent, leur format ne pouvant pas changer. #112052 (alexey-milovidov). - Correction de résultats erronés dus à une requête de recherche vectorielle qui corrompait le cache des conditions de requête. Une requête
SELECT ... WHERE <condition> ORDER BY <distance function> LIMIT nsur une table dotée d’un indexvector_similaritypouvait marquer des granules comme ne correspondant pas à<condition>, si bien qu’une requête ordinaireSELECT ... WHERE <condition>exécutée ensuite sur la même table renvoyait silencieusement moins de lignes. Les lectures liées à la recherche vectorielle n’écrivent plus dans le cache des conditions de requête. #112086 (groeneai). - Correction de l’omission de
serialize_string_in_memory_with_zero_bytedans le plan de requête sérialisé. Avecserialize_query_plan = 1, un cluster où ce paramètre était désactivé pouvait présenter une divergence de représentation sous forme de chaîne en mémoire entre l’initiateur et le nœud exécutant le plan désérialisé : le paramètre était lu lors de la désérialisation mais jamais écrit lors de la sérialisation, et prenait donc toujours sa valeur par défaut sur le nœud d’exécution. #112131 (groeneai). - Correction d’un résultat erroné pour une
JOINdont l’expressionONcontient une conjonction constante, par exempleON l.id = r.id AND CAST(NULL AS Nullable(UInt8)). La constante était silencieusement supprimée par l’optimisation du plan de requête, si bien que la jointure s’exécutait comme si elle n’existait pas : les jointuresINNER,LEFT SEMIetRIGHT SEMIrenvoyaient des lignes correspondantes alors qu’une condition jamais vraie ne doit en renvoyer aucune, etRIGHT ANTIne renvoyait aucune ligne au lieu de les renvoyer toutes. #112155 (vdimir). - Correction de résultats erronés lorsqu’une vue paramétrée est appelée avec un argument qui n’est pas une affectation
parameter = value. Avecenable_analyzer = 0, ainsi que dansEXPLAIN SYNTAXavec les paramètres par défaut, des appels tels quepv(concat(name, '!')),pv(name, 'a'),pv(name != 'a')etpv(tuple(name = 'a'))liaient silencieusement un paramètre de la vue à une expression sans rapport, au lieu de signalerUNKNOWN_QUERY_PARAMETERcomme le fait l’analyseur. Ces appels sont désormais rejetés de la même manière sur les deux chemins d’exécution. #112194 (groeneai). - Corrige un bogue qui faisait qu’une instruction
CREATE VIEWouCREATE FUNCTIONdont la définition appellesubstr,midoubyteSlicesous une forme que la grammaire desubstringne peut pas réanalyser était acceptée, alors que les métadonnées écrites par ClickHouse pour cette instruction ne constituaient pas du SQL valide. La relecture ultérieure de cette définition échouait avecSYNTAX_ERRORet, au démarrage du serveur, interrompait le chargement des métadonnées, empêchant purement et simplement le serveur de démarrer. Ces définitions peuvent désormais être réécrites puis relues sans perte, et les fichiers de métadonnées existants de la formesubstring(x, a, b, c)redeviennent lisibles : un serveur affecté démarre donc sans intervention manuelle. #112195 (groeneai). - Correction de résultats erronés, d’une sortie
ORDER BYmal triée et d’une exceptionBAD_TYPE_OF_FIELDlorsque la clé primaire est de typeArrayouTupleet que la requête lui appliqueplus,minus,multiply,divideouintDiv. Les opérations arithmétiques sur une valeur composée s’effectuent élément par élément, alors que la comparaison de valeurs composées est lexicographique ; l’analyse de la clé primaire ne considère donc plus une telle expression comme monotone. #112339 (groeneai). - Correction de l’erreur
Code: 62 ... You must not specify ANY or ALL for PASTE JOIN. (SYNTAX_ERROR)levée par un serveur distant lorsqu’une requête contenant unPASTE JOINest transmise à un autre serveur, par exemple lorsque la table de gauche est une tableDistributedou une fonction de table*Cluster. Le formateur produisaitALL PASTE JOIN, une écriture rejetée par l’analyseur, si bien que le serveur destinataire ne pouvait pas analyser la requête reçue. #112404 (groeneai). - Corrige un problème qui rendait une liste d’alias de colonnes telle que
(SELECT 1) AS t(x)ouWITH t(x) AS (SELECT 1)invisible à l’intérieur de la fonction de tableview: une référence àt.xy échouait avecUNKNOWN_IDENTIFIER, alors que la même construction fonctionne en dehors deview. #112690 (groeneai). - Corrige une erreur logique lors du formatage d’une requête lorsqu’une clause
ARRAY JOINne contient aucune expression. Une telle clause est désormais rejetée dès l’analyse avecSYNTAX_ERROR, comme c’est le cas pour unUSINGvide, au lieu d’être acceptée puis formatée en un texte impossible à réanalyser. #112699 (groeneai). - Correction de
connectionId, qui levaitContext has expiredlorsque les actions d’expression préparées pour une sous-requête s’exécutaient après la libération de leur contexte de construction. #112870 (clickgapai). - Corrige une erreur logique et des résultats erronés lorsqu’une condition
JOIN ONde non-équijointure évaluée pendant la jointure contientarrayJoin. Une jointurehash,parallel_hashougrace_hashrejette désormais une telle condition avecINVALID_JOIN_ON_EXPRESSION. Si l’expansion ne dépend que d’un seul côté, déplacez-la dans unARRAY JOINau sein d’une sous-requête, avant la jointure ; une condition dont l’argument dearrayJoinlit des colonnes des deux côtés doit être restructurée. #112889 (groeneai). - Correction de
geohashesInBox, qui pouvait s’exécuter indéfiniment sur une zone d’aire nulle, commegeohashesInBox(0., 0., 180., 0., 12). Une telle requête renvoyait bien l’unique geohash attendu, mais effectuait environ 5e8 itérations de boucle à vide par ligne et ignorait aussi bienmax_execution_timequeKILL QUERY. #112976 (groeneai). - Une modification
SETTINGSmarquée comme écrite sans valeur est désormais rejetée lorsqu’elle porte une valeur autre quetrue, et la valeur d’une telle modification n’est plus jamais omise lors du formatage d’une requête. Auparavant, une charge utile JSON d’AST spécialement conçue pouvait exécuter un paramètreBoolavecfalsealors quesystem.query_logetformatQueryFromJSONaffichaient la forme sans valeur. #113025 (alexey-milovidov). - Correction de l’erreur
UNKNOWN_IDENTIFIERlors d’une sélection depuis uneVIEWdont les types de colonnes déclarés diffèrent des types produits par sa requête interne, par exempleSELECT sum(length(arr)) FROM voùvdéclarearr Array(UInt8)sur une colonneString. Avec la valeur par défautoptimize_functions_to_subcolumns = 1, l’optimiseur réécrivaitlength(arr)en une lecture de la sous-colonnearr.size0et transmettait ce nom à la requête interne, qui ne possède pas cette sous-colonne. #113057 (groeneai). - Correction de l’annulation des lectures via la fonction de table
postgresqlet le moteur PostgreSQL. Une annulation survenant pendant le démarrage de la lecture pouvait provoquer une condition de concurrence sur le pointeur de transaction, et l’annulation pouvait être entièrement perdue, la requête continuant alors à s’exécuter jusqu’à ce que PostgreSQL la termine. Une annulation qui parvient à PostgreSQL avant que le statementCOPYn’ait commencé à s’exécuter peut encore être ignorée. #113150 (groeneai). - Correction d’une erreur
LOGICAL_ERROR(Next task callback is not set for query) lorsqu’une vueSQL SECURITY DEFINERouSQL SECURITY NONEreposant sur une fonction de table de cluster (s3Cluster,urlCluster,fileCluster) était lue en tant que requête secondaire, par exemple viaremoteouclusterAllReplicas. Cette imbrication non prise en charge est désormais rejetée avec une erreur de requête classique au lieu de faire planter le serveur dans les constructions debug et sanitizer. #113371 (groeneai). - Correction d’une erreur logique
IDENTIFIER is not a table expressionlorsqu’une fonction de table de la famille remote avec un argumentview(...)est utilisée du côté gauche d’unJOIN ... USINGdont la clé est un alias de la listeSELECT, avecanalyzer_compatibility_join_using_top_level_identifier = 1. #113400 (groeneai). - Correction de l’erreur
Not-ready Set is passed as the second argument for function 'in'lorsqu’une requête filtresystem.databasessur la colonnenameavec une sous-requête dansindexHint, par exempleSELECT count() FROM system.databases WHERE indexHint(name IN (SELECT 'foo')). Une telle requête était rejetée avec une erreurLOGICAL_ERRORsur les constructions release et faisait planter le serveur sur les constructions debug et sanitizer. #113556 (groeneai). - Correction d’un problème où une requête sur une colonne
Variantignoraitmax_execution_timeetKILL QUERY. L’appel d’une fonction avec plusieurs argumentsVariantrésolvait la fonction une fois pour chaque alternative de chaque argument, et aucune des deux boucles chargées de ce travail ne vérifiait l’annulation : une telle requête ne pouvait donc pas être interrompue avant la fin de son exécution. #113612 (groeneai). - Correction de l’échec de
ALTER TABLE ... MODIFY COLUMNavecCannot specify codec for column type ALIASlorsqu’un même statement transforme une colonneALIASen colonne physique (DEFAULTouMATERIALIZED) et spécifie unCODEC. #113853 (groeneai). - Correction d’un plantage du serveur lors d’une jointure avec une expression
ONconstante sur un côté droit contenant unARRAY JOIN. La lecture d’une colonne du côté droit répliquée de manière paresseuse utilisait unColumnReplicateddéjà libéré. #113901 (groeneai). - Correction d’une fuite de mémoire avec
optimize_aggregation_in_order = 1lorsque la clé de tri de la table est un préfixe strict de la cléGROUP BYet qu’une fonction d’agrégation dont l’état possède de la mémoire allouée sur le tas est utilisée, commequantileDD. La mémoire du serveur augmentait à chaque requête de ce type jusqu’au redémarrage. #114010 (groeneai). - Correction de
isProbablePrimesurUInt128/UInt256, qui ignoraitmax_execution_timeetKILL QUERY. Un bloc de valeurs larges s’exécutait jusqu’au bout au sein d’un unique appel de fonction, sans point d’annulation, si bien qu’une requête pouvait se prolonger plusieurs minutes au-delà de son délai. #114032 (groeneai). - Correction de l’erreur
Code: 46. DB::Exception: Unknown function exists. (UNKNOWN_FUNCTION)levée lorsqu’une clausePREWHEREcontient un prédicatIN (subquery)et querewrite_in_to_join = 1(oumake_distributed_plan = 1, qui l’active d’office) est défini. La même requête écrite avecWHEREfonctionnait correctement. #114067 (RohithPariki). - Correction d’une erreur
LOGICAL_ERRORdansarrayAutocorrelationlorsque l’argument est un tableau non vide dont le type d’élément estNothing, par exempleSELECT arrayAutocorrelation([arrayMax([])]). Un tel argument est désormais rejeté avecILLEGAL_COLUMN. Le littéral de tableau vide[]continue de renvoyer[]. #114249 (groeneai). CREATE TABLEetALTER TABLErejettent désormais les codecs avec perte, tels queSZ3, sur une colonne utilisée dans la clé de tri. #114531 (groeneai).- Correction d’une boucle infinie et impossible à annuler dans les fonctions
hopetwindowIDlorsque la durée d’un argument d’intervalle, exprimée en secondes, est un multiple de 2^32 (par exemple,toIntervalDay(2147483648)) : la soustraction avec dépassement échappait à la vérification de débordement temporel et, avec des arguments constants, la boucle s’exécutait dès l’analyse, à un stade où la requête ne pouvait même pas être interrompue. Le même intervalle pouvait également faire tourner indéfiniment un thread d’arrière-plan d’uneWINDOW VIEW; une telle window view est désormais rejetée dès sa création. #114607 (alexey-milovidov). - Correction de l’erreur logique
Not-ready Set is passed as the second argument for function 'in'pour une requête comportant une sous-requêteINlisant depuis un cluster distant : la requête échoue désormais avec l’erreur réelle de la sous-requête, par exemple un échec de connexion. #114983 (alexey-milovidov). - Correction d’un
INSERTdans une tableLog,TinyLogouStripeLogéchouant lors de la validation des tailles de fichiers enregistrées. Une telle insertion pouvait laisser ses lignes dans la table bien qu’elle ait signalé une erreur, ou rendre les fichiers de données d’une colonne de tableau incohérents entre eux. La lecture d’une tableLogouTinyLogdont la colonne de tableau ne contient aucun élément alors que ses offsets en annoncent lève désormais une erreur indiquant le nom de la colonne, au lieu de lire au-delà de la fin des éléments. Une colonne d’éléments partiellement écrite était déjà rejetée. #115027 (groeneai). - Correction de l’erreur
TYPE_MISMATCH(“CAST AS Array can only be performed between same-dimensional array types”) pour une requête comportant une constante de typeArray(Map(...)), commehas([map('k', 'v')], m), exécutée sur une tableDistributedou avec des répliques parallèles. #115883 (alexey-milovidov). - Correction de résultats erronés lors d’une jointure avec une vue ou
view()dont la colonne projetée porte le même nom qu’une colonne de l’une de ses propres relations internes, par exempleSELECT expr(x.c0) AS c0 FROM a AS x, b AS y. L’optimiseur d’ordre des jointures intégrait une telle expression au graphe de jointure aplati, puis l’appliquait deux fois : la requête renvoyait alors silencieusement des valeurs faussées. Lorsque l’expression modifiait également le type de la colonne, la même cause produisait à la place une erreurAMBIGUOUS_COLUMN_NAMElors de la planification. #116152 (groeneai). - Correction d’une exception dans les sous-requêtes corrélées lorsque des colonnes externes deviennent
Nullableavecgroup_by_use_nullset ROLLUP/CUBE. #100365 (alexey-milovidov). - Rejet de
max_replication_lag_to_enqueue = 0sur les bases de donnéesReplicated. Avec cette valeur, la vérification de non-synchronisation après récupération était trivialement vraie, ce qui provoquait l’arrêt du serveur avecLOGICAL_ERRORdans les builds de débogage et avec sanitizer.0est désormais rejeté dès l’analyse avecBAD_ARGUMENTS, quelle que soit la source (CREATE DATABASE ... SETTINGS, bloc<database_replicated>de la configuration du serveur, rejeu d’ATTACHet rejeu des métadonnées existantes lors d’une mise à niveau). La plus petite valeur valide est1. #106006 (groeneai). - Interdiction de créer un index de saut minmax sur les colonnes JSON (Object) afin d’éviter l’exception NO_COMMON_TYPE lors de l’insertion de tableaux de types mixtes. Utilisez plutôt des sous-colonnes typées (par exemple,
INDEX idx json.field TYPE minmax). #106094 (linhaojie). - Correction de
JSON_QUERY/JSON_VALUE/JSON_EXISTS, qui renvoyaient Dynamic au lieu de String/UInt8 avec des arguments Dynamic. #106877 (Avogar). - Correction d’un dépassement d’entier signé lorsqu’un paramètre de délai d’attente, tel que
interactive_delay, était défini sur une valeur très élevée : l’attente pouvait expirer immédiatement, et le serveur pouvait s’arrêter brutalement sous l’Undefined Behavior Sanitizer. #106961 (groeneai). - Correction d’une erreur
LOGICAL_ERROR(« Unsupported argument types ») dans la fonctiongeohashesInBoxlorsque ses arguments de coordonnées mélangeaient des valeurs constantes et non constantes, ou lorsqu’une coordonnée était de typeBFloat16. Les argumentsFloat32mêlant constantes et non-constantes fonctionnent désormais, et les argumentsBFloat16sont rejetés avec une erreur explicite. #107063 (groeneai). - Correction de l’en-tête de
CSVWithNamesetCSVWithNamesAndTypes, qui comportait moins de colonnes que les données lorsqueoutput_format_csv_serialize_tuple_into_separate_columnsest activé (valeur par défaut). L’en-tête (ainsi que la ligne des types) aplatit désormais les colonnesTupleen leurs champs terminaux avec des noms pointés (par exemplet.a,t.b), afin que le nombre de colonnes de l’en-tête corresponde à celui des données. Un nouveau paramètre,output_format_csv_header_serialize_tuple_into_separate_columns(1par défaut), contrôle ce comportement ; il peut être défini sur0pour rétablir l’ancien en-tête à nom unique. #107371 (groeneai). - Correction d’une fuite de mémoire dans le
mongo-c-driverintégré, susceptible de se produire lors de la lecture depuis MongoDB (par exemple via un dictionnaire MongoDB ou la fonction de tablemongodb) lorsqu’une erreur de lecture pouvant donner lieu à une nouvelle tentative était suivie d’un échec de la sélection du serveur pour cette nouvelle tentative. #107448 (groeneai). - Correction d’une erreur logique (
WhichDataType(const_type).isArray()) et d’un arrêt brutal du serveur lors de l’analyse de la clé primaire lorsquepointInPolygonest appelée avec un argument polygone constant d’un type enveloppe tel queVariantouDynamic(par exemplepointInPolygon((x, y), if(c, [(0, 0), ...], NULL))). #107589 (groeneai). - Correction d’erreurs logiques (
Bad cast) causées par une suppression incohérente deLowCardinalityimbriqué dans des colonnesVariantetDynamic, par exemple dansconcat,formatet l’analyse de la clé primaire. #107773 (Avogar). - Correction de l’analyse des paramètres de commande des fonctions définies par l’utilisateur de type executable, afin que les caractères de substitution dont le nom est vide ou invalide ne soient plus acceptés comme paramètres. #107983 (goutamadwant).
- Correction de
accurateCastOrNullappliquée à unTupledont un élément estDynamic/Variant: une valeurNULLréellement présente dans la source était traitée comme un échec de conversion. Pour un élément cibleNullable, une valeurNULLsource reste désormais un élémentNULL(comme pour une sourceTuple(Nullable(...))simple) ; pour un élément cible nonNullable, une valeurNULLsource rend désormais l’ensemble du tupleNULL(comme la référence nonDynamic) au lieu de produire la valeur par défaut de l’élément. Les échecs d’analyse ou de dépassement rendent toujours l’ensemble du tupleNULL. #108023 (groeneai). - La fonction de table
mongodbaccepte désormaisoid_columnspassé en argument nommé (par ex.oid_columns='_id'), au lieu de le rejeter avecBAD_ARGUMENTS. #108039 (alexey-milovidov). - Il est désormais possible d’interroger un dictionnaire
range_hashedoucomplex_key_range_hashedutilisant une plageDateTime64,Decimalou à virgule flottante avec un argument correspondant passé àdictGet/dictHas. Auparavant, ces requêtes échouaient avecmust be convertible to Int64, et les intervalles ouverts des plagesDecimal/DateTime64renvoyaient à tort la valeur par défaut. #108052 (alexey-milovidov). - Correction d’un arrêt brutal du serveur (
Logical errordansIColumn::insertFrom) lors de la conversion d’unArray(Dynamic)ouArray(Variant)enQBitavecaccurateCastOrNull, par ex.accurateCastOrNull(CAST(range(114), 'Array(Dynamic)'), 'QBit(Float32, 114)'). #108288 (groeneai). - Correction d’un plantage du serveur (
Received signal 4, instruction illégale) pouvant être déclenché par un flux du protocole TCP natif malformé ou désynchronisé. Le champinitial_addressdeClientInfoest désormais vérifié comme étant unhost:portnumérique avant son analyse, au lieu de laisser un port non numérique atteindre la fonction libcgetservbyname, qui est interceptée. #108410 (groeneai). - Correction d’une allocation mémoire excessive lors de la désérialisation d’états de fonctions d’agrégation forgés pour
mannWhitneyUTest,rankCorr,largestTriangleThreeBuckets,quantileGK,sequenceMatch/sequenceCountetgroupArrayIntersect. Un état malformé pouvait déclarer un nombre d’éléments démesuré et amener le serveur à tenter d’allouer des dizaines de gigaoctets à partir de quelques octets en entrée ; ces états sont désormais rejetés avecTOO_LARGE_ARRAY_SIZE. #108465 (groeneai). - Correction d’une erreur logique (
Bad cast from type DB::ColumnNullable to DB::ColumnString) et de résultats potentiellement incorrects lors de l’utilisation degroup_by_use_nullsavec une clé de regroupement constanteLowCardinalitydansGROUPING SETS/ROLLUP/CUBE. #108771 (alexey-milovidov). - Correction de l’erreur
TYPE_MISMATCHdansmapFilter,mapSort,mapReverseSort,mapPartialSortetmapConcatlorsqu’une valeurMapcontient uneMapimbriquée avecLowCardinality, par exemplemapFilter((k, v) -> 1, map('a'::LowCardinality(String), map('x'::LowCardinality(String), 'y'))). #108798 (groeneai). - Correction d’une erreur
LOGICAL_ERROR(« Inconsistent AST formatting ») qui provoquait l’arrêt du serveur dans les builds debug et sanitizer lors du formatage d’un type de donnéesTuplecombinant des éléments nommés et non nommés (par exempleTuple(a UInt8, UInt16)). #108915 (groeneai). JSONExtractrespecte désormaiscast_string_to_date_time_modelors de la conversion de valeurs JSON de type string enDateTime/DateTime64, de manière cohérente avecCAST. #109252 (Utkal059).- Correction de
INlorsque l’argument de droite est une simple colonne de type tableau : le résultat renvoyé était silencieusement incorrect (toujours faux) ou une exception était levée. Désormais,x IN arrse comporte commehas(arr, x). #109416 (alexey-milovidov). - Correction d’une erreur
LOGICAL_ERRORdansarrayFoldappliquée à un argument non constant de typeArray(LowCardinality(T))(par exemplearrayFold((acc, x) -> acc + x, materialize([1, 2, 3]::Array(LowCardinality(Int64))), toInt64(0))), qui échouait avec le message « Arguments of ‘plus’ have incorrect data types » (provoquant l’arrêt du serveur dans les builds debug et sanitizer). #109462 (groeneai). - Correction d’une exception
ILLEGAL_COLUMNdansconv: les argumentsFixedStringsont désormais correctement convertis enString. #109771 (hp77-creator). - Correction de résultats incorrects lors de lectures via des fonctions de table avec
FINAL/SAMPLElorsqueserialize_query_plan = 1, et correction de la clé du cache de statistiques des tables de hachage d’agrégation pour les fonctions de table (auparavant, toutes les fonctions de table partageaient la même entrée de préallocation). #109847 (azat). - Correction de l’analyse des valeurs numériques
1/0en tant que valeursBooldans les types conteneurs (par exempleArray(Bool),Tuple(Bool, ...)). Auparavant,[1,0]échouait avecCANNOT_READ_ARRAY_FROM_TEXT, alors que[true,false]fonctionnait. #109976 (groeneai). - Correction de l’erreur
NOT_IMPLEMENTED(Method getDataAt is not supported for Nullable(String) in case if value is NULL) survenant lorsqu’un indextextest construit surArray(LowCardinality(Nullable(String)))(y compris les champsNestedstockés de cette manière) et qu’un tableau indexé contient un élémentNULL. Les élémentsNULLdes tableaux sont désormais ignorés lors de la construction de l’index, comme c’est le cas pourArray(Nullable(String)). #110055 (groeneai). - Correction de résultats incorrects de
subBitmap,bitmapSubsetInRangeetbitmapSubsetLimitpour les bitmaps encore stockés dans la représentation compacte, y compris pour les valeurs d’élémentsUInt64etInt64supérieures à2^32, qui étaient tronquées à 32 bits. Les comparaisons effectuées par les fonctions bitmap sur des types d’éléments signés utilisent désormais systématiquement la valeur non signée du type d’élément : dans un bitmapInt8, l’élément-1est ainsi comparé en tant que255et non en tant que valeur étendue par le signe4294967295. Cela corrige égalementbitmapMin,bitmapMax,bitmapContainsetbitmapTransformsur les bitmaps ayant dépassé la représentation compacte. Les requêtes qui transmettaient des seuils étendus par le signe doivent être adaptées : sur un bitmapInt8,bitmapSubsetInRange(bm, 4294967168, 4294967296)devientbitmapSubsetInRange(bm, 128, 256). Correction également degroupNumericIndexedVector, qui renvoyait pour les colonnes d’indexInt8etInt16des résultats différents de ceux obtenus avec des types d’index plus larges, ainsi que denumericIndexedVectorGetValue, qui renvoyait0pour les index négatifs. La documentation des fonctions bitmap a été corrigée, notamment pour les fonctions de sous-ensemble décrites à tort comme utilisant une indexation à partir de 1, et pour la prise en charge des types signés parbitmapBuild/bitmapToArray. #110072 (RamiDarwiche). - Correction de cas de dépassement de capacité signé au comportement indéfini dans l’arithmétique des intervalles, pour
WITH FILL STEPde type intervalle et pour les fonctions d’intervalle date/heureadd*/subtract*avec des écarts extrêmes : les valeurs d’intervalle extrêmes produisent désormais un résultat déterministe au lieu de dépendre d’un dépassement de capacité signé. Correction également d’un blocage deWITH FILLde type intervalle avec un très grand pasYEAR, qui faisait auparavant reculer le calendrier. #110158 (groeneai). - Correction d’une explosion du temps d’exécution en complexité quadratique (et de l’absence de prise en compte de
max_execution_time) lors de l’agrégation dans l’ordre avec un regroupement sur plusieurs clés dont l’ordre de tri ne constitue qu’un préfixe de la clé de regroupement. #110159 (alexey-milovidov). - Correction des comparaisons qui levaient auparavant
ILLEGAL_TYPE_OF_ARGUMENTlorsque les opérandes n’avaient pas de supertype commun minimal. Les tableaux tels queArray(Int64)etArray(UInt64), ouArray(Int256)etArray(UInt256), peuvent désormais être comparés lexicographiquement avec=,!=,<,<=,>,>=,IS DISTINCT FROMetIS NOT DISTINCT FROM. Les comparaisons compatibles avecNULLtelles queisDistinctFrom/isNotDistinctFromcomparent également par valeur les paires numériques ou décimales (hors tableaux) prises en charge, au lieu de lever une exception. Les comparaisons d’égalité fonctionnent aussi pour les tableaux contenant des élémentsTuple(Nullable(...))imbriqués. #110245 (diegomestre2). - Correction d’un dépassement de capacité d’entier signé (UBSan) lors de la conversion d’une valeur
DateTime64extrême (par exempleINT64_MIN) enTime/Time64dans un fuseau horaire à décalage négatif. #110451 (groeneai). - La conversion des valeurs à virgule flottante hors plage (
BFloat16,Float32,Float64) et des valeursUInt64supérieures àInt64::max()enDateTimeetTimesature désormais de manière fiable aux bornes de la plage sur toutes les architectures (auparavant, le résultat d’une conversion hors plage dépendait de l’architecture et pouvait reboucler sur x86-64), et les valeurs non finies (NaN,inf) lèvent désormais une exception au lieu de produire un résultat arbitraire. Le même correctif s’applique au chemin de conversion des flottants versDatedetoDate, ainsi qu’aux conversions deUInt64et des entiers larges ((U)Int128,(U)Int256) enDateetDate32, qui pouvaient renvoyer un jour antérieur à l’epoch au lieu de saturer. La conversion d’un nombre enTimesature désormais à la plage du type, quel que soit le type numérique source (auparavant, les valeurs issues d’entiers non signés étroits ou d’entiers larges étaient stockées sans écrêtage et n’étaient écrêtées qu’à l’affichage). Par ailleurs, le cast exact versTimene rejette plus les valeurs négatives prises en charge parTimeet ne sature plus silencieusement les valeurs qui ne peuvent pas y être représentées. Le cast exact d’un nombre versDate32(accurateCast,accurateCastOrNull) ne sature plus silencieusement une valeur hors plage ou non finie : il lève une exception ou renvoieNULL, comme c’était déjà le cas pourDateetDateTime, et les variantesOrDefaultrenvoient la valeur par défaut deDate32pour une telle entrée. Le cast exact d’un nombre à virgule flottante non entier versDate,Date32,DateTimeouTimeest désormais rejeté au lieu d’être silencieusement tronqué. Correction également de la documentation de la fonctiontoDateTime32, qui affichait par erreur des exemples detoDateTime64et décrivait la plage de valeurs deDateTime64. #110459 (alexey-milovidov). - Correction de l’échec de l’inférence de schéma avec l’erreur
Map cannot have a key of type LowCardinality(Nullable(String))lors de la lecture de fichiers ORC dont les clés de map sont encodées par dictionnaire, y compris les fichiers ORC écrits par Spark et ceux écrits par ClickHouse lui-même lorsqueoutput_format_orc_dictionary_key_size_thresholdest activé. #110492 (tiandiwonder). - Correction d’une erreur logique (
Function node with name '...' is not resolved as ordinary function) pouvant survenir lorsqueoptimize_or_like_chainétait activé et qu’une fonction d’agrégation ou une fonction de fenêtre figurait à gauche d’unLIKE/ILIKE/matchau sein d’une chaîneOR. #110641 (groeneai). - Correction d’un dépassement de capacité d’entier signé dans
toStartOfIntervalavec un nombre extrême d’intervallesMONTH,WEEKouDAYsur des valeursDate/Date32/DateTime64. #110688 (groeneai). - Correction de
readWKTetreadWKTPoint, qui renvoyaient pourPOINT EMPTYdes coordonnées non initialisées (en mode scalaire) ou obsolètes, issues de la ligne précédente (en mode vectorisé).POINT EMPTYest désormais rejeté avecCANNOT_PARSE_TEXT, car unPointClickHouse est unTuple(Float64, Float64)fixe, dépourvu de représentation vide. #110692 (groeneai). - Correction de
flipCoordinates, qui perdait le typeGeometry: pour un argumentGeometry, le résultat est de nouveau typéGeometryau lieu duVariant(...)sous-jacent, ce qui permet de le passer directement à des fonctions commeareaCartesian. #110694 (groeneai). - Correction de la sérialisation WKB non canonique d’un polygone vide :
wkb(POLYGON EMPTY)émet désormaisnumRings = 0au lieu d’un anneau parasite unique à zéro point, de sorte qu’un aller-retour WKB d’un polygone vide standard restitue une valeur identique. #110796 (groeneai). - Les valeurs numériques
1/0lors de l’analyse deBoolen JSON respectent désormais le paramètreallow_special_bool_values. Auparavant, une entrée JSON telle que{"v":1}pourVariant(Bool, UInt32)était lue commeBoolmême avecallow_special_bool_values_inside_variant = 0, car les analyseurs JSON deBoolignoraient ce paramètre etBoolbénéficie d’une priorité de désérialisationVariantplus élevée que les types entiers. #110835 (groeneai). - Correction de
throwIf(notLike(col, pattern))(et d’autres appelsthrowIfappliqués à une fonction) qui levait systématiquement une exception lorsquecolest de typeLowCardinality. L’implémentation par défaut deLowCardinalityexécutaitthrowIfsur l’ensemble du dictionnaire, lequel contient toujours la valeur par défaut réservée, même lorsqu’aucune ligne n’y fait référence ; une valeur non nulle dans cet emplacement inutilisé amenait doncthrowIfà lever une exception pour des données ne satisfaisant pas la condition. #110864 (groeneai). - Correction d’un plantage lorsqu’une fonction d’agrégation avec le combinateur
-Tupleétait utilisée avecRESPECT NULLSet produisait un état intermédiaire (-State, agrégation distribuée,WITH ROLLUP/WITH CUBE). La fonction combinée portait le nom d’une variante d’état erronée, si bien que son typeAggregateFunctionsérialisé était de nouveau résolu vers une disposition en mémoire incompatible lors d’un aller-retour. #110930 (groeneai). - Correction de l’erreur
Nested type LineString cannot be inside Nullable type (ILLEGAL_TYPE_OF_ARGUMENT)lors de la lecture d’une colonne spatiale MySQL nullable (LINESTRING,POLYGON,MULTILINESTRING,MULTIPOLYGON,MULTIPOINTou le type génériqueGEOMETRY) via la fonction de tablemysqlou les moteurs de table/base de donnéesMySQL. Ces colonnes sont désormais converties par défaut enNullable(String), qui contient la valeur telle que MySQL la renvoie (un préfixe SRID de 4 octets suivi de la charge utile WKB).POINTreste associé àNullable(Point). #110943 (groeneai). - Correction de la sérialisation
Nativedes wrappersSimpleAggregateFunctioncontenant des états d’agrégation versionnés à destination des pairs plus anciens. #110997 (groeneai). - Correction de l’erreur
CANNOT_CONVERT_TYPEpour les constantes de typeVariant(y comprisGeometry) dans les requêtes distribuées et les requêtes utilisant des répliques parallèles. #111136 (fm4v). - Correction d’une erreur
LOGICAL_ERROR(“Lambda resolved type … is not equal to type from actions DAG …”) lorsque le corps de la lambda d’une fonction d’ordre supérieur est unif/multiIfà condition constante combinant une branche littéraleBoolet une branche de comparaisonUInt8, par exemplearrayFilter(p -> multiIf(false, true, p = 'ALL'), ['ALL']). #111245 (groeneai). - Correction d’un dépassement de capacité d’entier signé dans
toStartOfIntervalavec des intervalles inférieurs à la seconde : pour les valeursDateTime64situées à moins d’un intervalle de la borne inférieure deInt64, le résultat arrondi bouclait silencieusement vers une valeur positive aberrante ; la fonction lève désormais une exceptionDECIMAL_OVERFLOW. #111370 (alexey-milovidov). - Correction d’une exception (
CANNOT_CONVERT_TYPEou erreur logique) dans les requêtes distribuées utilisant le combinateur-Tupleavec un modificateurRESPECT NULLS/IGNORE NULLSsous des combinateurs imbriqués, par exempleanyRespectNullsStateTuple(...) IGNORE NULLS. #111570 (alexey-milovidov). - Corrige une tentative d’analyse textuelle de
FixedStringqui laissait des octets partiellement ajoutés dans la colonne en cas d’échec de l’analyse, ce qui pouvait provoquer une erreur logiqueSizes of nested column and null map of Nullable column are not equallors de la sérialisation de colonnesVariant/Array/Nullable, ou un décalage silencieux des octets du résultat. #111908 (groeneai). - Correction d’une exception et de données ignorées silencieusement lors de la lecture d’une sous-colonne dynamique (un chemin à l’intérieur d’une colonne
JSONouDynamic) via une tableBuffer. #111948 (alexey-milovidov). - Correction d’une complexité quadratique dans
countSubstringsCaseInsensitiveUTF8, qui pouvait faire durer la fonction plusieurs minutes sur une chaîne de quelques mégaoctets comportant de nombreuses correspondances. Le décalage en caractères de chaque correspondance est désormais calculé de manière incrémentale au lieu d’être recompté depuis le début de la ligne. #112003 (groeneai). - Correction d’un dépassement d’entier signé dans la surcharge à trois arguments de
toStartOfInterval: pour un argumentoriginproche de la borne inférieure deInt64, la fonction renvoyait une valeur ayant bouclé au lieu de signaler une erreur. #112045 (alexey-milovidov). - Les états d’agrégation sont désormais interdits dans les paramètres des fonctions de table, car ils n’y sont pas du tout pris en charge. #112087 (PedroTadim).
- Correction de la fonction de table
values, qui rendait une constanteBoolnon littérale (par ex.CAST(true, 'Nullable(Bool)')) insérée dans une colonneString/textuelle sous la forme1/0au lieu detrue/false. #112308 (yakov-olkhovskiy). - Corrige une erreur logique (qui provoque un arrêt dans les builds de débogage et avec sanitizer) lorsque
finalizeAggregationest appliquée à une colonne dont les états d’agrégation proviennent de fonctions différentes partageant une même représentation d’état mais produisant des types finaux différents — par exemplequantileStateetquantilesState(0.9)réunis par unUNIONou produits viaarrayReduce. Ces requêtes lèvent désormais une erreur ordinaire au lieu de planter. #112662 (zainulabidin302). - Correction de l’analyse des entiers ne tenant pas dans le type cible dans
Poco::NumberParser, utilisé pour lire les nombres JSON. Un tel nombre était silencieusement converti en une valeur erronée (par exemple,18446744073709551617devenait1) au lieu d’être rejeté, et un nombreUInt64supérieur au maximum deInt64ne survivait pas à un aller-retour JSON de l’AST. #112904 (alexey-milovidov). - Correction d’une constante
Boolsituée à droite deIN, qui était convertie en'1'/'0'pour un membre gauche de typeStringau lieu des valeurs canoniques'true'/'false'(comportement désormais cohérent avecCASTet la fonction de tablevalues). #113051 (yakov-olkhovskiy). - Correction d’un formatage incohérent de l’AST pour
viewIfPermitted: une fonction normalement écrite sous forme d’opérateur (par ex.not) dans la brancheELSEde la forme fonction de table, et la forme expressionviewIfPermitted(...)formatée à tort avecELSE. #113652 (alexey-milovidov). - Correction d’un comportement indéfini et de résultats erronés de
avgsurDate/DateTime/DateTime64/Time/Time64: la moyenne est désormais calculée de manière exacte dans l’espace des entiers, ce qui corrige à la fois le dépassement de capacité à la limite deInt64(UB, résultat erroné sur x86) et la perte de précision deFloat64au-delà de 2^53 (visible à l’échelle de la nanoseconde). #113912 (alexey-milovidov). - Correction d’une fuite de mémoire dans le codec de compression expérimental
SZ3: lorsque la compression de données peu compressibles ou corrompues échouait avec une exception, des tampons de travail temporaires n’étaient pas libérés. #113916 (alexey-milovidov). - Correction de
hasAny,hasAll,has,indexOf,mapContainsKey,mapContainsValueetmapContains, qui renvoyaient trop peu de lignes ou échouaient avecTOO_LARGE_STRING_SIZElorsqu’un indexbloom_filterétait interrogé avec une constanteFixedString. L’index hachait la forme complétée de la constante alors que la fonction compare la forme non complétée, si bien qu’un granule correspondant était ignoré. #114089 (alexey-milovidov). - Correction de
minetmaxsur les colonnesDateTime64, qui renvoyaient des résultats erronés lorsque l’agrégat était compilé JIT et que les données contenaient des timestamps antérieurs à 1970.is_signedn’était pas spécialisé pourDateTime64etTime64, qui dérivent deDecimal64; le code généré comparait donc les nombres de ticks comme des entiers non signés, de sorte qu’un timestamp antérieur à 1970 était à tort retenu parmaxet écarté parmin. #114168 (groeneai). - Correction de
arrayExists(x -> x = needle, arr), qui renvoyait un résultat erroné ou échouait avecTOO_LARGE_STRING_SIZElorsque l’élément du tableau et le needle étaient de types string différents (par exemple un needleStringcomparé à un élémentArray(FixedString(N))). L’optimisationoptimize_rewrite_array_exists_to_has, activée par défaut, réécrivait un tel appel enhas, qui, contrairement à=, ne tient pas compte de la complétion par des zéros lors de la comparaison. #114496 (groeneai). - Correction de l’évaluation par l’index de texte de l’opérateur
LIKE/ILIKEappliqué à des conteneurs Map ou JSON. #114544 (ahmadov). - Correction d’un comportement indéfini et de résultats incorrects aux bornes dans
quantileetquantilespour les valeursDateTime64etDecimallarges. #114919 (alexey-milovidov). - Correction de
ifetmultiIf, qui renvoyaient une grande valeur positive au lieu d’une valeur négative lorsqu’une brancheTimeétait combinée avecTime64,DateTimeouDateTime64et que l’expression était compilée JIT. #115146 (groeneai). - Correction de
timezoneOffset(aliastimeZoneOffset), qui renvoyait un décalage erroné d’exactement un jour pour les time zones dont le décalage UTC diffère d’un jour entier de leur décalage au 1970-01-01, commePacific/KiritimatietPacific/Apiaaprès le franchissement de la ligne de changement de date, ainsi que pour la plupart des fuseaux avant 1970. Cela corrige égalementparseDateTime,parseDateTimeOrNull,parseDateTime64,parseDateTimeInJodaSyntax,EXTRACT(TIMEZONE_HOUR / TIMEZONE_MINUTE ...), le%zdeformatDateTime,toUTCTimestampetfromUTCTimestamp, qui s’appuient sur ce décalage. #115332 (groeneai). - Correction de l’erreur
Code: 349. Cannot convert NULL value to non-Nullable typelorsqu’un prédicathasounotHascontient un élément de tableau NULL et que la clé primaire est de typeString,Array(String)ouMap(String, String), ainsi que des résultats incorrects lorsque cet élément est unDynamicou unVariantcontenant NULL. La valeur NULL est désormais retirée du set lors de l’analyse de la clé, comme c’était déjà le cas pour les autres types de clé. #115647 (groeneai). - Correction de
cast_keep_nullable, qui ne préservait pas le caractère nullable lorsque le type cible étaitLowCardinality. La conversion d’une valeur susceptible d’être NULL versLowCardinality(T)levait l’erreurCANNOT_INSERT_NULL_IN_ORDINARY_COLUMNau lieu de produireLowCardinality(Nullable(T)). #115851 (groeneai).
Corrections relatives aux index et au cache de requêtes
- Correction de la lecture des sous-colonnes d’une colonne qui possède une expression
DEFAULTet qui n’est pas matérialisée dans une partie de données (par exemple aprèsALTER TABLE ADD COLUMNou pendantALTER TABLE MATERIALIZE COLUMN) : la sous-colonne était remplie avec les valeurs par défaut du type au lieu de l’expressionDEFAULTévaluée, et les fonctions de distance vectorielle transposées (cosineDistanceTransposedet autres) appliquées à ces colonnesQBitéchouaient avec l’erreurSIZES_OF_ARRAYS_DONT_MATCH. #110636 (alexey-milovidov). - Correction de l’exception
Not-ready Set is passed as the second argumentqui pouvait survenir lorsque la construction d’un set de sous-requêteINpendant l’analyse de la clé primaire échouait silencieusement (par exemple, en cas de dépassement du délai d’une sous-requête avecoverflow_mode = 'break'), le set n’étant alors jamais construit pour le pipeline de la requête. #107924 (alexey-milovidov). - Correction d’un
SELECTqui échouait avecNOT_FOUND_COLUMN_IN_BLOCKsur une table dotée d’un index de saut de donnéessetlorsqu’une politique de lignes la filtre à l’aide d’une condition toujours vraie combinée à une vérification sur une colonne non indexée. #107971 (tiandiwonder). getClientHTTPHeaderest désormais correctement traitée comme non déterministe : son résultat n’est donc plus réutilisé à tort par le cache des résultats de requêtes. #108029 (alexey-milovidov).- Correction de résultats erronés lorsque le cache des conditions de requête (
use_query_condition_cache = 1) réutilisait une exclusion de marques issue d’un index de saut pour une requête ayant exécuté un ensemble différent d’index de saut, par exemple avecuse_skip_indexes = 0,ignore_data_skipping_indicesou un modeuse_skip_indexes_for_disjunctionsdifférent. Les entrées du cache issues des index de saut ont désormais pour clé l’ensemble effectif des index de saut exécutés, tandis que les entrées du cache des conditions de requête au niveau des lignes restent réutilisables dans tous ces cas. #108548 (groeneai). - Correction d’un blocage : une requête lisant via le cache du système de fichiers pouvait continuer d’attendre la fin d’un téléchargement en cours après avoir été annulée avec
KILL QUERY, et la suppression d’une vue matérialisée actualisable, ou l’exécution deSYSTEM STOP VIEWsur celle-ci, restait bloquée lorsque son rafraîchissement était coincé dans une telle attente. #109116 (murphy-4o). - Correction de résultats de requête erronés dus à l’élagage incorrect de granules par l’index de clé primaire pour les tables ayant une colonne de clé inversée (
DESC) lorsque les parties de données n’ont pas de marque finale (granularité non adaptative,index_granularity_bytes = 0). #109901 (nihalzp). - Correction de l’erreur logique
Expected CommonSubplanReferenceStep to reference CommonSubplanStep, de l’erreurSubplan cannot be used to build pipelineet de l’erreur logiqueTrying to extract chunk from ChunkBuffer before all inputs are finishedpourIN (subquery)lorsque la sous-requête contient une sous-requête corrélée et que le set est construit pendant l’analyse des index. #110491 (alexey-milovidov). - Correction de l’erreur
NOT_FOUND_COLUMN_IN_BLOCKpour les fonctions de distance transposées sur des colonnesQBit(commecosineDistanceTransposed) appelées avec un vecteur de référence constant ou issu d’une sous-requête scalaire lorsque les répliques parallèles sont activées. #110729 (alexey-milovidov). - Correction d’un index de texte qui n’était pas utilisé lorsque son expression contenait une comparaison avec une chaîne vide telle que
arrayFilter(s -> s != '', ...), car le paramètreoptimize_empty_string_comparisonsréécrit la comparaison ennotEmptyuniquement côté requête. #112115 (Ergus). - Les colonnes ne sont plus supprimées lorsqu’elles sont référencées à la fois dans les conditions de filtrage
PREWHEREetWHERE, même si elles sont réécrites en colonne virtuelle d’index de texte. #114460 (ahmadov). - Correction de l’erreur logique
Multi-block postings must be compresseddans les requêtes portant sur des tables dotées d’un index de texte en mode d’application différée des posting-lists, lorsque la requête était annulée pendant la lecture. #114636 (CurtizJ). - Correction de résultats erronés lorsqu’une clause
WHEREcontenait une expressionNULLsous unNOT, par exempleSELECT count() FROM t WHERE NOT (id >= 20 AND NULL). L’analyse d’index considérait à tort une telle condition comme toujours vraie sur l’ensemble de la plage, si bien que le filtre était ignoré :count()renvoyait des lignes rejetées par la requête, etALTER TABLE ... DELETEavec cette condition supprimait des lignes qui auraient dû être conservées. #115152 (groeneai). - Correction d’une
LOGICAL_ERROR(Join is supported only for pipelines with one output port) pour une jointurefull_sorting_mergeavecquery_plan_join_shard_by_pk_rangesactivé, lorsque l’un des deux côtés ne contient plus aucune partie de données après élagage, que ce soit par la clé primaire, par les statistiques de colonne ou parce que la table est vide. #115352 (alexey-milovidov). - Désactivation du cache des conditions de requête pour les filtres portant sur _part_starting_offset #115358 (azat).
- Correction de
LOGICAL_ERROR: Index with name auto_minmax_index_<column> already existslorsqu’un même statementALTER TABLEcombinaitRENAME COLUMNavec une autre commande, telle queMODIFY SETTING, sur une table dotée d’index minmax implicites (add_minmax_index_for_numeric_columnset paramètres associés). Par ailleurs, le renommage d’une colonne ordinaire ne fait plus échouer unDROP COLUMNultérieur avecUNKNOWN_IDENTIFIER, et ne prive plus unADD COLUMNultérieur de son index implicite. #116063 (groeneai). - Un motif
LIKE/NOT LIKEsans jokers (%,_) utilise désormais une plage exacte de clé primaire : il lit donc le même nombre de granules que le prédicat=/!=équivalent, au lieu d’une plage de préfixe plus large. #107077 (groeneai). - Correction d’une
LOGICAL_ERROR(Invalid binary search result in MergeTreeSetIndex) et d’un élagage d’index manqué dans les builds de production lorsqu’une conditionIN/NOT INsur la clé primaire encapsule la clé dans unintDivpar une constante et que la clé est un entier non signé dont les valeurs franchissent la limite signée du type de résultat deintDiv(par exempleintDiv(uint64_column, -9223372036854775807)). #107586 (groeneai). - Correction de
numericIndexedVectorPointwiseMultiply, qui renvoyait un résultat vide lors de la multiplication par un vecteur composé uniquement de uns ayant une configuration de bits BSI différente. #108027 (alexey-milovidov). - Correction d’un heap-buffer-overflow lors de la construction d’un index de texte avec
positions = 1sur de nombreux jetons courts distincts. #108659 (groeneai). - Les expressions
preprocessoretpostprocessord’un index de texte peuvent désormais référencer des colonnesALIAS. #110014 (Ergus). - L’optimisation de la recherche vectorielle est désormais ignorée lorsque
LIMIT ... WITH TIESest utilisé : cette optimisation limite la recherche ANN à exactement n candidats, ce qui entraîne la suppression des lignes à égalité avec la n-ième ligne. #110453 (tamish560). - Correction de la non-utilisation de l’index de texte pour
ILIKElorsque l’index est défini sur une expression plutôt que sur une simple colonne (par exempleassumeNotNull(col)avec un préprocesseurlower(...)). Ces requêtes utilisent désormais l’index au lieu de lire l’ensemble des granules. #110595 (ahmadov). - Correction d’une erreur
LOGICAL_ERROR(LazyMaterializingTransform: Number of rows in lazy chunk N does not match number of offsets M) qui pouvait survenir dans les requêtes de recherche vectorielle utilisantvector_search_with_rescoring = 1conjointement avec la matérialisation différée, lorsque plusieurs distances étaient à égalité. #111003 (groeneai). - Rejet des vecteurs dont la norme au carré provoque un dépassement de capacité vers l’infini lors de l’utilisation d’un index
vector_similarityavec une quantificationi8(auparavant, ces vecteurs déclenchaient un comportement indéfini dans usearch et produisaient silencieusement des résultats incohérents). #111085 (groeneai). - Correction de lectures obsolètes sur les disques
plain_rewritablelorsque le cache de pages est activé. #111105 (Michicosun). - Correction de résultats
count()erronés et de lignes perdues lorsqu’une clé ou un index de saut minmax de typeString(ouFixedStringplus étroit) est filtré par une comparaison avec une constanteFixedStringplus large, par exempletoFixedString('abc', 257) = string_col. L’élagage par clé primaire et par minmax construisait la plage à partir de la constante complétée par des caractères NUL, et ignorait donc à tort des granules correspondants. #111106 (groeneai). - Correction de la lecture des fichiers Parquet dont l’index des offsets ne commence pas à la ligne 0. Un tel fichier pouvait amener le lecteur Parquet natif à renvoyer des lignes erronées, ou à signaler
LOGICAL_ERRORau lieu deINCORRECT_DATA. L’index des offsets est désormais validé au moment de sa lecture. #114530 (groeneai).
Correctifs liés à la sécurité, à l’accès, à la sauvegarde et à la restauration
RESTOREeffectue désormais un fsync des fichiers des parties de données restaurées lorsquefsync_after_insertest activé sur la table de destination, de sorte qu’une partie de données restaurée résiste aussi bien à une coupure de courant qu’une partie insérée. Auparavant, les fichiers restaurés étaient seulement écrits puis fermés (sans aucun fsync) : une coupure de courant survenant juste après queRESTOREa renvoyéRESTOREDpouvait donc laisser des parties de données corrompues et une table vide. #111378 (groeneai).- Correction d’un problème de sécurité qui permettait à un client TCP non authentifié de sonder l’existence de tables et l’état de la réplication via le port interserveur. #99854 (tiandiwonder).
- Correction de
DELETE FROM(lightweight delete), qui exigeait le privilègeALTER UPDATEen plus deALTER DELETE. Un utilisateur disposant uniquement du grantALTER DELETEpeut désormais exécuterDELETE FROM, conformément à la documentation. #107491 (tiandiwonder). - Correction de
CREATE TABLE ... AS SELECTsur les bases de données Atomic, qui laissait derrière lui une table vide en cas d’échec de la requête — par exemple lorsque l’utilisateur n’a pas accès à une table référencée dans une sous-requête. Auparavant, une nouvelle tentative signalait que la table existait déjà au lieu de renvoyer l’erreur d’origine. La table est désormais créée via une table temporaire et ne devient visible qu’une fois entièrement remplie. #108048 (alexey-milovidov). - Correction d’une
LOGICAL_ERROR(No available columns) lors de l’exécution deSELECT count()(ou d’autres requêtes triviales) sur une table pour laquelle l’utilisateur ne dispose de l’accèsSELECTque sur une colonneALIAS. #108056 (alexey-milovidov). - Correction d’un problème qui permettait à des requêtes non authentifiées d’amener ClickHouse à résoudre des noms d’hôte fournis dans les en-têtes d’adresse client transférée. ClickHouse n’accepte désormais que des adresses IP numériques dans ces en-têtes. Les valeurs invalides sont ignorées, sans résolution DNS, pour l’attribution des quotas par adresse transférée. Lorsque
auth_use_forwarded_addressest activé, les adresses transférées invalides sont rejetées lors de l’authentification. Les rejets sont journalisés au niveau debug. #111060 (otselnik). - Correction de
SQL SECURITY DEFINER(etSQL SECURITY NONE), qui n’était pas respecté pour les vues paramétrées lorsque l’analyseur est désactivé (enable_analyzer = 0). Auparavant, une sélection sur une telle vue par un utilisateur sans privilèges sur la table sous-jacente échouait avecACCESS_DENIED, alors que la même vue fonctionne lorsque l’analyseur est activé. #111458 (groeneai). - Correction d’un défaut dans les intégrations
MySQL: le remplacement d’un identifiant TLS d’une collection nommée par une valeurssl_ca_pem/ssl_cert_pem/ssl_key_pemvide était accepté lorsque la collection stockait l’identifiant sous forme de contenu, ce qui supprimait silencieusement le CA ou le certificat client configuré au lieu de rejeter le remplacement. #113947 (alexey-milovidov). - Correction de
EXPLAIN ANALYZE, qui perdait les statistiques de jointure d’une vue déclaréeSQL SECURITY DEFINERouSQL SECURITY NONEdont le corps contient un JOIN. Dans les builds debug et sanitizer, la requête s’interrompait avec l’erreur logiqueJoinStep analyzed without the analyze mode. #115156 (groeneai). - Correction de
RESTORE ... AS <new name>, qui laissait la listeREFRESH ... DEPENDS ONd’une vue matérialisée actualisable pointer vers la base de données d’origine. La vue restaurée se rafraîchissait en réaction à une table qu’elle ne lisait plus, ignorait les rafraîchissements de son propre parent et cessait complètement de se rafraîchir dès que la base de données d’origine était supprimée. #115689 (groeneai). - Correction d’une exception
LOGICAL_ERRORlors de la sauvegarde d’une base de donnéesReplicatedsupprimée et recréée simultanément ; ces sauvegardes échouent désormais proprement avecCANNOT_GET_REPLICATED_DATABASE_SNAPSHOT. #100651 (alexey-milovidov). GRANT role TO roleappliqué à un même rôle est désormais rejeté avecBAD_ARGUMENTS, au lieu de créer silencieusement une entrée autoréférente danssystem.role_grants. #103315 (zxuhan).- Le
BACKUPd’une base de donnéesMaterializedPostgreSQLne reste plus bloqué indéfiniment avec le message « Table … were created or changed its definition during scanning » : il sauvegarde désormais réellement les données de la table (en déléguant auReplacingMergeTreesous-jacent), qui peuvent être restaurées sous forme deReplacingMergeTreeautonome. #107433 (alexey-milovidov). EXISTS <dictionary>est désormais autorisé pour un utilisateur disposant uniquement du privilègeSHOW DICTIONARIESsur le dictionnaire (auparavant,SHOW TABLESétait requis). #108084 (alexey-milovidov).- Correction du nettoyage d’un
BACKUP ... TO Memory(...)qui échoue avant sa finalisation : la sauvegarde en échec restait enregistrée, ce qui empêchait de réutiliser son nom. #109947 (jkartseva). - Correction d’une erreur logique
ReadBuffer is canceled. Can't read from it.(arrêt brutal du serveur dans les constructions debug/sanitizer) pouvant survenir lors de la lecture d’une archive zip (par exemple pendant unRESTOREdepuis une sauvegarde zip) lorsqu’une lecture précédente de la même archive avait échoué en cours de flux. #110197 (groeneai). - Correction d’une corruption du tas, susceptible de faire planter le serveur lors de son arrêt, causée par la méthode
constAccessRights::getFilters, qui modifiait un arbre de droits d’accès partagé par des requêtes concurrentes. #112692 (groeneai).
Exécution distribuée, tables, vues et dictionnaires
- Correction d’une erreur
Inconsistent AST formattinginjustifiée pourALTER TABLE ... MOVE PART ... TO SHARD '<path>'. Le formateur de requêtes omettait le mot-cléSHARD, si bien que la requête reformatée ne pouvait plus être analysée, ce qui provoquait uneLOGICAL_ERROR(une exception gérée dans les builds de production, un arrêt brutal dans les builds de débogage et avec sanitizers). #109060 (groeneai). - Correction d’une erreur logique (
!part.empty()) lorsqu’une tableDistributeddéfinie avec un nom de base de données distante vide est utilisée dans un JOIN avecdistributed_product_mode = 'local'. #110677 (groeneai). - Correction de
DISTINCTavec unLIMIT/OFFSETordonné, qui renvoyait des lignes incorrectes lorsque l’indice de limite d’arrêt anticipé de DISTINCT ne pouvait pas borner le début du résultat : unLIMITnégatif (le début était renvoyé au lieu de la fin), unLIMIT/OFFSETfractionnaire (la fraction n’est résolue qu’après une lecture complète) et unOFFSETseul sansLIMIT(la fin située après la position était ignorée). Par exemple,SELECT DISTINCT intDiv(x, 100) FROM t ORDER BY intDiv(x, 100) LIMIT -1sur une table comportant plusieurs parties de données renvoyait la plus petite valeur distincte au lieu de la plus grande. #111326 (groeneai). - Correction du cas où un alias placé après une sous-requête dans DESCRIBE TABLE était refusé par le parseur et provoquait une erreur de syntaxe. Corrige https://github.com/ClickHouse/ClickHouse/issues/100031. #100205 (yariks5s).
- Correction d’un arrêt brutal du serveur (
Logical error: 'Block structure mismatch') pouvant survenir lors d’unINSERTconcurrent pendant l’exécution d’unALTER RENAME COLUMNdans une base de donnéesAtomicaveclazy_load_tables = 1après unDETACH DATABASE/ATTACH DATABASE. #104852 (groeneai). - Correction de la corruption des noms de colonnes et de l’exception
BAD_ARGUMENTSprovoquées par le paramètreinject_random_order_for_select_without_order_by. Lorsque ce paramètre est activé, les SELECT portant sur plusieurs colonnes n’échouent plus et les noms des colonnes en sortie (par exemple pourCREATE TABLE AS SELECT,CREATE VIEW AS SELECT,JSONEachRow) sont conservés au lieu d’être remplacés par des alias internes__subquery_column_<UUID>. #105896 (groeneai). - Correction d’un indice trompeur « Maybe you meant X? » après un redémarrage du serveur (ou un
DETACH/ATTACH DATABASE) : lors de la suppression d’une table déjà supprimée, le nom qui venait d’être supprimé était proposé comme alternative. Les tâches de chargement asynchrone sont désormais retirées deDatabaseOrdinary::startup_tableet deload_tablelors du détachement. #106238 (groeneai). - Correction des moteurs de table et de base de données
MaterializedPostgreSQLafin qu’une table ou une base de données isolée puisse être répliquée depuis un schéma PostgreSQL autre que celui par défaut (materialized_postgresql_schema), y compris lorsque des tables portant le même nom existent dans plusieurs schémas de la même base de données (auparavant, elles partageaient une publication et un slot de réplication, et interféraient entre elles). #107425 (alexey-milovidov). - Correction de
NO_SUCH_COLUMN_IN_TABLElorsqu’une requête utilisant des répliques parallèles sélectionne une colonneALIASd’une table transmise en tant que table temporaireGLOBAL JOIN, deMULTIPLE_EXPRESSIONS_FOR_ALIASlorsque les deux côtés d’unJOINdistribué déclarent une colonneALIASportant le même nom, et deUNKNOWN_IDENTIFIERlorsqu’une tableDistributeddéclare une colonneALIASreposant sur une autre colonneALIAS, y compris en tant que clé deJOIN USING. #107700 (yakov-olkhovskiy). - Correction d’un dépassement de capacité d’entier signé lorsqu’une vue matérialisée actualisable relance un rafraîchissement ayant échoué alors que
refresh_retriesest défini sur une valeur très élevée (proche du maximum deInt64). Ce dépassement de capacité pouvait provoquer l’arrêt brutal du serveur dans les constructions utilisant le sanitizer de comportement indéfini. #108005 (groeneai). - Correction d’une exception (
CANNOT_PARSE_TEXT) lors du chargement d’un dictionnaire doté d’une clé composite dont les colonnes de clé ne sont pas les premières colonnes de la définition du dictionnaire, avec une sourceClickHouselocale utilisant une requête explicite. Les colonnes sources sont désormais associées à la structure du dictionnaire par leur nom et non plus par leur position. #108053 (alexey-milovidov). - Correction d’un plantage (déréférencement de pointeur nul) lors de l’interrogation d’une table
Hivesans clauseWHERE, par exempleSELECT * FROM hive_table. #108094 (alexey-milovidov). - Correction d’un plantage du serveur (erreur de segmentation) pouvant survenir lorsqu’une requête distribuée faisait référence à une CTE
MATERIALIZEDnon encore matérialisée en tant que table externe et que la source distante était créée de manière différée (lazy). Le plantage était dû au déréférencement d’unLoggernul dansRemoteQueryExecutor::sendExternalTables(). #108547 (groeneai). - Correction d’une erreur logique (
Equal values are not contiguous within the range assumed to be sorted) lors de l’exécution deDISTINCTsur une lectureSTREAM(SELECT DISTINCT ... FROM table STREAM). Les optimisations de lecture ordonnée ne sont plus appliquées aux lecturesSTREAM, qui renvoient les lignes dans l’ordre de validation et non dans l’ordre de la clé de tri. #108568 (groeneai). - Correction d’une exception (
Cannot find sharding key column, ainsi qu’un arrêt brutal du serveur dans les constructions debug/sanitizer) lorsque la clé de sharding d’une tableDistributedest une expression que l’analyseur simplifie par repli de constantes, par exempleif(1, toInt32(id), toInt32(id) + 1), avecoptimize_skip_unused_shards = 1. #108737 (groeneai). - Correction d’un arrêt brutal du serveur (
LOGICAL_ERROR/ assertion dans les constructions debug et sanitizer) lorsqu’unINSERT ... SELECTpassant par une tableAliasest annulé sans exception, par exemple avectimeout_overflow_mode = 'break'. #108783 (groeneai). - Correction d’un arrêt brutal du serveur (
LOGICAL_ERROR/ assertion dans les constructions debug et sanitizer) lorsqu’unINSERT ... SELECTvers une tableTimeSeriesest annulé sans exception, par exemple avectimeout_overflow_mode = 'break'. #108796 (tiandiwonder). - Correction d’échecs occasionnels de requêtes distribuées avec
UNEXPECTED_PACKET_FROM_SERVER(“expected TablesStatusResponse, got ProfileInfo”) lorsqu’une connexion laissée désynchronisée par une requête annulée précédemment était réutilisée depuis le pool. #108854 (alexey-milovidov). - Correction d’une
LOGICAL_ERROR(CTE '...' does not have query tree, but was not planned yet) lorsqu’une CTEMATERIALIZEDest référencée à plusieurs endroits de l’arbre de jointure (par exemple dans deux sous-requêtes jointes, ou dans une sous-requête jointe et une sous-requête scalaire dansWHERE) au sein d’une requête portant sur une tableDistributed. La requête s’exécute désormais au lieu de lever l’exception (qui provoquait l’arrêt brutal du serveur dans les constructions debug/sanitizer). #108924 (groeneai). - Corrige un problème de sécurité mémoire où des tâches asynchrones planifiées lors du traitement d’une vue matérialisée pouvaient continuer à utiliser la comptabilisation au niveau de la requête après la fin de celle-ci. #108988 (filimonov).
- Corrige une erreur
LOGICAL_ERROR(“Cannot find__grouping_setcolumn in header of MergingAggregatedTransform with grouping sets”, ou “Chunk info was not set for chunk in MergingAggregatedTransform”) qui pouvait survenir, sans l’analyseur, pour unUNION ALL/INTERSECT/EXCEPTdont une branche utiliseGROUP BY GROUPING SETSavec les répliques parallèles et une autre utiliseFINAL. #109003 (groeneai). - Corrige l’échec de
CREATE TABLE ... AS SELECT FROM s3Cluster(...)(et d’autres fonctions de table de cluster telles quefileCluster/urlCluster) avec l’erreurNOT_FOUND_COLUMN_IN_BLOCKdans une base de donnéesReplicated. #109266 (groeneai). - Corrige une erreur (
NOT_FOUND_COLUMN_IN_BLOCK, oustd::bad_function_calldans les versions antérieures) lors de l’exécution deCREATE TABLE ... ON CLUSTER ... AS SELECTlisant une tableDistributedsur un cluster comportant au moins deux shards. #109407 (alexey-milovidov). - Corrige une erreur interne déroutante (
Method getResultType is not supported for TABLE query tree node) lorsqu’une expression de table était utilisée comme argument gauche de l’opérateurIN; ces requêtes produisent désormais un message d’erreur explicite. #109412 (alexey-milovidov). - Corrige l’erreur logique
Bad cast from type DB::FunctionNode to DB::ConstantNode(arrêt brutal du serveur dans les constructions debug/sanitizer) lors de l’exécution deSELECT ... ORDER BY ... WITH FILLsur une tableDistributedavec une valeur faible deoptimize_const_name_size. #109938 (groeneai). - Corrige une erreur
LOGICAL_ERROR(Left and right columns have same names) dans l’optimiseur d’ordre des jointures, qui pouvait être déclenchée par une jointure par virgule sur une vue multi-tables lorsquequery_plan_merge_expression_into_joinest activé. #110227 (groeneai). - Corrige une erreur rare
Logical error: 'No more packets are available.'levée pour une requête distribuée valide comportant unLIMIT, qui provoquait l’arrêt brutal du serveur dans les constructions debug et sanitizer. #110334 (groeneai). - Corrige un bogue de l’analyseur syntaxique où COMMENT était interprété à tort comme un alias implicite lorsqu’une requête SELECT se terminait directement après un simple identifiant de table (par ex.
... FROM t COMMENT 'x'), ce qui provoquait une erreur de syntaxe trompeuse au lieu d’appliquer le commentaire à la vue ou à la table. #110372 (adityaksolves). - Corrige un résultat erroné où
length()(ainsi que la dimension QBit) appliqué à une colonneFixedStringrenvoyait0au lieu de la taille fixeNavec les répliques parallèles lorsque la requête comportait un filtre sélectif. #110427 (groeneai). - Corrige l’erreur
NOT_FOUND_COLUMN_IN_BLOCKpour les requêtes comportant une sous-requête dansFROMlorsque les répliques parallèles s’exécutent en modecustom_key_sampling/custom_key_range. Ces requêtes (par ex.SELECT * FROM (SELECT id, k, v FROM t WHERE id < 20) ORDER BY k) échouaient auparavant avecNot found column __table2.id in block .... #110690 (groeneai). - Correction de
Logical error: 'clock'(arrêt brutal du serveur dans les builds debug/sanitizer ; blocage infini dans les builds release) lors de l’exécution deEXPLAIN ANALYZEsur une requête comportant une lecture en flux (FROM ... STREAM) qui n’est pas une simple expression de table de premier niveau : imbriquée dans une sous-requête (par exemple dansWHERE ... IN (...)ou une CTE), ou masquée derrière une vue ordinaire ou paramétrée.EXPLAIN ANALYZErejette désormais ces requêtes avecNOT_IMPLEMENTED, comme il le faisait déjà pour une lecture en flux de premier niveau. #110935 (groeneai). - Correction de la résolution des noms de colonne pleinement qualifiés tels que
db.table.columndans l’analyseur, pour les tables portant le même nom que leur base de données. #110976 (alexey-milovidov). - Correction des erreurs
NOT_FOUND_COLUMN_IN_BLOCK/THERE_IS_NO_COLUMN(et, sur certaines versions, de résultats erronés sans avertissement) pour unRIGHT JOINlorsqueparallel_replicas_min_number_of_rows_per_replicaest défini et qu’une colonne de la table de gauche est projetée. #111332 (groeneai). - Correction d’une condition de concurrence dans les UDF exécutables, le moteur de table
executableet les dictionnaires exécutables : unfcntlsur un descripteur de fichier déjà fermé pouvait corrompre un descripteur sans rapport appartenant à une requête concurrente (en supprimantO_NONBLOCK), ce qui pouvait bloquer des requêtes indéfiniment. #111779 (Algunenano). - Correction d’une
LOGICAL_ERROR(« Invalid number of rows in Chunk ») — et, dans les builds renforcés, d’un arrêt associé dû à un accès hors limites — pourORDER BY ... WITH FILL ... INTERPOLATEsur une tableDistributedcomportant au moins deux shards, surclusterAllReplicasou sur des répliques parallèles à clé personnalisée, y compris avec des résultats vides.WITH FILLn’est désormais appliqué que sur le nœud qui produit le résultat final, ce qui corrige également la duplication des lignes de remplissage générées entre shards/répliques. #111919 (yakov-olkhovskiy). - Correction du blocage indéfini de
DROP TABLE ... SYNClorsqu’une requête sursystem.replicasavait été interrompue avant le traitement de ses demandes de statut. #112164 (evillique). - Correction d’une exception
LOGICAL_ERROR(Block structure mismatch in joined block stream) sur une jointure multi-tables dont les deux sous-jointures ne produisent aucune colonne en sortie, par exempleSELECT count() FROM t1, t2, t3, t4 WHERE (t1.b = t2.b) AND (t3.a = t4.a)avecquery_plan_optimize_join_order_limitdéfini à0ou1. #112205 (groeneai). - Correction d’une erreur logique
Cannot add step Expression to QueryPlan because it has incompatible header with root step JoinLazyColumnsSteppour une requête avecFINAL, un filtrePREWHERE, un petitLIMITetmake_distributed_plan = 1, lorsque les colonnes sélectionnées sont listées dans un ordre différent de celui des colonnes de la table. La matérialisation différée remplaçait un nœud du plan sans conserver son en-tête de sortie, ce qui rendait le plan de requête incohérent. #112303 (groeneai). - Correction de résultats erronés et d’une erreur logique lorsqu’un argument devant être constant, comme l’échelle de
toDecimal32ou le fuseau horaire detoDateTime, provient d’une sous-requête scalaire et que l’ancien analyseur est utilisé. Un tel argument était analysé comme si sa valeur était nulle ou vide : le type de résultat déclaré ne correspondait donc pas à la valeur calculée, etCREATE VIEWetCREATE MATERIALIZED VIEWenregistraient un type de colonne erroné. #112492 (groeneai). - Corrige une erreur logique et un enregistrement de dépendance erroné lorsque le corps d’une
VIEWordinaire référence une table ou un dictionnaire via un paramètre de requête, comme dansCREATE VIEW v AS SELECT x FROM {db:Identifier}.t. Une telle vue n’enregistre plus de dépendance référentielle envers une table homonyme de la base de données courante : des tables sans rapport peuvent donc de nouveau être supprimées. #112704 (groeneai). - Corrige une erreur logique lorsqu’une table utilisant le table engine
Joinse trouve du côté droit d’une JOIN dont la sectionONcontient une condition portant sur des colonnes des deux tables, par exempleON (t.key = j.key) AND (t.a < j.a). Une telle requête est désormais rejetée avec une exception explicite, au lieu de leverrequired columns: ... but not found any in left tableoustd::bad_variant_access. #112815 (groeneai). - Correction d’un comportement indéfini et d’une erreur de planification silencieuse lorsqu’une tâche en arrière-plan est planifiée avec un délai très long, par exemple par une vue matérialisée actualisable dotée d’une période
REFRESH AFTERdémesurée. Les délais sont désormais plafonnés à la plus grande valeur représentable au lieu de provoquer un dépassement de capacité. #113041 (groeneai). - Correction de l’erreur signalée lorsqu’un
INSERTasynchrone dans une tableDistributednécessite un répertoire de file d’attente dont le nom dépasse la limite de 255 octets du système de fichiers (cas possible avecuse_compact_format_in_distributed_parts_names = 0). Il s’agissait d’uneLOGICAL_ERRORpour un shard avecinternal_replication, et d’uneCode: 1001. std::exceptionsans origine identifiée dans les autres cas ; les deux cas signalent désormaisARGUMENT_OUT_OF_BOUNDen indiquant la table, le cluster et la limite. #113083 (groeneai). UNDROP TABLEpeut désormais être interrompu parKILL QUERYpendant qu’il attend que les requêtes en cours libèrent la table supprimée. #113263 (alexey-milovidov).- Correction d’un blocage permanent de
DROP TABLEet d’une fuite de mémoire après l’échec d’une requête utilisant une CTE matérialisée. La table restait bloquée dans la file d’attente de suppression jusqu’au redémarrage du serveur. #113397 (tiandiwonder). - Corrige une erreur de segmentation et une
LOGICAL_ERROR(No host found for exchange stream final_result__0_0) lorsqu’une sous-requête définitdistributed_plan_execute_locallydans sa propre clauseSETTINGSavecmake_distributed_plan. Le plan distribué et le code chargé de l’exécuter lisaient le paramètre dans deux contextes différents et pouvaient diverger, si bien que l’initiateur construisait un pipeline incohérent. #113422 (groeneai). - Correction d’un
CREATE TABLE ... AS SELECTqui devenait impossible à interrompre après l’échec de sonSELECTde remplissage lorsquedatabase_atomic_wait_for_drop_and_detach_synchronouslyest activé : leDROPinterne de nettoyage de la table temporaire attendait la file d’attente de suppression en arrière-plan et ignorait à la foisKILL QUERYetmax_execution_time. #113504 (groeneai). - Correction de résultats erronés et, dans une version compilée avec les assertions activées, d’un échec d’assertion pour une
JOINsur un dictionnaire dont la clauseONcomporte une condition de non-égalité portant sur les deux tables, telle queON (t.key = d.key) AND (t.a * 10 < d.a), lorsquejoin_use_nullsest activé. La condition était évaluée sur une colonne lue avec un type incorrect, si bien que des lignes pouvaient correspondre de manière arbitraire. #113534 (alexey-milovidov). - Correction d’un problème où une vue paramétrée perdait sa base de données lorsqu’une requête y faisant référence sans qualification était envoyée à un shard, si bien que celui-ci résolvait le nom par rapport à sa propre base de données par défaut. Selon le contenu de cette base de données, la requête échouait avec
UNKNOWN_FUNCTIONou renvoyait silencieusement des lignes provenant d’une autre vue. ConcerneIN,JOINetremote()via une tableDistributed. #113550 (groeneai). - Correction de l’erreur
Unsupported JOIN keys of type keys256 in StorageJoinlors de la lecture d’une table utilisant le moteurJoindont la clé est composite (plusieurs colonnes) ou constituée d’une seule valeur de 16/32 octets telle queUUID,Int256ouFixedString(4). Une telle table pouvait être créée, alimentée et utilisée dans une jointure, mais jamais relue avecSELECT. #113578 (groeneai). - Correction d’une erreur logique
Sending a distributed query with unknown (zero) client versionlorsqu’une tableDistributedsans structure portant sur un shard distant est attachée ou chargée à partir de métadonnées écrites par une version plus ancienne du serveur. #113675 (alexey-milovidov). - Correction d’une erreur
LOGICAL_ERRORlorsqu’unSELECTutilisait le modificateurSTREAMsur une table nommée conjointement avec les répliques parallèles en mode read-tasks. Avec une CTE matérialisée utilisée comme setINdansPREWHERE, le serveur levaitReading from materialized CTE ... DelayedPortsProcessor gate is missing in the query plan(provoquant un arrêt brutal du serveur dans les builds debug et sanitizer). Une table portantSTREAMest désormais rejetée lorsque les répliques parallèles sont demandées : avecenable_parallel_replicas = 2, la requête échoue avecSUPPORT_IS_DISABLED; avec1, elle s’exécute sans elles, exactement comme c’est déjà le cas pourFINAL. #113754 (groeneai). - Correction de la complexité quadratique de l’analyse de l’argument d’adresse des fonctions de table
remote,mysqlet similaires : une adresse très longue (par exemple uneFixedStringd’un mégaoctet complétée par des zéros) bloquait la requête pendant l’analyse, sans possibilité de l’annuler. #113918 (alexey-milovidov). - Correction d’une erreur intempestive
Failed to drop temporary table after refresh. Table ... is left behind and requires manual cleanup.journalisée lorsque le rafraîchissement d’une vue matérialisée actualisable est annulé (par exemple lors de l’arrêt du serveur) alors quedatabase_atomic_wait_for_drop_and_detach_synchronouslyest activé. La table temporaire était en réalité bien supprimée ; aucun nettoyage manuel n’a donc jamais été nécessaire. #113957 (groeneai). - Correction d’une ligne manquante dans
system.query_views_logpour une vue matérialisée qui échoue pendant la collecte de ses dépendances lorsquematerialized_views_ignore_errorsest activé. Dans les builds debug et sanitizer, cela provoquait également l’arrêt brutal du serveur avecstd::out_of_rangeau lieu de journaliser la vue. #114064 (groeneai). - Correction de résultats incohérents lorsqu’un filtre sur une colonne non clé de la table de droite était poussé sous une ANY INNER JOIN. #114313 (kirillshokhin).
- Correction de
CREATE OR REPLACEqui laissait subsister une table interne_tmp_replace_*, et deCREATE OR REPLACE VIEWqui échouait avecNOT_IMPLEMENTED, lorsqueignore_drop_queries_probabilityest défini. Les DROP émis en interne n’étant que des étapes d’une même instruction utilisateur, l’injection de fautes sur les DROP ne s’y applique plus. #114420 (groeneai). - Correction d’une erreur
LOGICAL_ERRORlors de la lecture d’une table Delta Lake dontmetaData.partitionColumnsréférence une colonne non déclarée dansmetaData.schemaString. Ces métadonnées sont désormais rejetées avecBAD_ARGUMENTSpar le lecteur delta-kernel et avecINCORRECT_DATApar l’ancien lecteur, dès que la table ou son schéma est lu à partir d’un instantané, et pas uniquement lorsque la requête comporte un prédicat. #114538 (groeneai). - Correction d’un problème où les statistiques des tables de hachage — et, avec elles, la préallocation des tables de hachage d’agrégation — étaient désactivées silencieusement et définitivement pour l’ensemble du serveur lorsqu’une requête utilisant l’optimisation
FINALdifférée (query_plan_optimize_lazy_final) était la première agrégation exécutée après le démarrage du serveur. #114597 (alexey-milovidov). - Correction d’un problème où une vue matérialisée actualisable laissait fuiter son ancienne table cible, remplacée lors de la rotation, lorsque
ignore_drop_queries_probabilityest activé. LeDROPémis par un rafraîchissement pour nettoyer la cible précédente fait partie du rafraîchissement et n’est pas unDROPdemandé par l’utilisateur ; l’injection de fautes ne s’y applique donc plus. #114622 (groeneai). - Correction de
ANY RIGHT JOINetSEMI RIGHT JOINcomportant plusieurs conditions combinées parORdans la sectionON, qui renvoyaient certaines lignes de la table de droite en double et perdaient les correspondances d’autres lignes. UnANY LEFT JOINécrit explicitement était également concerné, car le planificateur peut inverser les tables et l’exécuter comme unANY RIGHT JOIN. #114676 (vdimir). - Correction d’une erreur
LOGICAL_ERROR(Cannot find input column ... on its position in inputs of expression actions DAG) lorsqu’une requête comporte unJOINau-dessus d’une table dont la colonne dotée d’un index textuel est utilisée à la fois par un prédicat de recherche textuellePREWHEREet par un prédicatWHERE. #114771 (groeneai). - Correction de l’erreur
NOT_FOUND_COLUMN_IN_BLOCKsurvenant à chaqueINSERTdans une table déclarantSTATISTICS(...)sur une colonneALIASouEPHEMERAL, ce qui rendait de fait ces tables accessibles en lecture seule. #115231 (groeneai). - Correction de
dictGetet de ses variantes dans les requêtes distribuées : un nom de dictionnaire non qualifié est désormais lié à la base de données courante de l’initiateur, au lieu d’être résolu par rapport à la base de données courante de chaque shard, où il était soit introuvable, soit résolu vers un autre dictionnaire portant le même nom. #115541 (alexey-milovidov). - Correction d’un bug où la restauration d’une base de données ou d’une table sous un nouveau nom supprimait les alias de tables du corps des vues stockées, si bien que la lecture d’une vue restaurée échouait avec
UNKNOWN_IDENTIFIER. #115645 (groeneai). - Correction de l’erreur
LOGICAL_ERROR“Reading from materialized CTE ‘X’ before its materialization completed - DelayedPortsProcessor gate is missing in the query plan” lorsqu’une CTEMATERIALIZEDest lue depuis une sous-requêteINportant sur une tableDistributed. #115740 (groeneai). - Correction de l’erreur BAD_ARGUMENTS “Dictionary not found” sur dictGet après un DETACH DICTIONARY … PERMANENTLY rejeté par la vérification des dépendances (HAVE_DEPENDENT_OBJECTS). Le dictionnaire reste désormais pleinement utilisable lorsque le détachement est rejeté. #105259 (groeneai).
- Correction d’une erreur
Logical error: 'removed'(arrêt du serveur dans les builds de débogage) dans la file d’attente de suppression de tables en arrière-plan. Elle pouvait se produire lorsque le même UUID explicite était réutilisé dans plusieurs requêtesCREATE OR REPLACE TABLE, ce qui plaçait dans la file d’attente plusieurs tables supprimées partageant cet UUID. #107031 (groeneai). - Correction d’un problème où
MaterializedPostgreSQLinterrompait la réplication d’une base de données entière (avecLOGICAL_ERROR: Columns number mismatch) lorsque la structure d’une seule table répliquée avait changé pendant l’arrêt du serveur. Désormais, seule la table concernée est ignorée ; elle peut être récupérée avecDETACH/ATTACH. #107427 (alexey-milovidov). - Correction d’un fort déséquilibre dans la répartition du travail avec les répliques parallèles lorsque le cluster contient des répliques inactives (par exemple, des entrées obsolètes laissées après une mise à l’échelle automatique). Ces répliques ne sont plus prises en compte par le coordinateur de lecture : le travail est ainsi réparti entre les répliques en ligne au lieu de s’accumuler sur une seule. #107805 (alexey-milovidov).
- Correction d’un blocage de
SYSTEM RELOAD DICTIONARIES(et deRELOAD DICTIONARY) lorsque de nombreux dictionnaires MySQL définis en XML partageaient un même pool de connexions viashare_connection. Ces pools respectent désormais les paramètresconnection_pool_sizeetconnection_wait_timeout(5 secondes par défaut) de la configuration, comme les dictionnaires définis au moyen de collections nommées. #108083 (alexey-milovidov). - L’épuisement des tentatives pour le DDL distribué répliqué exécuté par le leader ne bloque plus définitivement les requêtes DDL
ON CLUSTERsuivantes. #108505 (ahaanlimaye). - Correction d’un plantage possible (use-after-free) lorsque
SYSTEM FLUSH DISTRIBUTEDs’exécute en même temps qu’unDROP TABLEsur la même tableDistributed. #108684 (groeneai). - Correction d’une erreur
LOGICAL_ERROR(local_replica_plan_reading_step->getAnalyzedResult() == nullptr) dans le planificateur automatique des répliques parallèles, qui pouvait survenir lorsqueautomatic_parallel_replicas_modeétait activé et queparallel_replicas_min_number_of_rows_per_replicaavait une valeur supérieure à 0. #109011 (groeneai). - Correction d’une erreur
LOGICAL_ERROR(creation_csn is not set while removal_csn is set to 1) qui pouvait être levée lorsqu’unTRUNCATEnon transactionnel s’exécutait en même temps qu’une transaction non validée ayant inséré des données dans la même table. Un telTRUNCATEne supprime plus les parts créées par des transactions pas encore validées. #109598 (tuanpach). - Les moteurs de base de données externes (par ex.
PostgreSQL) ne délèguent plus les comparaisons de plage (>=,>,<=,<) sur les colonnesUUID. ClickHouse et les bases de données externes n’ordonnent pas les UUID de la même manière : déléguer ces prédicats supprimait donc silencieusement des lignes du résultat. Ils sont désormais évalués par ClickHouse. #109833 (vismaytiwari). - Correction d’un plantage du serveur dans le moteur de base de données
MaterializedPostgreSQL, qui pouvait se produire lorsqu’une table était détachée (ou que sa structure changeait) alors qu’elle était encore en file d’attente de synchronisation. #110596 (alexey-milovidov). - Correction de la réécriture du type d’une colonne
EPHEMERALpar lesquery_masking_rulesdu serveur. Une règle correspondant à une partie du type amenaitCREATE TABLEà enregistrer un type incorrect, voire à échouer. #112048 (alexey-milovidov). - Corrige un dépassement inférieur non signé dans la vérification de la longueur du nom de table, qui permettait de créer une table impossible à supprimer. Lorsque le nom de base de données échappé atteignait 214 octets, la limite calculée pour le nom de fichier
metadata_droppedrepartait au début de la plage, si bien queCREATE TABLEétait accepté, tandis que les instructionsDROP TABLEouDROP DATABASEultérieures échouaient avecFile name too long. Un tel nom est désormais rejeté avecARGUMENT_OUT_OF_BOUND, la même erreur que celle déjà renvoyée juste en dessous de cette limite. #112527 (groeneai). - Correction de
RENAME TABLE, qui vérifiait la longueur maximale du nom de table par rapport à la base de données source plutôt qu’à la base de données de destination. Renommer une table vers une base de données au nom long pouvait produire une table queDROP TABLEne parvenait pas à supprimer, tandis que renommer une table pour la sortir d’une telle base de données était rejeté à tort. #113019 (groeneai). - Corrige la colonne
viewsdequery_log, qui restait toujours vide lors des insertions dans une tableAliasdont la cible déclenche des vues matérialisées. #113076 (eclbg). - Les expressions
parallel_replicas_custom_keyinvalides, telles quetuple()ou(x, y), sont désormais rejetées avecILLEGAL_TYPE_OF_COLUMN_FOR_FILTERau lieu de provoquer une lecture au-delà de la liste de types de la clé personnalisée. #113359 (nickitat). - Correction de
RENAME DATABASE, qui acceptait un nom cible suffisamment long pour rendre les tables de la base de données impossibles à supprimer. La vérification de la longueur du nom de table s’exécute désormais indépendamment decheck_table_dependencieset couvre également les tables détachées, qui n’étaient jamais vérifiées et étaient donc concernées même avec les paramètres par défaut. #113557 (groeneai). - Lors d’insertions en arrière-plan dans des tables utilisant le moteur
Distributed, les délais provoqués par des erreurs répétées lors de l’envoi de données vers des shards distants diminuent désormais une fois les erreurs résolues. Auparavant, le délai ne faisait qu’augmenter, sans jamais être réinitialisé. #87378 (Blackmorse). - Rejet des poignées de main du protocole natif qui utilisent
USER_INTERSERVER_MARKERpour un cluster inconnu ou pour un cluster configuré sans<secret>. Auparavant, une telle poignée de main permettait à un client non authentifié de passer en mode interserveur et d’utiliser des paquets de protocole antérieurs à l’authentification (par ex.TablesStatusRequest) s’appuyant sur unfake_interserver_context, et ainsi d’obtenir des informations sur les tables locales sans avoir à prouver qu’il connaissait le secret de cluster. #99675 (MillaFleurs).
Corrections liées à SQL, à l’analyseur et aux jointures
- Correction de la substitution des paramètres de requête dans les définitions d’une clause
WINDOWnommée. Auparavant, ces paramètres n’étaient pas substitués, sans aucun avertissement, et un paramètreIdentifiernon défini pouvait provoquer l’exceptionLogical error: '!part.empty()'lors deEXPLAIN SYNTAX. #110506 (alexey-milovidov). - Correction d’un plantage rare du serveur lorsque des vues matérialisées actualisables sont supprimées ou remplacées de manière concurrente. Un pointeur nul était déréférencé dans
RefreshTask::doSchedulinglorsqu’un autre thread affectaitnullptrà laviewde la tâche alors que le code de planification avait temporairement libéré son mutex. #105588 (groeneai). - Correction d’un résultat erroné renvoyé par une vue définie avec
EXCEPTouINTERSECTdont l’opérande est une chaîneUNION, après unDETACH/ATTACHou un redémarrage du serveur. Le formateur omettait les parenthèses autour des enfantsUNIONdeINTERSECT/EXCEPT; le SQL stocké était donc réanalysé avec une priorité inversée. #105935 (groeneai). - Correction de résultats erronés (lignes dupliquées) pour
SELECT DISTINCTappliqué à unGROUP BYavecWITH CUBE,WITH ROLLUPouGROUPING SETSsur les mêmes clés. L’optimisationquery_plan_remove_redundant_distinctne supprime plus leDISTINCTdans ces cas, car les modificateurs de regroupement produisent des lignes supplémentaires dont les colonnes clés prennent leur valeur par défaut, lesquelles peuvent entrer en collision avec de véritables valeurs de groupe. #107072 (groeneai). - Correction d’un résultat erroné dans un OUTER JOIN lorsque le filtre
WHEREest une conjonction contenant un terme constant (par exemplep AND 1, ouWHERE p QUALIFY NULLoùQUALIFY NULLest fusionné dansWHERE). Le terme constant pouvait être poussé vers le côté non préservé de la jointure et retiré du filtre post-jointure : la jointure produisait alors des lignes sans correspondance dont les colonnes de ce côté prenaient leur valeur par défaut, et ces lignes passaient à tort le filtre. #107084 (groeneai). - Correction d’une
LOGICAL_ERROR(“Cannot find input column … on its position in inputs of expression actions DAG”) qui interrompait le serveur pour une sous-requête scalaire corrélée portant sur une source projetant deux fois le même identifiant de colonne (par ex.SELECT number, *) lorsquecorrelated_subqueries_default_join_kind = 'left'. #107112 (groeneai). - Correction d’une
LOGICAL_ERROR(arrêt du serveur dans les builds debug/sanitizer) lorsqu’unJOINutilise l’opérateur de comparaison null-safe (<=>/IS NOT DISTINCT FROM) et que l’une des clés est une sous-requête scalaire, par ex.... JOIN t2 ON (SELECT x FROM t1) <=> t2.k, avec l’ancien analyseur (enable_analyzer = 0). Une telle requête renvoie désormais une erreurNOT_FOUND_COLUMN_IN_BLOCKclassique au lieu d’une erreur logique. #108123 (groeneai). - Correction des exceptions
LOGICAL_ERROR(Join is supported only for pipelines with one output port) etNOT_IMPLEMENTED(MergeJoinAlgorithm is not implemented for strictness Semi) lorsquejoin_algorithm = 'full_sorting_merge'était utilisé pour une jointureSEMI/ANTI, y compris les jointures issues de la décorrélation d’une sous-requête corréléeEXISTS.full_sorting_mergerefuse désormais les combinaisons strictness/kind qu’il ne peut pas exécuter, de sorte que le planificateur se rabat sur un autre algorithme activé ou signale que la jointure ne peut pas être exécutée. #108658 (groeneai). - Correction d’un bogue où la ligne
WITH TOTALSd’unJOINpouvait contenir des valeurs par défaut (comme0) au lieu des valeurs constantes issues d’une sous-requête constante située d’un côté de la jointure. Le résultat erroné n’apparaissait qu’avec certains ordres de jointure ou avec le paramètrequery_plan_join_swap_table. #108807 (vdimir). - Correction d’un arrêt brutal au démarrage (
Cannot allocate ThreadStack,EINVAL) sur les constructions glibc exécutées sur des CPU dotés d’une pile de signaux de grande taille (par exemple Intel Sapphire Rapids / Granite Rapids avec un noyau prenant en charge AMX) : la taille de la pile alternative de signaux n’était pas arrondie au multiple supérieur de la taille de page avant l’appel àaligned_alloc. #108813 (groeneai). - Correction d’une erreur logique
Block structure mismatch in JoinStep(arrêt du serveur dans les constructions debug/sanitizer) lorsqu’une sous-requête corrélée est décorrélée en jointure et que la relation source contient plusieurs fois le même nom de colonne, par exempleWITH t AS (SELECT number, * FROM numbers(3)) SELECT *, (SELECT t.number WHERE t.number >= 0) FROM taveccorrelated_subqueries_default_join_kind = 'right'. #109114 (groeneai). - Correction de
CREATE USER ... HOST LIKE 'a', 'b'(et de son équivalentALTER USER), qui ne conservait silencieusement que le premier motif. Tous les motifsHOST LIKEspécifiés sont désormais enregistrés dans la liste des hôtes autorisés de l’utilisateur. #109187 (groeneai). - Correction d’un résultat inattendu pour
ANY JOINavec une conditionONconstante (par exemplet1 ANY INNER JOIN t2 ON 1) : la requête renvoyait le produit cartésien complet au lieu du résultat de la jointure ANY #109207 (vdimir). - Correction de la limite globale
max_rows_in_join/max_bytes_in_join, qui n’était pas appliquée avec l’algorithme de jointure parallel_hash : une requête avecjoin_overflow_mode = 'throw'pouvait ainsi réussir silencieusement au lieu de leverSET_SIZE_LIMIT_EXCEEDED. #109488 (m-selmi). - Correction d’une perte de données silencieuse lorsqu’un
INSERT ... VALUESdans un flux multi-requêtes est suivi d’un commentaire SQL final (par exempleVALUES (1) -- comment) avec l’analyse côté serveur des insertions à données intégrées (send_table_structure_on_insert_with_inline_data = 0). Le commentaire final était analysé comme des données de ligne au-delà du;terminal, si bien que les requêtes suivantes du flux étaient ignorées sans avertissement. #109643 (groeneai). - Correction du
PREWHEREdifféré avecoptimize_move_to_prewhere = 1lorsquePREWHEREs’exécute aprèsFINAL: les conditionsWHEREne sont plus placées avant une politique de lignes différée, ce qui pouvait modifier le résultat des requêtes. #109703 (yariks5s). - Correction d’une erreur
LOGICAL_ERROR(query tree node does not have valid source node) lorsqu’une CTE récursive résolvait un identifiant d’une portée externe comme une colonne corrélée (avecallow_experimental_correlated_subqueries = 1). Ces requêtes renvoient désormais une erreur expliciteUNSUPPORTED_METHOD. #109863 (groeneai). - Correction d’un dépassement de capacité d’entier signé lorsque
ORDER BY ... WITH FILLfranchit un très grand intervalle manquant sur une colonneInt64/UInt64(par exemple un pas de 2 sur un intervalle proche de 2^63). Ce dépassement de capacité constituait un comportement indéfini détecté par les sanitizers et provoquait un rebouclage silencieux dans les constructions de production. #109937 (groeneai). - Correction d’une erreur logique
Invalid number of rows in Chunklorsqu’une cibleINTERPOLATEest un alias d’une colonneWITH FILLavec l’ancien analyseur (enable_analyzer = 0). Ces requêtes sont désormais rejetées avec une erreur expliciteINVALID_WITH_FILL_EXPRESSION. #110103 (groeneai). - Correction d’une erreur logique (
Unexpected number of columns in result sample block) lorsqu’un filtre contenant une sous-requête corrélée (par exempleexists((SELECT ...))) est optimisé avecconvert_query_to_cnfouoptimize_and_compare_chain. #110187 (alexey-milovidov). - Une sous-requête
EXISTScorrélée imbriquée qui référence une colonne d’une portée située au-delà de sa requête externe immédiate (en sautant une portée intermédiaire) échoue désormais avec une erreur expliciteNOT_IMPLEMENTEDau lieu d’une erreur interneNOT_FOUND_COLUMN_IN_BLOCK. #110310 (groeneai). - Correction de résultats erronés renvoyés par les sous-requêtes scalaires corrélées lorsque la requête externe contient des valeurs en double pour la colonne corrélée et que la sous-requête est décorrélée via le chemin CROSS JOIN. Auparavant, les agrégats tels que
count()etsum()étaient multipliés par le nombre de doublons. Ce problème concerne la fonctionnalité expérimentaleallow_experimental_correlated_subqueries. #110311 (groeneai). - Correction de
ORDER BY ... WITH FILL, qui ne respectait pasmax_execution_timeet tardait à s’annuler lors de la génération d’une vaste plage de remplissage (en particulier avecINTERPOLATE). #110332 (alexey-milovidov). - L’optimisation
FINALdifférée (query_plan_optimize_lazy_final, désactivée par défaut) n’est plus appliquée lorsque la requête lit dans l’ordre de la clé de tri : son plan de remplacement ne produit pas les lignes dans l’ordre de la clé de tri, alors que le plan situé au-dessus peut déjà s’appuyer sur cet ordre après l’optimisation de lecture ordonnée, ce qui pouvait produire des résultats mal ordonnés. Elle n’est pas non plus appliquée lorsqu’une clauseLIMITinférieure au nombre de lignes à lire s’applique directement à l’étape de lecture, car la passe obligatoire de construction de l’ensemble rendrait alors l’arrêt anticipé inopérant. #110576 (KochetovNicolai). - Le vidage en arrière-plan d’une insertion asynchrone s’arrête désormais rapidement lorsqu’il est interrompu avec
KILL QUERY. Auparavant, le vidage d’une charge utile volumineuse mise en tampon poursuivait l’analyse jusqu’au bout sans tenir compte de l’annulation. #110652 (tiandiwonder). - Correction de résultats erronés renvoyés par
GROUP BY ... optimize_aggregation_in_orderetDISTINCT ... optimize_distinct_in_orderplacés au-dessus d’une jointurepartial_merge. L’optimisation de lecture ordonnée était propagée à traversPartialMergeJoin, qui retrie son entrée gauche selon la clé de jointure et ne préserve donc pas l’ordre d’origine du flux gauche, si bien que les lignes étaient mal regroupées. #110671 (groeneai). - Correction d’un cas où, lors de l’utilisation d’alias de colonnes de CTE avec des requêtes
INTERSECTouEXCEPT, par exempleWITH t (a, b) AS (SELECT 1, 2 INTERSECT SELECT 1, 2) SELECT a, b FROM t, la requête échouait avec une erreur UNKNOWN_IDENTIFIER. #110885 (yariks5s). - Correction d’une erreur
LOGICAL_ERROR: ReadBuffer is canceled. Can't read from it.qui pouvait survenir dans une jointuregrace_hashlorsque la lecture de blocs déversés sur disque échouait en cours de route alors que plusieurs threads partageaient le lecteur. #111056 (groeneai). - Corrige un bug où la matérialisation des colonnes du côté droit lors des *_hash JOINs utilisait le mauvais fuseau horaire. #111074 (yariks5s).
- Corrige les instructions
CREATEcomportant une clauseCOMMENTafin qu’elles lèvent une erreur de syntaxe lorsque la chaîne littérale du commentaire est absente, au lieu d’accepter silencieusement une requête mal analysée (par exemple,CREATE VIEW v COMMENT AS SELECT 1ne crée plus de vue sans commentaire). #111159 (tiandiwonder). - Corrige une erreur
LOGICAL_ERROR(Reading from materialized CTE '...' before its materialization completed - DelayedPortsProcessor gate is missing in the query plan) survenant lorsqu’une CTE matérialisée réutilisée (enable_materialized_cte) est lue sur une branche dont la sortieWITH TOTALSouextremesest ignorée, notamment en cas d’agrégation externe, deINSERT ... SELECT, d’opérations ensemblistes et deEXPLAIN ANALYZE. #111194 (groeneai). - Corrige
join_algorithm = 'full_sorting_merge', qui remplissait les lignes non jointes d’unLEFT/RIGHT/FULL/ASOFJOINavec un zéro brut au lieu de la valeur par défaut du type de colonne. Pour une colonneEnum(dont la valeur par défaut est son premier élément, et non0), cela produisait des résultats incorrects (un filtre sur la valeur de remplissage éliminait les lignes sans correspondance, si bien qu’une jointure externe se comportait silencieusement comme une jointure interne) ainsi qu’une erreurUNKNOWN_ELEMENT_OF_ENUMlorsque la colonne était sélectionnée. #111197 (groeneai). - Corrige des résultats incorrects de
SummingMergeTree(etCoalescingMergeTree) avecFINALlorsqueoptimize_move_to_prewhere_if_final = 1et que la clauseWHEREest une condition booléenne implicite sur une colonne de la clé de tri (par exempleWHERE k). La colonne clé était renvoyée sommée sur les parties de données non fusionnées au lieu d’être conservée telle quelle. #111342 (groeneai). - Corrige une erreur logique (
Unexpected number of columns in result sample block) pouvant survenir pour unRIGHT/FULL JOINlorsque le côté gauche contient une colonne dupliquée portant le même nom (par exemple1 AS b, 1 AS b) qui est conservée à travers unUNION ALL. #111554 (groeneai). - Corrige un plantage du client lors du formatage d’une requête
EXECUTE ASdont l’AST a un enfant remplacé (comme le fait le fuzzer AST).ASTExecuteAsQuerypossède désormais ses enfantstarget_useretsubqueryau lieu de conserver des pointeurs non propriétaires verschildren. #111725 (groeneai). - Corrige des résultats incorrects lorsque
query_plan_join_swap_tablepermute unANY JOINalors quejoin_any_take_last_row = 1: ClickHouse conserve désormais l’ordre d’origine des côtés de la jointure afin queANY JOINrenvoie toujours la dernière ligne correspondante. #112458 (vdimir). - Corrige l’exception
Context has expiredlorsquegetClientHTTPHeaderest utilisé dans une sous-requête. #112533 (alexey-milovidov). - Corrige des résultats incorrects pour un
JOINdont la clauseONcontient une condition mixte, c’est-à-dire un résidu de non-équijointure portant sur les deux côtés, tel queON (t1.key = t2.key) AND (t1.a * 10 < t2.a). Seule la famille d’algorithmes de hachage évalue ce type de condition, maisfull_sorting_merge,partial_mergeet la jointure directe clé-valeur se déclaraient capables d’exécuter ces jointures, puis ignoraient silencieusement le résidu et renvoyaient des lignes en trop. Ils refusent désormais ces jointures, et un algorithme de hachage est alors utilisé à la place. #112831 (groeneai). - Correction de résultats erronés pour une jointure par virgule ou
CROSSdont la clauseWHEREcompare des colonnes de deux tables au moyen d’une expression non déterministe telle querand. Une telle requête pouvait renvoyer des lignes contredisant sa propre clauseWHERE, car la réécriture de la jointure en jointureINNERdéplaçait l’expression dans la clé de jointure, où elle est réévaluée pour chaque ligne de chaque côté. #112938 (groeneai). - Correction d’un ralentissement quadratique lors de l’analyse d’une requête PromQL se terminant par une longue suite de caractères non reconnus (par exemple une valeur
FixedStringcomplétée par des octets NUL) : l’analyse d’une entrée invalide de l’ordre du mégaoctet pouvait occuper un thread pendant plusieurs dizaines de minutes sans pouvoir être annulée, car elle a lieu pendant l’analyse de requêtes. Désormais, l’analyseur syntaxique s’arrête à la première erreur. #112944 (alexey-milovidov). - Correction de
intDivappliqué à une colonne non constante avec le diviseur constant -1, qui faisait déborder silencieusement la division du plus petit nombre signé (par exempleintDiv(-9223372036854775808, -1)) au lieu de lever l’exceptionILLEGAL_DIVISIONcomme le font les autres chemins d’exécution. Ce débordement silencieux pouvait également produire des résultatsORDER BY/DISTINCTerronés, car l’optimisation de lecture dans l’ordre considère à juste titreintDivpar une constante négative comme monotone, et la valeur débordée enfreignait l’ordre de tri qui en découle. #113048 (alexey-milovidov). - Correction de l’erreur
UNKNOWN_IDENTIFIERavecenable_analyzer = 0lorsqu’une clauseWHEREfait référence à une colonne produite paruntupledans une sous-requête, par exempleSELECT t.keys FROM (SELECT untuple(arrayJoin(m)) AS t FROM ...) WHERE t.values > 0. La réécritureenable_optimize_predicate_expressionpoussait un tel prédicat dans la sous-requête sous forme deHAVING, où le nom n’existe pas encore. #113760 (groeneai). - Correction de résultats erronés dans les
JOINavecjoin_algorithm = 'partial_merge'lorsque le côté droit contient des totaux : le côté droit pouvait rester non fusionné, de sorte que les jointuresLEFTsubstituaient des valeurs par défaut aux correspondances réelles et que les jointuresINNER/RIGHTne renvoyaient aucune ligne. Dans le chemin des lignes non jointes deRIGHT/FULL, ce même état provoquait le déréférencement d’un pointeur nul, entraînant le plantage du serveur. #113936 (groeneai). - Correction de résultats erronés pour
SELECT DISTINCTavec une clauseLIMITdevant lire l’intégralité de son entrée :LIMIT n WITH TIESsupprimait les lignes ex æquo,exact_rows_before_limit = 1renvoyait une valeurrows_before_limit_at_leasttronquée, etGROUP BY ... WITH TOTALScalculait la ligne des totaux à partir d’un préfixe du flux. #114025 (groeneai). - Correction d’une erreur
LOGICAL_ERROR(« Unexpected number of kept output positions after removing unused columns fromReadFromMergeTree») levée par une requêteSELECT ... FINALdont la clausePREWHEREutilise une colonne nécessaire àFINALpour la fusion (ver,is_deleted,sign) sans sélectionner cette colonne. #114746 (groeneai). - Correction d’un problème de durée de vie dans le vidage des INSERT asynchrones, le traitement des vues matérialisées et
EXPLAIN ANALYZE, qui pouvait entraîner l’accès à un état de suivi de requête expiré. #114940 (azat). - Correction de
CREATE QUOTAetALTER QUOTA, qui ignoraient silencieusement tous les blocsFOR INTERVALsauf le dernier lorsque la virgule séparant les intervalles était omise. Un tel statement s’exécutait sans erreur, mais sans appliquer aucune des limites précédentes. Les intervalles se cumulent de nouveau, comme avant 2020. #115320 (groeneai). - Correction de
randConstant, qui renvoyait deux valeurs différentes dans une même requête lorsque ses appels portaient des alias différents. Selon la documentation,randConstantconserve une valeur unique pour l’ensemble de la requête, etSELECT randConstant() = randConstant()renvoyait déjà1, mais l’ajout d’alias, comme dansSELECT randConstant() AS a, randConstant() AS b, produisait deux valeurs sans aucun rapport. #115384 (alexey-milovidov). - Correction de
SELECT count(), qui ne se terminait jamais ou renvoyait un nombre de lignes fictif sur un fichierMsgPackouProtobufListcorrompu. Le chemin rapideoptimize_count_from_filescomptait les lignes sans exiger que la position de lecture avance, si bien qu’un fichierProtobufListde deux octets produisait des milliards de lignes et ne se terminait jamais. Une telle entrée est désormais rejetée avec la même erreur que celle renvoyée par le chemin de lecture ordinaire. #115884 (groeneai). - Correction de
broken_data_filesdanssystem.distribution_queueet de la métriqueBrokenDistributedFilesToInsert, qui indiquaient toujours0: lors du parcours de la file d’attente d’insertion asynchrone au démarrage,DistributedAsyncInsertDirectoryQueue::initializeFilesFromDiskcomptabilisait les octets endommagés, mais n’incrémentait jamais le compteur de fichiers endommagés. #92124 (squalfof).
Autres corrections de bogues
- Les requêtes secondaires exécutées dans le cadre de requêtes internes sont désormais journalisées comme des requêtes internes. #108506 (mstetsyuk).
- Correction d’un problème où une colonne DEFAULT absente d’une partie de données était remplie avec la valeur par défaut du type au lieu de l’expression DEFAULT lorsque la condition PREWHERE était scindée en plusieurs étapes de lecture. #111795 (yariks5s).
- Les quotas indexés par
normalized_query_hashcomptabilisent désormais toutes les ressources (read_rows,read_bytes,result_rows,result_bytes,execution_time,written_bytes,errors) par modèle de requête, à l’instar des compteurs de nombre de requêtes, au lieu de les imputer à un compartiment unique partagé par utilisateur. #107681 (alexey-milovidov). - Correction de la non-prise en compte de
connect_timeoutet des délais de lecture et d’écriture de MySQL : une tentative de connexion à un serveur MySQL qui ne répond pas pouvait rester bloquée plus de deux minutes, même avecconnect_timeout = 1, car les signaux périodiques du Sampling query profiler réinitialisaient sans cesse l’échéance interne de poll du client MySQL. #109592 (tiandiwonder). - Correction d’un problème où le délai d’attente de bloc des insertions en streaming (
input_format_max_block_wait_ms) pouvait ne jamais expirer lorsque le QueryProfiler était actif : le poll du descripteur de fichier repartait avec le délai complet après chaque signal du profiler, si bien qu’une source d’entrée bloquée pouvait retarder indéfiniment le vidage du bloc partiel au lieu de le déclencher une fois la limite d’attente atteinte. #109602 (tiandiwonder). - Correction d’une erreur
LOGICAL_ERROR(std::length_error) lorsqu’une requête utilisant le paramètre expérimentalmake_distributed_plan = 1spécifiait une valeur très élevée pourdistributed_plan_default_reader_bucket_countoudistributed_plan_default_shuffle_join_bucket_count. De telles valeurs sont désormais rejetées avecINVALID_SETTING_VALUE. #109770 (groeneai). - Correction de
distinct_overflow_mode = 'break': DISTINCT renvoie désormais le résultat partiel accumulé jusqu’à la limite et arrête la lecture de la source, conformément à la documentation. Auparavant, le fragment qui dépassaitmax_rows_in_distinct/max_bytes_in_distinctétait ignoré (résultats tronqués ou vides) et la requête continuait de lire et d’insérer dans le set de hachage jusqu’à la fin de l’entrée, ce qui pouvait aboutir àMEMORY_LIMIT_EXCEEDED. #110075 (skuznetsov-clickhouse). - Correction de
optimize_aggregation_in_order, qui ignorait l’annulation des requêtes.AggregatingInOrderTransformvérifie désormais l’annulation pendant l’agrégation d’un fragment, de sorte qu’une requête arrêtée parKILL QUERYou parmax_execution_time(avec le mode par défauttimeout_overflow_mode = 'throw') s’interrompt rapidement au lieu de traiter le fragment entier jusqu’au bout. #110104 (groeneai). - Correction d’un arrêt brutal du serveur (dans les builds de débogage et avec sanitizer) lorsqu’une valeur provenant d’une source PostgreSQL de la famille
mysql/postgresql/sqliteest lue dans un type déclaré vers lequel elle ne peut pas être convertie (par exemple une colonnetextdéclarée commeInt32). Une telle incompatibilité de type est désormais signalée comme une erreur de requête au lieu de provoquer l’arrêt du serveur. #110264 (groeneai). - Correction d’un arrêt brutal du serveur lors de l’analyse de certaines requêtes PRQL (
SET dialect = 'prql'). Une panique dans le compilateurprqlcinterrompait le processus au lieu d’être signalée comme une erreur de requête. #110316 (groeneai). - Correction de
NOT_FOUND_COLUMN_IN_BLOCKlorsqu’une politique de ligne etadditional_table_filtersfont référence à la même colonne, non sélectionnée par ailleurs dans la requête. #111099 (groeneai). - Correction d’un blocage dans
randChiSquared,randStudentT,randFisherFetrandBinomialavec des paramètres extrêmes. La requête ne pouvait être interrompue ni parmax_execution_timeni parKILL QUERY. De tels paramètres sont désormais rejetés, même lorsquemax_rand_distribution_parameteroumax_rand_distribution_trialsvaut 0, etmax_rand_distribution_trialsne peut plus dépasser sa valeur par défaut de 10^9 pourrandBinomial. #111909 (alexey-milovidov). - Correction de
connection_pool_max_wait_msafin que sa valeur par défaut documentée,0, corresponde à un délai d’attente infini. Une requête qui trouvait le pool de connexions plein effectuait auparavant de nouvelles tentatives en boucle serrée, consommant du CPU et journalisantNo free connections in pool. Waiting 0 ms.à chaque itération. Elle attend désormais qu’une connexion soit restituée au pool. #112380 (groeneai). - Correction de
replaceOne,replaceAll,replaceRegexpOneetreplaceRegexpAll, qui ignoraientmax_execution_timeetKILL QUERY. Un appel unique vérifie désormais l’annulation en cours d’exécution, de sorte qu’un remplacement de longue durée sur une valeur volumineuse ou sur un grand nombre de lignes s’arrête au lieu d’occuper un thread du serveur jusqu’à son terme. Un tel appel n’ayant aucun résultat partiel à renvoyer, il lève le dépassement de l’échéance sous forme d’erreur lorsquetimeout_overflow_mode = 'break': systématiquement lorsqu’il est évalué par repliement de constantes, et dans le pipeline chaque fois que ce point de contrôle est atteint avant la vérification entre blocs de l’executor, qui continue d’arrêter la requête silencieusement. #112483 (groeneai). - Correction de
countSubstrings,countSubstringsCaseInsensitiveetcountSubstringsCaseInsensitiveUTF8, qui ignoraientKILL QUERYetmax_execution_time: un appel portant sur de nombreuses lignes ou de nombreuses correspondances pouvait continuer à s’exécuter pendant plusieurs minutes après l’annulation de la requête. #113369 (groeneai). - Correction d’un possible blocage d’une requête (pendant
receive_timeoutsecondes) lorsque celle-ci se termine très rapidement sur l’initiateur. #113551 (nickitat). - Correction de
countMatchesetcountMatchesCaseInsensitive, qui ignoraientmax_execution_timeetKILL QUERYlors du comptage des correspondances dans une valeur volumineuse, ce qui pouvait maintenir une requête annulée en cours d’exécution pendant plusieurs minutes. Avec un argument constant, l’appel a lieu pendant l’analyse de requêtes ; il n’existe donc aucun pipeline permettant de l’annuler. #113886 (groeneai). - Une requête pouvait être annulée jusqu’à 1 ms avant l’expiration de son
max_execution_time, et échouer avec le message contradictoireTimeout exceeded: elapsed 999.672 ms, maximum: 1000 ms. #114559 (alexey-milovidov). - Correction d’une lecture hors limites dans
pointInPolygonavec un polygone constant dont la boîte englobante n’est pas bornée, par exemple lorsqu’une coordonnée atteint+-DBL_MAX. Un tel polygone est désormais rejeté avecBAD_ARGUMENTS, et un polygone comportant un anneau vide est considéré comme dépourvu d’intérieur. Auparavant, la requête pouvait renvoyer un résultat erroné, voire faire planter le serveur dans les builds où le durcissement ou les sanitizers étaient activés. #115035 (groeneai). - Correction d’une condition de concurrence qui pouvait amener une requête
STREAM BOUNDEDà renvoyer moins de lignes que celles validées avant son démarrage, le plus souvent aucune. #115543 (alexey-milovidov). - Correction de l’erreur
Unknown identifierlevée lors de l’optimisation du plan de requête avecmake_distributed_plan = 1lorsque la colonne de tri d’une requête de fenêtrage passe par une étapeExpressionqui ne la mentionne pas. #115890 (groeneai). - Correction de
h3kRing,h3HexRing,h3Lineeth3ToChildren, qui ignoraientmax_execution_timeetKILL QUERYlors de l’expansion d’un bloc de lignes. #115893 (alexey-milovidov). - Correction de l’erreur
NOT_FOUND_COLUMN_IN_BLOCKdans le lecteur Parquet V3 natif (à la suite d’une régression antérieure) lorsqu’unPREWHEREcomportait des conjonctions partageant une expression intermédiaire commune. #107059 (groeneai). - Correction d’un blocage lors de l’écriture de fichiers Parquet avec
output_format_parquet_parallel_encodingactivé (valeur par défaut) etmax_threadssupérieur à 1. Si l’encodeur ne parvenait pas à planifier un thread supplémentaire, son compteur de threads actifs subissait un dépassement par le bas (underflow) et l’écriture pouvait se bloquer définitivement au lieu de se terminer ou de signaler une erreur. #112959 (groeneai). - Correction d’une allocation mémoire non bornée lors de la lecture d’un fichier Parquet dont les métadonnées Thrift déclarent une longueur de conteneur ou de chaîne supérieure à la taille des métadonnées elles-mêmes. Une telle longueur est désormais rejetée au lieu de donner lieu à une allocation. #113212 (groeneai).
- Correction d’une exception
std::out_of_range(Logical error: 'std::exception. Code: 1001, type: std::out_of_range', qui provoque également l’arrêt du serveur dans les builds de débogage et avec sanitizer) dans le lecteur Parquet v3 lorsqu’une colonne nécessaire uniquement à l’évaluation d’un filtre était planifiée pour décodage alors que son emplacement de sortie avait déjà été supprimé. #113956 (groeneai). - Correction de data races dans les profile events et le memory tracker. #112466 (mstetsyuk).
- Correction d’une data race théorique dans les profile events lors de l’utilisation du paramètre
trace_profile_events_listpour écrire les stack traces de certains profile events danssystem.trace_log. #113553 (mstetsyuk). - Correction de
intDivOrNull,moduloOrNulletpositiveModuloOrNull, qui renvoyaient0au lieu deNULL, ainsi que deintDivOrNulletintDivOrZero, qui levaient une exception au lieu de renvoyerNULL/0, lorsque la division entraîne une exception en virgule flottante (division par zéro ouINT_MIN / -1), y compris avec des arguments mixtes signés/non signés. #101976 (yariks5s). - Correction de
IS DISTINCT FROMpour les valeursArrayetMapcomparées àNULL. #103162 (ylw510). - Correction de
groupConcatlorsque les syntaxes paramétrique et à deux arguments sont combinées, par exemplegroupConcat(',', 2)(x, '/'): le paramètre de limite de lignes était ignoré silencieusement, si bien que toutes les lignes étaient renvoyées au lieu du nombre demandé ; le délimiteur fourni par le second argument remplace désormais correctement le paramètre. #104882 (yariks5s). - Correction de bogues lors de l’utilisation de CAST d’unités d’intervalle plus petites vers des unités plus grandes. #105058 (yariks5s).
- Correction d’une erreur logique (
Assertion 'row < chunk.getNumRows()' failed) dans les requêtesLIMIT ... WITH TIESexécutées avec le pipeline de lecture ordonnée (optimize_read_in_order = 1etread_in_order_use_virtual_row_per_block = 1). #105102 (groeneai). - Correction de
Logical error: 'Pipeline stuck'dans les requêtes qui utilisentenable_sharding_aggregator = 1conjointement avec unUNION ALLet une valeur demax_streams_for_union_stepinférieure à la largeur du pipeline.BufferedShardByHashTransformtermine désormais les ports de sortie dont la file d’attente est vide dès que son entrée est épuisée, et continue de lire l’entrée lorsqu’un port vide sollicité n’a rien à vider, même si une file d’attente voisine a atteint la limite de contre-pression. #106251 (groeneai). - Correction de
removeDirectorysur les disques de stockage objetplain(tels ques3_plain), qui supprimait tous les fichiers d’un répertoire non vide comme si la suppression était récursive. La suppression d’un répertoire non vide échoue désormais avecCANNOT_RMDIR, et la suppression récursive traite explicitement le contenu. #106281 (RinChanNOWWW). - Correction des fonctions définies par l’utilisateur
executable_poolconfigurées avec<lifetime>, qui ne prenaient pas en compte les modifications du script sous-jacent. Auparavant, seulSYSTEM RELOAD FUNCTIONSrelisait un script modifié ; les rechargements périodiques via<lifetime>continuaient d’exécuter l’ancienne version. #107087 (groeneai). - Correction d’une condition de concurrence sur le collecteur de traces global du serveur, entre le démarrage du profileur d’un thread de travail et l’arrêt du serveur. #107307 (groeneai).
- Correction d’un rare plantage du serveur lors de son arrêt (
std::future_error, « The associated promise has been destructed prior to the associated state becoming ready ») provoqué par une tâche planifiée viathreadPoolCallbackRunnerUnsafeet retirée de la file d’attente du thread pool avant son exécution. #107383 (groeneai). - Correction d’une erreur logique de
FileLog(Last stored last_written_position in meta file ... is bigger than current last_written_pos) qui pouvait survenir lorsqu’un fichier surveillé était supprimé puis recréé avec le même inode. #107617 (groeneai). - Correction de
toTime64etCAST(... AS Time64), qui ne ramenaient pas les valeurs hors plage dans la plage deTime64avec les modes de dépassement de capacitésaturateetignore, ce qui pouvait produire des valeurs affichées à l’identique mais considérées comme différentes lors des comparaisons. #108028 (alexey-milovidov). - Correction de la gestion des assertions de largeur nulle (
\b,^,$) dans les fonctions regexp de type « match all »extractAll,extractAllGroupsVertical,extractAllGroupsHorizontal,countMatchesetsplitByRegexp. Par exemple,extractAll('new york is the greatest', '\b(\w)')renvoie désormais correctement la première lettre de chaque mot au lieu de chaque lettre. #108047 (alexey-milovidov). - Correction de résultats incorrects lors de l’utilisation de
hasTokensur des index de texte avec un tokenizer autre quesplitByNonAlpha. #108066 (rschu1ze). - Correction de
toStartOfIntervaletdateTrunc, qui renvoyaient une valeur arrondie au lieu du début de l’intervalle englobant lorsque l’entrée avait une précision plus fine que l’unité de l’intervalle ; par exemple,toStartOfInterval(toDateTime64('2023-10-09 10:11:12.000999', 6), INTERVAL 1 millisecond)renvoyait10:11:12.001au lieu de10:11:12.000. La surcharge avec une origine explicite était également concernée. #108186 (yariks5s). - Correction de
replaceRegexpOneetreplaceRegexpAllafin que.corresponde par défaut aux caractères de nouvelle ligne, à l’instar des autres fonctions d’expressions régulières. #108265 (linjiayu1025-collab). - Correction de la double évaluation des conditions des UPDATE/DELETE légers. #108323 (ofeliacode).
- Correction de
arrayPartialSort()avec un argument de limite non constant. #108327 (vitlibar). - Correction des fonctions d’expressions régulières (
match,extract,extractAll,replaceRegexpOne,replaceRegexpAll, etc.) qui renvoyaient silencieusement des résultats erronés lorsque le motif contenait un octet NUL (\0). L’octet NUL est désormais traité comme un octet littéral ordinaire, conformément au comportement de RE2. #108427 (alexey-milovidov). - Correction de
changeYear/changeMonth/changeDay/changeHour/changeMinute/changeSecondappliquées à un argumentDateTime64(N), qui créaient la colonne de résultat avec la scale par défaut codée en dur (3) au lieu deN. Les valeurs étaient calculées avec la scaleN, mais l’objet colonne déclarait une scale de 3, ce qui le rendait structurellement incohérent avec son type. #108551 (groeneai). - Correction d’une erreur
LOGICAL_ERROR(« Trying to extract chunk from ChunkBuffer before all inputs are finished ») lorsqu’une opération ensembliste (INTERSECT/UNION ALL/EXCEPT) combine des branches utilisant des sous-requêtes corrélées aveccorrelated_subqueries_default_join_kind = 'left'. #108554 (groeneai). - Correction de bogues liés à
DateTime64danschangeYear,changeMonth,changeDay,changeHour,changeMinuteetchangeSecond: les entrées avec une precision à la nanoseconde (scale 9) ne lèvent plusDECIMAL_OVERFLOW, et les entrées inférieures à la seconde antérieures à l’epoch renvoient désormais la seconde calendaire correcte. #108681 (takumihara). - Suppression des sorties excessives dans le journal du serveur et des messages d’erreur démesurés lors de la compilation d’une très grande expression régulière (par exemple un motif
LIKEoumatchcomportant des centaines de milliers de jokers) ; ces motifs échouent désormais avec une erreur expliciteCANNOT_COMPILE_REGEXP. #108821 (Algunenano). - Correction de
reinterpret(x, 'Decimal128(scale)')(ainsi que des ciblesDecimal32/Decimal64/Decimal256/DateTime64), qui produisait une colonne de résultat dont la scale interne était celle de la source au lieu de la scale cible demandée lorsque la source et la cible avaient le même type physique. Les valeurs étaient correctes, mais l’objet colonne était structurellement incohérent avec son type déclaré. #108878 (groeneai). - Correction d’un comportement indéfini lors de la conversion en chaîne d’un type de paquet de protocole hors limites (par exemple dans les messages d’erreur « Unexpected packet from server » / « Received … packet ») pour une connexion désynchronisée ou soumise à du fuzzing. #108885 (groeneai).
- Correction de
changeYear/changeMonth/changeDay/changeHour/changeMinute/changeSecondsurDateTime64(N), qui construisaient la colonne de résultat avec la scale par défaut codée en dur à 3 au lieu deN, ainsi que detimeSlotssurDateTime64, qui ignorait la scale de l’argument facultatifSizedans son type de retour déclaré. Dans les deux cas, la colonne produite avait une scale physique différente de son type déclaré, ce qui provoquait uneLOGICAL_ERROR(writeSlice expects same column types) lorsque le résultat était passé àarrayPushBack/arrayPushFront/arrayConcat, ettimeSlotsrenvoyait des timestamps erronés lorsqueSizeavait la plus grande scale. #108994 (groeneai). - Correction des incréments non monotones des ProfileEvents #109180 (azat).
- Correction des ratios
SAMPLEdont l’exposant est trop grand en valeur absolue pour tenir dans unInt32(par ex.SAMPLE 1e-3000000000), qui étaient traités silencieusement commeSAMPLE 1. #109197 (Algunenano). - Correction de deux bogues dans le traitement
DateTime64detoUTCTimestamp/fromUTCTimestamp(et de leurs aliasto_utc_timestamp/from_utc_timestamp) ainsi que detoTime64. D’une part, un dépassement de capacité d’entier signé près de la limite deInt64(le calcul est désormais effectué enInt128et borné à la plage représentable). D’autre part, un résultat erroné pour les valeurs fractionnaires négatives proches d’un changement de décalage de fuseau horaire : la séparation des secondes tronquait vers zéro, si bien quetimezoneOffset()examinait la seconde suivante et pouvait se placer du mauvais côté d’un changement d’heure (DST) ou de décalage. #109738 (groeneai). - Correction d’une erreur logique (
column->size() == num_rows) lorsqu’une expression de filtre de politique de ligne utilisearrayJoin; ces filtres sont désormais rejetés. #109753 (Algunenano). - Correction de
generateRandomStructure(), qui produisait parfois une chaîne de structure invalide contenant deux types de données concaténés (par exempleDecimal32(7)IPv4) lorsque l’imbrication des types dépassait la limite de profondeur interne, ce qui rendait le résultat impossible à analyser. #109928 (groeneai). - Correction de la propagation des paramètres de requête dans
accurateCastOrDefaultet de la préservation desNULLd’origine encodés parDynamicetVariant. #109946 (Avogar). #114912 (alexey-milovidov). - Correction de
max_bytes_in_distinctetmax_bytes_in_set: les clés de type string sont stockées dans une arena qui n’était pas prise en compte par les vérifications de limite, si bien que DISTINCT / IN sur des clés string pouvaient occuper une quantité de mémoire dépassant la limite en octets de toute la taille des clés (sans borne, quelle que soit la longueur des clés). Les limites tiennent désormais compte de l’arena, conformément à leur documentation ; les requêtes avec des clés string proches d’une limite en octets peuvent donc l’atteindre plus tôt (à juste titre). #110120 (skuznetsov-clickhouse). - Correction de la lecture des fichiers Npy comportant des dimensions internes de taille nulle, afin que les lignes matérialisées et les résultats de
count()optimisés et non optimisés concordent. #110146 (qiuyanjun888). - Correction d’une erreur logique (arrêt du serveur dans les constructions debug/sanitizer) lorsque les fonctions
indexHint/ignore/isZeroOrNullreçoivent un argument dont le type se résout enNothing, par exemple dans des expressions commeindexHint(assumeNotNull(materialize(NULL))). #110192 (groeneai). - Correction de la lecture des fichiers sur les disques
plain_rewritableaprès la réécriture d’un path existant avec un contenu de taille différente : les métadonnées en mémoire conservaient l’ancienne taille du fichier, ce qui pouvait faire échouer les lectures avecUNEXPECTED_END_OF_FILE. #110304 (thevar1able). - Rejet des valeurs de
vector_search_index_fetch_multiplierinférieures à 1.0 afin d’éviter des résultats de recherche ANN vides lorsque le nombre de récupérations calculé est tronqué à zéro. #110452 (tamish560). - Correction d’une erreur sporadique
Cannot parse string ... as UInt64 ... While executing ValuesBlockInputFormatpouvant survenir lors de l’insertion de valeurs dont les expressions contiennent une conversion numérique telle queinitializeAggregation('sumState', 0::UInt64). #110637 (groeneai). - Correction de
readWKT, qui rejetait les strings WKT commençant par des espaces (par ex.readWKT(' POINT(1 2)')), pourtant acceptées par les lecteurs typésreadWKTPoint/readWKTPolygon/… ainsi que par la grammaire WKT. #110706 (groeneai). - Correction d’un plantage du serveur (division entière par zéro) lors de la consommation d’un quota dont l’intervalle est de durée nulle (par exemple CREATE QUOTA q FOR INTERVAL 0 SECOND MAX queries = 1000). Une durée d’intervalle de quota négative ou nulle est désormais rejetée dès la création du quota. #110846 (PedroTadim).
- Correction d’un plantage dans les constructions FIPS lors de l’utilisation d’une clé SSH Ed25519 (
CREATE USER ... IDENTIFIED WITH ssh_key ... TYPE 'ssh-ed25519', ou une telle clé dansusers.xml). Ed25519 n’étant pas approuvé par FIPS, ces clés sont désormais rejetées avec une erreurLIBSSH_ERRORexplicite. #110891 (thevar1able). - Les fonctions de distance transposées sur
QBit(cosineDistanceTransposed,L2DistanceTransposed,dotProductTransposed) utilisent désormais une reconstruction bornée à faible précision d’une valeur tronquée àprecisionplans de bits, au lieu de la reconstruire à la borne inférieure de la cellule grossière (bits supprimés remplis de zéros). Le remplissage par des zéros biaisait chaque valeur reconstruite vers zéro et dégénérait à faible précision : pourQBit(BFloat16)avec une précision de 1, seul le bit de signe subsistait, si bien que toutes les valeurs étaient reconstruites à±0.0et que la distance était une même constante pour toutes les lignes, sans aucune information de classement. La reconstruction dépend désormais des bits supprimés : les codesInt8bruts sont reconstruits au centre de leur cellule (comme la reconstructionLloyd-Maxdéjà utilisée par le chemin...TransposedQuantized) ; une valeur à virgule flottante avec une précision de 1 devient une véritable quantification de signe ; une valeur à virgule flottante qui conserve l’intégralité de son exposant et ne perd que des bits de mantisse est reconstruite au point médian borné de sa propre binade (tandis qu’un véritable zéro ou±0.0reste exactement à zéro et que la cellule non finie est isolée afin que±infreste exactement infini ; voir la remarque ci-dessous sur la cellule ambiguëNaN) ; enfin, tant que des bits d’exposant sont encore tronqués, la borne inférieure bornée est conservée, de sorte qu’uneprecisionplus faible sacrifie de l’exactitude au profit de la vitesse, sans gonfler une valeur de plusieurs ordres de grandeur. Les résultats en pleine précision restent inchangés. #110911 (alexey-milovidov). - Correction d’une lecture hors limites dans le lecteur ORC natif lors de l’inférence de schéma d’un fichier ORC corrompu dont l’arbre de types déclare plus de colonnes que le pied de stripe ne contient d’encodages de colonnes. Ce fichier est désormais rejeté avec
CANNOT_EXTRACT_TABLE_STRUCTUREau lieu de provoquer l’arrêt du serveur dans les constructions debug/sanitizer. #110967 (groeneai). - Chaque clé SSH compte désormais individuellement dans la limite
max_authentication_methods_per_user, afin que la limite s’applique de manière cohérente quelle que soit la syntaxe. Auparavant, plusieurs clés déclarées dans une même méthodessh_keyne comptaient que pour une seule. #111181 (TheMC47). - Les catalogues REST Iceberg signalent désormais les identifiants expirés en indiquant l’erreur sous-jacente, au lieu de renvoyer silencieusement
UNKNOWN_TABLE. #111379 (alesapin). - Correction de
readWKTPoint/readWKT, qui renvoyaient des coordonnées non initialisées (en mode scalaire) ou celles de la ligne précédente (en mode vectorisé) pour un point vide avec indicateur de dimension tel quePOINT M EMPTY. Ces entrées sont désormais rejetées avecCANNOT_PARSE_TEXT, comme c’est déjà le cas pourPOINT EMPTY. #111517 (groeneai). - La création de statistiques
minmaxémet désormais un avertissement au lieu de lever une exception. #111785 (hanfei1991). randBinomialreste utilisable avec les probabilités dégénérées0et1, quel que soit le nombre d’essais. #112021 (alexey-milovidov).- Correction de
system.s3_queue_settings, qui renvoyait des valeurs incorrectes pourbucketing_mode,partitioning_mode,partition_regexetpartition_component. #112300 (bharatnc). - Les erreurs dans les requêtes PromQL indiquent désormais la position correcte. #112494 (fallintoplace).
SYSTEM DISABLE FAILPOINTrejette désormais un nom de fail point inexistant en levantBAD_ARGUMENTS, comme le faisait déjàSYSTEM ENABLE FAILPOINT. Auparavant, un nom mal saisi renvoyait un succès tout en laissant activé le fail point visé, sans aucune indication que rien n’avait été désactivé. #112680 (groeneai).- Correction d’une lecture mal typée d’une sous-colonne d’élément
Nesteddont la colonne avait été supprimée puis rajoutée. Sélectionner une telle sous-colonne en même temps que sa propre colonne parente renvoyait l’élément entier à l’emplacement de la sous-colonne, alors que le bloc déclarait toujours le type d’élément. Cela produisait des valeurs arbitraires dans les constructions de production, et une erreur logique dans les constructions de débogage et avec sanitizer. #112769 (groeneai). - Rejet des durées PromQL dont les unités sont répétées ou ne sont pas classées de la plus longue à la plus courte. #112954 (fallintoplace).
- Correction d’un comportement indéfini (pointeur nul passé à
memcpy) dansreplaceRegexpOne/replaceRegexpAlllorsque la string de remplacement fait référence à un groupe capturant qui n’a pas participé à la correspondance, par exemplereplaceRegexpAll('abc', '(a)|(b)', '\\2'). #113012 (alexey-milovidov). - Correction d’une incompatibilité empêchant le chargement, dans les versions ultérieures, des index de texte créés dans ClickHouse 26.3 avec le tokenizer
unicode_word#113061 (rschu1ze). - Rejet des points de code Unicode de substitution (surrogates) invalides dans les séquences d’échappement des strings PromQL. #113203 (fallintoplace).
- Rejet des échappements de délimiteurs croisés invalides dans les strings PromQL. #113587 (fallintoplace).
- Correction de
theilsUsur un frame de fenêtre, qui renvoyait une valeur arbitraire au lieu de 0 lorsque le premier argument est constant au sein du frame. #113691 (alexey-milovidov). - Correction du code d’erreur signalé pour certaines colonnes sérialisées
Replicatedmalformées reçues via le protocole Native : elles sont désormais rejetées avecINCORRECT_DATAau lieu deLOGICAL_ERROR(qui provoquait l’arrêt du serveur dans les builds de débogage et les builds avec sanitizer). #114186 (Avogar). - Correction des littéraux
Time64et des constantes de listeINincorrects, souvent de signe inversé, produits lorsque la remise à l’échelle d’unDecimal64d’échelle inférieure provoquait un dépassement de capacité deInt64. Une telle conversion signale désormaisDECIMAL_OVERFLOW, à l’instar de la brancheDateTime64et duCASTexplicite. #114546 (groeneai). - Prise en charge des noms de métriques et de labels entre guillemets dans les sélecteurs PromQL. #114551 (fallintoplace).
- Correction des tables
ReplicatedMergeTreequi restaient indéfiniment en lecture seule après l’échec d’une tentative de démarrage exécutée via le thread d’attachement. La nouvelle tentative de redémarrage est désormais correctement planifiée, ce qui rétablit la récupération automatique et ses vérifications de session. #114802 (azat). timeSeriesRangeettimeSeriesFromGridlevaient à tort une erreurDECIMAL_OVERFLOWpour les timestamps antérieurs à 1970, car les timestamps de début et de fin étaient lus comme des valeurs non signées. En outre, pour les timestampsDateTime/UInt32, le pas était silencieusement tronqué à ses 32 bits de poids faible. Tous les calculs sont désormais effectués enInt64. #114815 (vitlibar).- Correction d’une exception susceptible de se produire dans les insertions asynchrones après l’échec d’une requête avec
MEMORY_LIMIT_EXCEEDED, et correction deasync_insert_queue_flush_on_shutdownafin que les insertions en file d’attente soient écrites sur disque lors de l’arrêt du serveur. #114839 (azat). - Correction d’une exception
out_of_rangelevée sous la forme d’une erreur interneCode: 1001lorsqu’un motifsequenceMatch,sequenceCountousequenceMatchEventscontient le numéro d’événement0, par exemplesequenceMatch('(?0)'). Un tel motif est désormais rejeté avecBAD_ARGUMENTS. Une condition temporelle ne contenant qu’un signe, commesequenceMatch('(?1)(?t>+)(?2)'), était silencieusement interprétée comme(?t>0); elle est désormais rejetée avecSYNTAX_ERROR. #115056 (groeneai). - Correction du message d’erreur de
geoToH3, qui indiquait une position d’argument et un type erronés lorsqu’une coordonnée n’est pas de typeFloat64. Avec la valeur par défautgeotoh3_argument_order = 'lat_lon', le message désignait l’autre argument et affichait le type de celui-ci. #115503 (groeneai). - Correction des caractères d’échappement antislash invalides dans les index text, tokenbf_v1 et ngrambf_v1. #115634 (ahmadov).
- Correction d’un problème empêchant le serveur de démarrer lorsque la variable d’environnement
TZétait vide. #68921 (ardenwick).