Statut expérimental
Les interfaces principales du client, de la source de données, de la session et des opérations, ainsi que les extensions d’injection de dépendances, génèrent l’avertissement de compilationCHTCP0001. Pour prendre acte de cet avertissement pendant l’évaluation de l’API, ajoutez-le
à NoWarn dans votre fichier de projet :
Versions de .NET prises en charge
Le client TCP natif prend en charge les versions de .NET suivantes :- .NET 8.0
- .NET 9.0
- .NET 10.0
Versions de ClickHouse prises en charge
Le client TCP prend officiellement en charge les deux dernières versions LTS et les trois dernières versions du serveur ClickHouse.Installation
Le client TCP natif est inclus dans le paquetClickHouse.Driver. Installez-le via NuGet :
Démarrage rapide
Migration depuis le client HTTP
L’API TCP est distincte deIClickHouseClient : ce n’est pas une option de transport pour
ClickHouseClient ou ClickHouseConnection. La majeure partie du SQL peut être réutilisée, mais il faut instancier un
ClickHouseTcpClient et adapter chaque opération à son équivalent TCP.
Équivalences des méthodes
Par exemple, une boucle de lecture HTTP :
Options et paramètres
Les classes HTTPQueryOptions et ClickHouseParameterCollection ne sont pas interchangeables avec leurs
équivalents TCP. Placez les valeurs dans ClickHouseTcpQueryOptions : les paramètres de configuration y sont des chaînes de caractères et
les paramètres de requête font partie de l’objet d’options :
{name:Type} natifs de ClickHouse, mais ne réécrit pas
les caractères de substitution @name au format ADO.NET. Il ne permet pas non plus de définir, pour chaque requête, une base de données, un rôle, un jeton Bearer, un
en-tête personnalisé, un résolveur ou un formateur de paramètres, ni un convertisseur de lecture. Consultez les limitations pour connaître les
fonctionnalités qui restent propres au client HTTP.
Durée de vie des connexions et des résultats
Les deux clients de haut niveau peuvent être utilisés simultanément par plusieurs threads et doivent être réutilisés. Le client TCP gère des connexions natives persistantes plutôt que des connexions HTTP, implémenteIAsyncDisposable et doit normalement être
libéré de manière asynchrone à l’arrêt de l’application.
Les lignes renvoyées par QueryAsync appartiennent au code appelant. Les blocs de StreamAsync et leurs colonnes ne sont que des références temporaires, valides
uniquement pendant l’itération en cours ; copiez les valeurs à conserver au-delà. Allez toujours au bout d’une
énumération ou libérez-la pour que sa connexion soit remise dans le pool. Utilisez OpenSessionAsync lorsque plusieurs opérations
doivent s’exécuter sur la même connexion tout en conservant l’état de la session.
Consultez l’exemple complet de migration de HTTP vers TCP
pour voir les deux clients utilisés avec la même table.
Configuration
Il existe deux façons de configurer un client TCP natif :- Chaîne de connexion : paires clé/valeur séparées par des points-virgules qui indiquent l’endpoint du serveur, les identifiants d’authentification et d’autres options de connexion.
- Objet
ClickHouseTcpClientOptions: objet de configuration immuable et fortement typé, défini directement dans le code.
ClickHouseTcpClient. Utilisez
ClickHouseTcpConnectionStringBuilder pour analyser ou construire une chaîne de connexion, puis la convertir en
ClickHouseTcpClientOptions.
Paramètres de connexion
Dans la chaîne de connexion, les valeurs des propriétés de typeTimeSpan sont exprimées en secondes.
Format de données et sérialisation
Pool de connexions
Une connexion n’exécute qu’une seule opération à la fois. Le pool permet d’exécuter plusieurs opérations simultanément et réutilise les connexions d’une opération à l’autre.Sécurité
Le protocole natif sécurisé dispose d’un endpoint serveur distinct : il ne résulte pas d’une mise à niveau de la connexion existante. Un client TLS
doit se connecter à un port natif sécurisé ; il ne bascule pas vers une connexion en clair.
ConfigureTls est
appliqué en dernier et peut modifier la validation des certificats et des noms d’hôte ; examinez donc attentivement les fonctions de rappel
personnalisées.
Journalisation et débogage
Le composant de journalisation du client enregistre les événements liés au cycle de vie du client et à ses opérations. Les paquets de log du serveur sont quant à eux envoyés
à
ClickHouseTcpQueryCallbacks.OnLog. Le texte des statements peut contenir des données sensibles ; il est donc
exclu par défaut des étiquettes d’activité et fortement tronqué dans les logs de débogage.
Paramètres personnalisés
ClickHouseTcpClientOptions.CustomSettings applique des paramètres du serveur ClickHouse à chaque requête et
insertion. Les valeurs de ClickHouseTcpQueryOptions.Settings définies pour une opération donnée remplacent les valeurs de même nom
définies au niveau du client.
set_ :
set_ lorsque vous ajoutez un paramètre à CustomSettings ou aux Settings
propres à une opération.
ClickHouseTcpQueryOptions
ClickHouseTcpQueryOptions permet de définir des paramètres pour chaque opération. Toutes les propriétés sont facultatives.
ClickHouseTcpInsertOptions
ClickHouseTcpInsertOptions étend ClickHouseTcpQueryOptions avec des paramètres pour l’insertion
de blocs au format Native. Toutes les propriétés des options de requête restent disponibles.
ClickHouseTcpClient
ClickHouseTcpClient est l’API de haut niveau du protocole TCP natif. Il exécute des statements et des
requêtes scalaires, transmet les résultats sous forme de blocs colonnaires, de lignes ou de POCO, insère des données par colonne ou par ligne
et ouvre des sessions associées à une connexion dédiée.
Le client peut être utilisé simultanément par plusieurs threads et gère un pool de connexions. Créez un client par endpoint, réutilisez-le
dans toute l’application et libérez ses ressources à l’arrêt. Les opérations s’exécutent simultanément dans la limite de
MaxPoolSize ; au-delà, elles attendent qu’une connexion se libère, pendant au plus PoolTimeout.
Création d’un client
Créez un client à partir d’une chaîne de connexion ou deClickHouseTcpClientOptions. Consultez la section
Configuration pour connaître les paramètres disponibles.
À partir d’une chaîne de connexion :
PoolTimeout que les opérations en cours se terminent avant de les interrompre.
Injection de dépendances
AddClickHouseTcpDataSource enregistre une source de données unique (singleton) et expose son client partagé sous la forme de
IClickHouseTcpClient et IClickHouseTcpOperations :
LoggerFactory,
l’enregistrement utilise l’ILoggerFactory du conteneur. Une clé serviceKey permet d’enregistrer plusieurs
sources de données indépendantes.
Exécution des requêtes
UtilisezExecuteAsync pour les statements qui ne renvoient aucune ligne, notamment les instructions DDL et les mutations :
ExecuteAsync les lit puis les ignore. Pour
INSERT INTO ... VALUES, utilisez InsertAsync ou InsertRowsAsync et terminez le statement SQL par
VALUES, sans valeurs intégrées.
Lecture des données
Choisissez l’API de lecture selon la forme de résultat attendue par l’application :Lectures scalaires
ExecuteScalarAsync renvoie la valeur de la première colonne de la première ligne sous forme d’object :
NULL comme une requête
qui ne renvoie aucune ligne produisent toutes deux null.
Lecture ligne par ligne
QueryAsync transmet chaque ligne sous forme d’un tableau object[] qui lui est propre, dont les valeurs suivent l’ordre des colonnes du résultat :
Lecture des POCO
QueryAsync<T> associe les colonnes aux propriétés publiques dotées d’un accesseur set. La correspondance des noms ne tient compte ni de la casse ni
des traits de soulignement ; utilisez ClickHouseTcpColumn pour définir un nom explicite et ClickHouseTcpNotMapped pour
exclure une propriété.
Lecture de blocs colonnaires
StreamAsync expose le résultat colonnaire natif sous forme d’une séquence de valeurs Block. C’est la méthode la plus rapide pour lire les données.
Terminez toujours l’énumération ou libérez l’énumérateur pour que sa connexion soit rendue au pool.
Block.Column<T> donne accès au type CLR produit par le décodeur. Utilisez Block.ReadAs<T> ou une
interface spécialisée comme IDateTimeColumn si une conversion est nécessaire.
Insertion de données
Les insertions natives transmettent les données sous forme de blocs au format wire, organisés en colonnes. Le statement SQL doit être unINSERT INTO ... VALUES
sans liste de valeurs dans le statement. Utilisez des colonnes typées pour limiter au maximum le traitement côté client, ou les surcharges acceptant des lignes et des
POCO si l’application dispose déjà de données organisées par lignes.
Insertions par colonnes
InsertAsync accepte des données déjà regroupées en colonnes typées. C’est la méthode la plus rapide pour insérer des données.
InsertAsync, à condition que
l’insertion soit terminée avant la libération de ce bloc.
Insertion de lignes
InsertRowsAsync accepte des lignes de type object[]. Les valeurs correspondent, dans l’ordre, aux colonnes de la liste SQL :
Variant ou Dynamic. Ne modifiez pas les lignes tant que l’opération n’est pas terminée.
Insertions de POCO
La surcharge génériqueInsertRowsAsync<T> fait correspondre les colonnes de destination aux propriétés publiques accessibles en lecture, selon
les mêmes conventions de nommage et les mêmes règles relatives aux attributs que pour la lecture de POCO :
ClickHouseTcpNotMapped exclut du mappage les propriétés propres à l’application, comme
ImportBatch.
Paramètres SQL
Le client natif lie les valeurs aux caractères de substitution{name:Type} propres à ClickHouse. Il ne réécrit pas
les caractères de substitution @name au format ADO.NET.
ClickHouseTcpParameter.ClickHouseType. Utilisez le type Identifier pour les noms de tables et de colonnes.
Si un DateTime ou un DateTimeOffset désigne un instant précis, indiquez un fuseau horaire, par exemple
{timestamp:DateTime('UTC')} ; sinon, le fuseau horaire de la session du serveur risque d’en modifier l’interprétation.
ID de requête
Chaque opération possède un ID de requête utilisé dans les tables système de ClickHouse, les logs du client et les spans de trace. SiQueryId est nul ou vide, le client génère un nouveau GUID. Définissez-le si l’opération doit
être mise en corrélation avec un identifiant d’application :
Progression de la requête et métadonnées
DéfinissezClickHouseTcpQueryOptions.Callbacks pour recevoir les métadonnées au fil de la réponse :
OnLog, OnProfileEvents, OnTotals et OnExtremes sont empruntés et ne doivent pas être utilisés en dehors de la
fonction de rappel.
ClickHouse n’envoie pas de paquets de progression de requête pour les lignes téléversées lors d’une insertion. Utilisez
OnBlockWritten pour suivre les blocs envoyés par le client : cette fonction indique la progression du transfert, mais ne garantit pas que le
serveur a validé l’insertion.
Annulation
Chaque opération accepte unCancellationToken :
Informations sur le serveur et vérifications de son état
GetServerInfoAsync renvoie l’identité du serveur, sa version, son fuseau horaire et les informations sur le protocole négocié
lors de l’échange initial du protocole natif :
ProtocolRevision, la révision négociée entre le client et
le serveur. Pour les fonctionnalités SQL, comme les types de données et les fonctions, utilisez Version. La méthode réutilise une
connexion si elle est disponible et en ouvre une nouvelle si le pool est vide.
Utilisez PingAsync pour vérifier la disponibilité du service via le protocole natif :
Autres exemples
Pour consulter des exemples complets et exécutables couvrant la lecture, les insertions, les types, les sessions, TLS, l’observability et la gestion des erreurs, reportez-vous aux exemples en TCP natif dans le dépôt GitHub.Sessions
Les opérations client courantes utilisent n’importe quelle connexion disponible dans le pool. L’état propre à chaque connexion n’est donc ni isolé ni assuré d’être conservé d’un appel à l’autre. Les connexions du pool peuvent être établies avec des serveurs différents. Ouvrez une session lorsque des tables temporaires, des statementsSET ou une autre séquence d’opérations doivent utiliser la même connexion.
IClickHouseTcpSession expose les mêmes API de requête, d’exécution, d’insertion, de ping et d’accès aux informations du serveur
que le client. La session ne peut pas être utilisée simultanément par plusieurs threads. Ses opérations sont séquentielles : toute opération lancée avant la fin de la précédente
est rejetée. Un résultat transmis en flux garde la session occupée jusqu’à ce qu’il soit entièrement parcouru ou que son
énumérateur soit libéré.
Chaque session occupe un emplacement MaxPoolSize pendant toute sa durée de vie. Le client peut continuer à utiliser d’autres
connexions du pool, mais si celui-ci ne contient qu’une seule connexion, les autres opérations du client attendent
la libération de la session ou l’expiration du délai PoolTimeout.
Libérez la session avant de libérer le client qui l’a créée. La libération de la session ferme la
connexion qui lui est réservée au lieu de la remettre dans le pool, ce qui évite que les appels suivants n’héritent de ses
tables temporaires ou de ses paramètres. Une défaillance de la connexion ou du protocole, une annulation ou un flux de résultats incomplet
peuvent rendre la session inutilisable ; lorsque IsOpen passe à false, ouvrez une nouvelle session.
Bonnes pratiques
Durée de vie du client et pool de connexions
Créez unClickHouseTcpClient ou un ClickHouseTcpDataSource pour chaque combinaison distincte d’endpoint et de
configuration, puis réutilisez-le pendant toute la durée de vie de l’application. Le client peut être utilisé par plusieurs threads et gère
son propre pool de connexions ; en créer un à chaque opération revient à créer un nouveau pool et empêche la réutilisation des connexions.
Dans une application utilisant l’injection de dépendances, enregistrez AddClickHouseTcpDataSource une seule fois et injectez
IClickHouseTcpClient. Le fournisseur de services gère la durée de vie du client : les composants qui l’utilisent ne doivent donc pas libérer
l’instance injectée. Sans injection de dépendances, libérez le client à l’arrêt de l’application avec await using.
Chaque connexion native ne prend en charge qu’une opération à la fois. MaxPoolSize limite donc à la fois le nombre de
connexions ouvertes et celui des opérations simultanées ; les appels supplémentaires attendent qu’une place se libère, au maximum pendant PoolTimeout.
Choisissez une valeur adaptée au niveau réel de concurrence de l’application, sans dépasser les limites côté serveur
relatives aux connexions et aux requêtes. Augmenter cette valeur n’accélère pas une requête.
Tenez compte des utilisations suivantes du pool :
- Un résultat transmis en flux conserve sa connexion jusqu’à la libération de son énumérateur.
- Une session conserve une connexion pendant toute sa durée de vie et n’accepte qu’une opération à la fois.
- Si un résultat est abandonné, qu’une annulation survient pendant une opération ou qu’une erreur de protocole ou de connexion se produit, la connexion est fermée au lieu d’être réutilisée.
ClickHouse.Driver.Tcp.Pool pour diagnostiquer l’épuisement du pool,
la fermeture inattendue de connexions ou les reconnexions fréquentes.
Délais d’attente et annulation
Le client TCP applique des limites distinctes selon le type d’attente :
Un checkout qui attend d’abord un emplacement libre dans le pool, puis ouvre une connexion peut prendre jusqu’à
PoolTimeout + DialTimeout. ReadTimeout est réinitialisé à chaque lecture sur le transport : une requête longue qui
continue d’envoyer des informations de progression ou des données peut donc durer plus longtemps que cette valeur. Fixez-le à une valeur suffisamment élevée pour couvrir les périodes normales
de silence du serveur ; ne le définissez sur TimeSpan.Zero que si un autre délai d’attente borne de manière fiable
l’opération.
Utilisez un jeton d’annulation si vous avez besoin d’un délai d’attente couvrant l’ensemble de l’opération :
Gestion des dates et des heures
PrivilégiezDateTime('UTC') ou DateTime64(S, 'UTC') pour les timestamps et utilisez DateTimeOffset ou un
DateTime dont le Kind est Utc dans le code de l’application. L’instant représenté est ainsi explicite
et ne dépend pas du fuseau horaire du serveur ni de celui de la session.
Le client TCP applique les règles suivantes lors de l’écriture des valeurs DateTime :
Une heure sans fuseau horaire spécifié qui n’existe pas en raison du passage à l’heure d’été est rejetée, car elle ne correspond à aucun
instant. Si une heure est ambiguë lors du retour à l’heure d’hiver, la première occurrence est retenue. Utilisez
DateTimeOffset lorsque ce
choix doit être explicite.
Pour les paramètres SQL qui représentent un instant, indiquez le fuseau horaire dans le caractère de substitution :
DateTime et DateTime64 exposent par défaut leurs valeurs numériques brutes de type uint ou long.
Utilisez Block.ReadAs<DateTimeOffset>, IDateTimeColumn.GetDateTimeOffset ou une propriété POCO correspondante
si une valeur de date et d’heure est plus pratique. Conservez la valeur brute lorsque chaque chiffre compte :
DateTimeOffset a une résolution de 100 nanosecondes ; lire DateTime64 avec une échelle de 8 ou 9 par ce biais
entraîne une perte de précision en dessous du tick.
Utilisez DateOnly pour Date et Date32. Utilisez TimeSpan pour les valeurs Time et Time64 susceptibles d’être
négatives ou de dépasser 24 heures ; TimeOnly ne convient que si les valeurs de la colonne représentent
une heure de la journée.
Traitement en flux et durée de vie des résultats
UtilisezStreamAsync et des colonnes typées pour les traitements à haut débit. Cette approche respecte l’organisation
en colonnes de ClickHouse et évite les tableaux pour chaque ligne, le boxing et l’allocation d’objets POCO. Utilisez QueryAsync<T> lorsqu’un
modèle propre à l’application prime sur la réduction des allocations, et la version non typée de
QueryAsync uniquement lorsque le schéma n’est pas connu à la compilation.
Les blocs renvoyés par StreamAsync sont empruntés. Le bloc, ses colonnes, les colonnes enfants composites et
tous les spans ne sont valides que pendant l’itération en cours de la boucle. Traitez-les sur place ou copiez les valeurs qui
doivent rester disponibles après cette itération :
await foreach se charger de libérer l’énumérateur. Si vous n’avez besoin que d’une partie du
résultat, utilisez LIMIT en SQL et sélectionnez uniquement les colonnes nécessaires. Quitter
la boucle prématurément annule la réception du reste de la réponse et empêche la réutilisation de cette connexion.
Structure des insertions et traitement par lots
PrivilégiezInsertAsync avec des colonnes typées lorsque les données sont déjà organisées par colonnes. Cette méthode réduit au minimum les
conversions côté client. InsertRowsAsync<T> est le choix naturel pour les données POCO ; les lignes non typées
object[] sont les plus souples, mais nécessitent d’allouer des tableaux et de mettre en boîte les types valeur.
Envoyez un nombre suffisant de lignes à chaque appel d’insertion plutôt que de multiplier les insertions de petite taille. Lors d’un même
appel, MaxRowsPerBlock répartit les données en blocs au format wire natif. Sa valeur par défaut de 50 000 lignes
limite également la taille des tampons de colonnes temporaires utilisés pour convertir les lignes et les données POCO. Augmenter cette valeur peut
améliorer le débit pour les lignes comportant peu de colonnes, mais accroît le pic d’utilisation de la mémoire ; la définir sur null écrit toute
l’insertion dans un seul bloc et convertit en une fois toutes les données organisées par lignes de ce bloc.
MaxSendBufferBytes limite, indépendamment, la quantité de données encodées conservées en tampon avant leur envoi sur
le socket. Il s’agit d’une limite souple vérifiée entre les colonnes : une seule colonne volumineuse peut donc la dépasser.
Les données constituées de lignes ou de POCO sont converties bloc par bloc. Une valeur incorrecte dans un bloc ultérieur peut donc être
détectée alors que les blocs précédents ont déjà été envoyés. Vérifiez les contraintes de nullabilité et les types CLR avant
l’insertion si la qualité des données est incertaine, et définissez un DeduplicationToken dérivé des données chaque fois que
le lot logique est susceptible d’être envoyé à nouveau.
Types de données pris en charge
Les tableaux ci-dessous distinguent le type renvoyé par l’objetIColumn<T> décodé des autres types
disponibles par conversion avec Block.ReadAs<T>, par mappage de POCO avec QueryAsync<T> ou par insertion. Vous pouvez interroger le même
résolveur que celui utilisé par ces opérations pour savoir si un mappage donné est pris en charge :
Nullable, Array, Tuple, Map et LowCardinality s’appliquent récursivement à leurs
types internes.
Correspondance des types : lecture depuis ClickHouse
Default .NET type désigne le type T exposé par Block.Column<T> et IColumn<T>. Les types indiqués dans la
colonne Also readable as sont également accessibles avec Block.ReadAs<T> et les propriétés des POCO.
Types entiers
Types à virgule flottante
Types décimaux
ClickHouseTcpDecimal stocke une mantisse entière de taille arbitraire et une scale, ce qui permet de conserver les valeurs
dont la précision dépasse celle que peut représenter decimal.
Type booléen
Types de chaînes de caractères
Utilisez
IStringColumn.GetBytes(row) ou lisez les données sous forme de byte[] si elles risquent de ne pas être au format UTF-8 valide.
FixedString(N) conserve les N octets, y compris les octets nuls en fin de chaîne.
Types de date et d’heure
La représentation sous forme d’entier brut est utilisée par défaut pour que les lectures colonnaires conservent la valeur wire exacte. Les
conversions en date et heure utilisent le fuseau horaire déclaré par le type, ou celui de la session si le type
n’en déclare pas. La lecture de
Time ou de Time64 sous forme de TimeOnly lève une exception si la valeur est négative ou égale
ou supérieure à 24 heures ; utilisez TimeSpan pour couvrir toute la plage de valeurs de ClickHouse.
Types énumérés
IEnumColumn expose également la correspondance déclarée entre les libellés et leurs valeurs ordinales.
Autres types scalaires
Types composites
Les tuples peuvent contenir jusqu’à sept éléments. La lecture d’une colonne
Nested, quelle que soit son arité, se fait de préférence
avec INestedColumn, qui donne accès à ses colonnes de champs nommés à plat et aux décalages de lignes partagés sans
allouer d’enregistrements encapsulés dans des objets. Avec la valeur par défaut flatten_nested = 1 de ClickHouse, les champs imbriqués sont plutôt renvoyés sous forme de
colonnes Array(T) distinctes dont les noms comportent des points.
Types Variant, Dynamic et JSON
Variant et Dynamic renvoient, pour chaque ligne, la valeur CLR du type sélectionné ou null. Leurs
vues colonnaires donnent accès au flux des discriminateurs et à une colonne enfant typée pour chaque type présent à l’exécution, ce qui évite
le boxing lors du traitement des données par colonne.
Le client TCP lit JSON au moyen de la sérialisation String de ClickHouse. Il active
output_format_native_write_json_as_string = 1 par défaut ; si ce paramètre est désactivé, la lecture de JSON n’est
plus prise en charge. ClickHouse analyse et normalise le JSON : le texte renvoyé peut donc différer du texte inséré
par l’ordre des clés, les espaces ou le format des nombres.
Types géométriques
Geometry est représenté par une IVariantColumn regroupant les six types géométriques.
Type QBit
Le client TCP prend en charge la forme
QBit(T, N) à deux arguments, sans paramètre stride. La variante à trois arguments
avec stride n’est pas prise en charge.
Types AggregateFunction
Une colonne
AggregateFunction contient un état intermédiaire propre à la fonction utilisée. Finalisez cet état sur le
serveur, par exemple avec sumMerge(column), puis lisez la valeur obtenue.
Correspondance des types : écriture dans ClickHouse
Chaque entrée indique le type CLR d’une ligne de l’IColumn transmise à InsertAsync. Ces correspondances sont
exactes : le client TCP n’effectue aucune conversion de type à la manière de Convert.
Types entiers
Types à virgule flottante
Lors de l’écriture en
BFloat16, chaque valeur float est tronquée au format « brain floating point » sur 16 bits.
Types décimaux
L’écriture lève une
OverflowException si la mantisse, une fois mise à l’échelle, dépasse la précision déclarée.
Type booléen
Types de chaînes de caractères
FixedString(N) n’accepte pas string volontairement : encodez la valeur et complétez-la explicitement pour que sa
représentation binaire exacte ne prête à aucune ambiguïté.
Types de date et d’heure
Les valeurs entières brutes utilisent les unités indiquées dans le tableau de lecture.
DateTimeOffset conserve l’instant exact.
DateTime tient compte de sa propriété Kind ; une valeur Unspecified est interprétée comme une heure locale dans le
fuseau horaire de la colonne, ou dans celui de la session si la colonne ne précise pas de fuseau horaire.
Types énumérés
Tout libellé inconnu est rejeté avant l’envoi des données.
Autres types scalaires
Types composites
La structure acceptée est récursive :Array(Nullable(DateTime)) accepte donc un DateTime?[] pour chaque
ligne, et Map(String, UInt32) accepte un KeyValuePair<string, uint>[].
Les écritures directes de
Nested utilisent la structure de colonnes dense renvoyée par une lecture précédente. Pour les insertions
réalisées par l’application, conservez la représentation par défaut flatten_nested = 1 et écrivez chaque champ Array(T) dont le nom contient un point
dans une colonne distincte.
Types Variant, Dynamic et JSON
Pour
Variant, le type à l’exécution doit correspondre sans ambiguïté au type CLR par défaut d’une alternative. Les conversions
pratiques, comme l’écriture d’un DateTime dans une alternative DateTime, ne s’appliquent pas au sein d’un variant ;
utilisez plutôt le type brut par défaut de l’alternative. Dynamic prend en charge les valeurs scalaires, ainsi que les
valeurs de type tableau, map et tuple prises en charge de manière récursive.
Types géométriques
Pour une colonne
Geometry créée par une application, seuls Point et MultiPolygon ont des structures CLR distinctes.
Ring et LineString ont la même structure, tout comme Polygon et MultiLineString : le client ne peut donc pas
déterminer quelle variante une valeur object est censée représenter. Une colonne Geometry décodée conserve ses
discriminateurs et peut être insérée à nouveau sans cette ambiguïté.
Type QBit
Types AggregateFunction
Compression
Le client active la compression par défaut et utilise LZ4 pour les blocs qu’il écrit ; ClickHouse utilise aussi LZ4 par défaut pour les blocs de réponse. La compression s’applique aux blocs de résultats et aux blocs envoyés lors d’une insertion, tandis que le texte des requêtes, les informations de progression, les exceptions et les autres paquets du protocole conservent leur encodage binaire habituel. Utilisez la cléCompression de la chaîne de connexion pour choisir le codec utilisé par le client :
IClickHouseCompressor :
Compressor = null pour désactiver la compression. Un compresseur personnalisé doit prendre en charge le tramage des blocs
natifs ; ceux qui ne prennent en charge que les corps des requêtes et réponses HTTP sont rejetés à la création du client.
Choix du codec de réponse
Compressor détermine comment sont compressés les blocs écrits par le client. Le paquet de requête natif demande
au serveur de compresser la réponse, sans toutefois préciser de codec. ClickHouse choisit donc le codec de réponse en fonction
de son paramètre network_compression_method. Le codec par défaut du serveur est LZ4.
Si nécessaire, définissez le codec de réponse pour chaque opération :
Gestion des erreurs
Les erreurs signalées par ClickHouse ou par la connexion native dérivent deClickHouseTcpException,
qui dérive elle-même de DbException :
ClickHouseTcpServerException expose RawCode, le code numérique exact envoyé par le serveur,
ainsi que Code, le ClickHouseErrorCode correspondant si le driver lui attribue un nom. Elle contient également le
nom de l’exception du serveur (Name), ServerStackTrace et les éventuelles exceptions imbriquées du serveur, accessibles via
InnerException.
ClickHouseErrorCode ont Code == ClickHouseErrorCode.Unknown ; consultez
RawCode sans partir du principe que l’énumération couvre toutes les erreurs ClickHouse.
Les erreurs de validation des arguments et de gestion du cycle de vie des objets conservent leurs types d’exception .NET habituels.
Une annulation lève OperationCanceledException. DialTimeout et ReadTimeout lèvent
ClickHouseTcpConnectionException avec une exception interne TimeoutException, et la connexion est écartée.
PoolTimeout lève une simple TimeoutException, qui n’est pas une ClickHouseTcpException : aucune connexion
n’a échoué. Pour résoudre le problème, réduisez le nombre d’opérations simultanées, augmentez la taille du pool ou terminez l’énumération des résultats.
Réessayer les opérations
En cas d’échec de connexion ou de dépassement du délai d’attente pendant une insertion, il est impossible de savoir si elle a abouti : le serveur peut avoir validé les lignes avant que le client ne perde la réponse. Définissez unDeduplicationToken stable pour le lot logique avant de retenter l’insertion :
Journalisation et diagnostics
Le client TCP s’intègre àMicrosoft.Extensions.Logging. La journalisation est facultative : sans
LoggerFactory, le client ne crée aucun logger et ne met en forme aucun message de journal.
ILoggerFactory du conteneur
sauf si les options fournies en spécifient déjà une.
Catégories de journalisation
Configurez les catégories au moyen de la configuration standard de la journalisation .NET :
Debug et contient au maximum StatementMaxLength caractères de
SQL. La valeur par défaut est de cinq caractères. Définissez cette valeur à zéro ou moins pour exclure le texte du statement des logs,
et ne l’augmentez qu’après avoir vérifié que les paramètres et les littéraux ne contiennent pas de données sensibles.
Messages du journal du serveur
L’intégration de journalisation renseigne sur le comportement côté client. Les paquets du journal des requêtes de ClickHouse sont distincts et transmis àClickHouseTcpQueryCallbacks.OnLog. Activez-les à l’aide du
paramètre serveur send_logs_level :
OpenTelemetry
Le client TCP émet des spans de traçage distribué via l’APISystem.Diagnostics.Activity de .NET.
Abonnez un fournisseur de traceurs OpenTelemetry à la source d’activité TCP :
ClickHouse.Driver.Tcp, distinct de celui de la source du client HTTP. Chaque transport peut ainsi être collecté indépendamment. Si aucun listener n’est abonné, les opérations ne génèrent aucune activité.
Spans et attributs
Le client émet des spans pour les opérations SQL, les pings et les nouvelles connexions. Un span SQL porte le nom du premier mot-clé du statement, commeSELECT ou INSERT ; si ce mot-clé n’est pas reconnaissable,
le span est nommé query. Un span connect couvre l’établissement de la connexion socket, la négociation TLS et
le handshake natif. Les spans des statements incluent aussi le temps d’attente d’une connexion disponible dans le pool.
Les compteurs ne sont présents que si le serveur ou le client dispose d’une valeur pertinente à communiquer. Par exemple,
une insertion qui téléverse des blocs indique le nombre de lignes envoyées par le client, mais ne reçoit aucun compteur de lecture du
serveur. Les spans des opérations ayant échoué contiennent aussi un événement
exception avec le type d’exception, le message et la trace
de la pile d’appels.
Texte SQL et données sensibles
Par défaut, le texte SQL n’est pas inclus dans les spans. Activez explicitement sa collecte et définissez une limite adaptée :StatementMaxLength limite la longueur de l’attribut db.query.text et du texte SQL dans les logs de débogage. Une valeur nulle
ou négative supprime ces deux éléments. Vérifiez également les messages d’exception exportés et les traces de pile, car
les erreurs du serveur peuvent contenir des détails sur les requêtes.
Propagation du contexte de trace
LorsqueActivity.Current utilise le format d’identifiant W3C, le client inscrit l’identifiant de trace, l’identifiant de span, les indicateurs de trace
et l’état de la trace dans le paquet de requête natif. ClickHouse peut alors créer des spans côté serveur appartenant à la même
trace distribuée. La collecte et l’échantillonnage des spans côté serveur se configurent toujours dans ClickHouse ; par
exemple, la probabilité d’échantillonnage peut être définie pour chaque requête :
system.query_log et, s’il est configuré, avec system.opentelemetry_span_log de ClickHouse.
Limitations
Le client TCP est encore expérimental et n’offre pas toutes les fonctionnalités du client HTTP.Fonctionnalités disponibles uniquement via HTTP
L’API TCP n’est pas un fournisseur ADO.NET et ne peut pas être utilisée avec des ORM. Elle ne prend pas non plus en charge les entrées et sorties aux formats CSV, JSONEachRow ou Parquet, ni les flux bruts ; l’authentification par jeton porteur ou les en-têtes HTTP personnalisés ; la résolution personnalisée des types de paramètres, le formatage ou la conversion à la lecture ; ni le choix d’une base de données ou d’un rôle pour chaque requête. Utilisez le client HTTP si votre application a besoin de l’une de ces fonctionnalités.Paramètres SQL
Seuls les caractères de substitution{name:Type} natifs de ClickHouse sont pris en charge ; le client TCP ne réécrit pas
ceux de la forme @name utilisés par ADO.NET. Dans les versions 25.8 à 26.6 de ClickHouse, les noms de paramètres qui correspondent à des
paramètres du serveur, comme limit ou offset, peuvent être interprétés comme tels et rejetés. Si vous devez prendre en charge ces versions, renommez-les,
par exemple en row_limit.
Prise en charge des types de données
La section types de données pris en charge détaille toutes les correspondances. Le codec natif présente actuellement les limites suivantes :- Les tuples peuvent contenir au maximum sept éléments.
- Les états intermédiaires de
AggregateFunction(function, ...)ne sont pas pris en charge. Finalisez-les sur le serveur, par exemple avecsumMerge(column), puis lisez le résultat. - Seule la disposition
QBit(T, N)à deux arguments, sans paramètre stride, est prise en charge. JSONutilise la sérialisation String de ClickHouse et nécessiteoutput_format_native_write_json_as_string = 1, que le client demande par défaut.- Les insertions créées par l’application n’ont pas de structure orientée lignes pour
Nested(...)lorsqueflatten_nested = 0. Utilisez plutôt les colonnesArray(T)aplaties par défaut, dont les noms sont séparés par des points. - Pour une colonne
Geometrycréée par l’application, il est impossible de déduire le type géométrique lorsque plusieurs types ont la même structure CLR, commeRingetLineString. Insérez le type géométrique précis ou réinsérez une colonneGeometrydécodée qui conserve ses discriminateurs.
Nouvelles tentatives automatiques
Le client ne réessaie pas automatiquement les opérations qui ont échoué. Ne réessayez que les opérations qui peuvent être répétées sans risque et définissez unDeduplicationToken stable avant de réessayer une insertion dont l’issue est inconnue.
Pour en savoir plus, consultez la section sur les nouvelles tentatives d’opérations.