FORMAT Native géré par le client, ce qui couvre query, query_np, query_df, leurs variantes de streaming par bloc et par ligne, ainsi que les insertions, y compris insert_df. Les méthodes Arrow utilisent FORMAT Arrow et ne sont donc pas concernées, pas plus que les requêtes raw, les insertions raw et les formats non natifs.
Le codec est expérimental et son utilisation est optionnelle. Le codec Python reste celui utilisé par défaut.
Installation
Le codec compilé est fourni sous la forme d’un paquet wheel distinct, nomméclickhouse-connect-core, qui contient le module d’extension _ch_core. Installez le codec avec les intégrations utilisées par votre application :
query_np, query_df, leurs variantes en streaming, ainsi que query(..., use_numpy=True). Les requêtes NumPy ne nécessitent pas Pandas. Ajoutez l’extra async pour utiliser le client asynchrone.
PyArrow reste nécessaire pour les méthodes Arrow et le stockage Pandas basé sur Arrow. Installez l’extra arrow pour bénéficier de ces fonctionnalités :
mode.string_storage de Pandas. Lorsque PyArrow est installé, les strings utilisent la conversion Arrow existante, avec une validation UTF-8 complète, quel que soit le backend de stockage. Sans PyArrow, le driver utilise la conversion d’objets Rust, et le stockage par défaut de Pandas utilise des strings Python. Demander explicitement le stockage de strings Arrow sans PyArrow lève une erreur de dépendance. Les données UTF-8 invalides conservent le rendu hexadécimal existant, quel que soit le backend de stockage.
Le codec, son empaquetage et ses dépendances sont expérimentaux. La conversion directe par tampon prend désormais en charge les colonnes d’integers non nullable de 8 à 64 bits, ainsi que les colonnes Float32/64, Boolean, BFloat16, Interval, Date, Date32, DateTime et DateTime64. Les colonnes scalaires Time et Time64, y compris les valeurs nullable, utilisent également des tampons directs, tout comme BFloat16 nullable et la sortie Pandas étendue des integers, flottants et Interval nullable. BFloat16 conserve une sortie float32 ainsi que sa politique actuelle de gestion des valeurs manquantes Float32 dans Pandas. Les valeurs Interval restent des décomptes signés exprimés dans leur unité déclarée. La conversion temporelle conserve les unités déclarées et les règles de fuseau horaire existantes. Les alias SimpleAggregateFunction nullable de Time64 renvoient désormais des durées correctes, et NaT pour les valeurs NULL. Les colonnes scalaires nullable DateTime64(9) utilisent également des tampons afin de préserver les nanosecondes dans la sortie NumPy et Pandas. Les autres dates et timestamp nullable conservent leurs chemins de conversion d’objets.
Les tableaux de Time/Time64, y compris les tableaux imbriqués et les feuilles nullable, ainsi que LowCardinality(Time), y compris les valeurs nullable, utilisent également des tampons directs. Leur imbrication, leurs unités de durée et leur représentation des valeurs nulles restent inchangées. LowCardinality(Time64) n’est toujours pas pris en charge par le cœur Rust.
Pour les colonnes scalaires nullable DateTime64(9), query_df et query_df_stream préservent les neuf chiffres fractionnaires, y compris via les alias SimpleAggregateFunction. Sous Pandas 3, les colonnes datetime de la sortie par défaut utilisent désormais la nanoseconde comme unité, et non plus la microseconde. L’inférence existante du dtype object pour les blocs entièrement NULL reste inchangée. Si un fuseau horaire nommé fait sortir une valeur de la plage en nanosecondes de Pandas, la colonne concernée conserve sa conversion d’objets et son comportement de plage antérieurs.
Pour ces colonnes, les champs object de query_np et query_np_stream contiennent désormais des cellules numpy.datetime64 au lieu de cellules Python datetime, avec None pour les NULL SQL. Les valeurs associées à un fuseau nommé utilisent des ticks UTC sans métadonnées de fuseau horaire, comme le codec Python. Les nanosecondes sont ainsi préservées sans nécessiter Pandas. Utilisez query_df si vous avez besoin de timestamp tenant compte du fuseau horaire. Les autres types de cellules temporelles NumPy nullable restent inchangés.
Les requêtes NumPy et Pandas sur des DateTime64 scalaires rejettent toute précision autre que 0, 3, 6 et 9 avec une ProgrammingError, y compris pour les colonnes nullable et les alias SimpleAggregateFunction.
Si un codec Rust est sélectionné alors que le module compilé n’est pas installé, la création du client lève une NotSupportedError indiquant cette commande d’installation.
Activation du codec
Sélectionnez le codec via l’option clientnative_codec :
La valeur par défaut peut également être définie via le paramètre commun
native_codec ou la variable d’environnement CLICKHOUSE_CONNECT_NATIVE_CODEC. L’ordre de préséance est le suivant : l’argument nommé du client, puis le paramètre commun, puis la variable d’environnement.
L’option est ignorée pour les clients interface="chdb", qui utilisent toujours le codec Python.
Quand utiliser le codec Rust
Le codec Rust est particulièrement utile pour les résultats DataFrame volumineux comportant du texte, des conteneurs et des types complexes tels queString, LowCardinality, Map, Array, JSON, Decimal et UUID. Il peut également bénéficier aux flux volumineux de blocs de lignes et de colonnes, aux charges de travail de requêtes concurrentes et aux insertions en masse.
Les petits résultats et les requêtes limitées par le réseau ne montreront sans doute que peu de différence. Les résultats numériques plats empruntent déjà des chemins d’accès en masse efficaces dans le codec Python : le gain y sera donc lui aussi plus limité.
Les tampons directs évitent de passer par des tableaux Arrow intermédiaires pour les types pris en charge. L’assemblage final des résultats NumPy et Pandas peut toutefois encore nécessiter des allocations et des copies : tous les résultats de requête ne sont donc pas pour autant zero-copy.
Sans PyArrow, la conversion des strings par Rust construit des objets string Python à partir de chaque bloc décodé. Avec les tailles de bloc par défaut, le pic de mémoire pour les résultats String volumineux est proche de celui du codec Python. Les très grands blocs, par exemple un bloc unique contenant un million de lignes, maintiennent l’intégralité du bloc décodé en mémoire pendant la construction de ses strings et peuvent entraîner un pic de mémoire supérieur à celui du codec Python. Pour les résultats Pandas StringDtype volumineux, installez l’extra arrow et utilisez le stockage de strings Arrow. Pandas 3 sélectionne le stockage Arrow par défaut lorsque PyArrow est installé. Pandas 2 nécessite pd.options.mode.string_storage = "pyarrow".
Les appels query() bufferisés portant sur des résultats très larges ou entièrement numériques peuvent actuellement s’avérer plus lents et consommer davantage de mémoire de pointe avec le codec Rust. Pour ces charges de travail, privilégiez query_df, query_row_block_stream ou query_column_block_stream. Pour NumPy et Pandas, query_np_stream et query_df_stream permettent également de réduire le pic de mémoire. Traitez et libérez chaque bloc au fur et à mesure plutôt que de collecter l’intégralité du flux. La consommation de mémoire reste fonction de la taille de chaque bloc : diffuser en streaming un seul bloc volumineux n’apporte donc pas le même avantage.
Évaluez les performances sur votre propre charge de travail avant d’adopter le codec. Utilisez native_codec="rust_strict" pendant vos mesures afin qu’une option non prise en charge ou une dépendance manquante lève une erreur au lieu de rediriger silencieusement la requête vers Python.
Règles de fallback
Les décisions de fallback sont prises avant que le moindre octet ne soit lu ou envoyé : aucun changement de codec ne survient donc en cours de stream. Pour les requêtes, le choix intervient avant la consommation du response body. Pour les insertions, l’encodeur Rust n’est retenu que si tous les types de colonnes sont pris en charge ; sinon, l’insertion s’exécute intégralement avec le codec Python. Lorsquenaive_datetime_insert="server" est actif, rust route vers le codec Python toute insertion contenant une colonne DateTime ou DateTime64, afin que la timezone déclarée de la colonne ou la server timezone soit appliquée. rust_strict rejette cette combinaison. Le mode par défaut naive_datetime_insert="local" continue d’utiliser l’encodeur Rust.
Les requêtes de metadata internes au driver, y compris les statements de reflection du dialect SQLAlchemy, passent toujours par le codec Python, de façon silencieuse, quel que soit le mode.
Les payloads Native malformés détectés par le codec Rust lèvent DataError.
Versioning
clickhouse-connect-core est versionné indépendamment de clickhouse-connect. L’extra rust requiert clickhouse-connect-core>=0.2.1,<0.3. Le driver vérifie à la fois la version de l’API de binding et la capability column-buffer lorsqu’un codec Rust est sélectionné. Le wheel core 0.2.0 publié ne dispose pas de la capability column-buffer. Si le wheel installé est incompatible, la création du client lève une NotSupportedError pour rust comme pour rust_strict, indiquant la commande d’upgrade suivante :
clickhouse-connect-core et peuvent être obtenues par une simple mise à niveau vers un wheel core compatible. Les modifications de l’intégration Rust du driver nécessitent en revanche une mise à niveau de clickhouse-connect.
Différences de comportement connues
Le codec Rust vise une parité cellule par cellule avec le codec Python. Les différences suivantes sont connues.- Les résultats de
query_npetquery_dfpour les colonnesVariantcontiennent des objets Python simples plutôt que des valeurs scalaires numpy. Les valeurs sont identiques, mais les types de cellules diffèrent. - Les valeurs
DynamiccontenantTime64sont matérialisées sous la formedatetime.timedeltadans les résultats Rust dequery_npetquery_df. Aux échelles 0, 3, 6 et 9, les valeurs sont égales aux cellulesnumpy.timedelta64du codec Python, mais les types de cellules diffèrent. Aux autres échelles, le codec Rust renvoiedatetime.timedeltaalors que le codec Python lèveProgrammingError, car NumPy n’a pas d’unité correspondante. Les métadonnées des membres Dynamic ne sont pas exposées au driver après le décodage Rust : utilisez doncnative_codec="python"lorsque les types de cellules NumPy ou la validation des échelles non prises en charge sont nécessaires. - Pour
query_df, le codec Python peut convertir en chaîne les valeurs Compound stockées dans les shared data JSON. Le codec Rust renvoie des objets décodés, ce qui correspond aux résultats dequery_npdes deux codecs. - Une alternative
LowCardinalityplacée dans un conteneur qui se matérialise cellule par cellule, commeArray(Variant(...)), produit des cellules de valeurs égales qui ne partagent pas l’identité d’objet par slot de dictionary observée avec le codec Python. - Les colonnes
Nullable(Tuple(...))comportant un ou plusieurs elements sont décodées correctement par le codec Rust. Le codec Python interprète mal ce layout ; le résultat Rust constitue donc le comportement de référence. Les deux codecs prennent en chargeNullable(Tuple()). rust_strictrejette les options de requête que le chemin Rust n’implémente pas, telles que desquery_formatscustom par requête, plutôt que de modifier silencieusement le comportement.- Les erreurs de conversion et de validation lors d’une insertion Rust peuvent lever
DataErrorlà où le codec Python lèveValueError, et le texte du message peut différer. Exemples : valeursTimeetTime64invalides, adresses IPv6, dimensions QBit, longueursFixedString, chaînesFloat64et tentatives d’insertion d’elements dans une colonneTuple(). - L’encodeur Rust rejette
b""pourFixedString(N)ainsi que les chaînes numériques telles que"2"pour les colonnes integer. Le codec Python, lui, complète par des zéros une valeurFixedStringvide et convertit les chaînes numériques. - Le codec Rust décode certaines valeurs de variante partagée
Dynamicvers leurs types Python là où le codec Python laisse la valeur en raw bytes. Par exemple, unDecimalstocké peut être renvoyé commedecimal.Decimalpar Rust et comme valeur binaire par Python. - Pour les valeurs
Datedans le stockage partagéDynamic,query_npetquery_dfrenvoient des cellulesdatetime.dateavec le codec Rust et des cellulesnumpy.datetime64avec le codec Python. Les deux codecs renvoientdatetime.datedepuisquery.