Connexion
L’exemple suivant, qui renvoie la version du serveur, montre comment se connecter à ClickHouse, en supposant que ClickHouse n’est pas sécurisé et qu’il est accessible avec l’utilisateurdefault.
Notez que nous utilisons le port natif par défaut pour nous connecter.
conn a déjà été créée et est disponible.
Exécution
Il est possible d’exécuter des instructions arbitraires via la méthodeExec. Cela est utile pour les DDL et les instructions simples. Elle ne doit pas être utilisée pour des insertions volumineuses ni pour l’itération de requêtes.
Insertion par lot
Pour insérer un grand nombre de lignes, le client prend en charge les lots. Cela nécessite de préparer un lot auquel des lignes peuvent être ajoutées. Le lot est ensuite envoyé via la méthodeSend(). Les lots sont conservés en mémoire jusqu’à l’exécution de Send.
Il est recommandé d’appeler Close sur le lot afin d’éviter les fuites de connexions. Cela peut se faire à l’aide du mot-clé defer après la préparation du lot. La connexion sera ainsi libérée si Send n’est jamais appelé. Notez que, si aucune ligne n’a été ajoutée, cela fera apparaître une insertion de 0 ligne dans le journal des requêtes.
Colonnes éphémères
Les colonnes éphémères sont des colonnes accessibles uniquement en écriture, qui n’existent que pendant l’insertion : elles ne sont pas stockées et ne peuvent pas être sélectionnées. Elles sont utiles pour calculer, au moment de l’insertion, des valeurs dérivées pour d’autres colonnes.Interroger des lignes
Vous pouvez soit interroger une seule ligne à l’aide de la méthodeQueryRow, soit obtenir un curseur pour parcourir un jeu de résultats via Query. Alors que la première accepte une destination dans laquelle sérialiser les données, la seconde nécessite d’appeler Scan sur chaque ligne.
SELECT — par défaut, dans le cas d’un SELECT *, c’est l’ordre de déclaration des colonnes qui sera utilisé, comme illustré ci-dessus.
Comme pour l’insertion, la méthode Scan exige que les variables cibles soient d’un type approprié. Là encore, l’objectif est de rester flexible, avec conversion des types lorsque c’est possible, à condition qu’il n’y ait aucune perte de précision. Par exemple, l’exemple ci-dessus montre une colonne UUID lue dans une variable string. Pour la liste complète des types Go pris en charge pour chaque type de colonne, consultez conversion de type.
Enfin, notez qu’il est possible de passer un Context aux méthodes Query et QueryRow. Cela peut être utilisé pour définir des paramètres au niveau de la requête — voir Using Context pour plus de détails.
Insertion asynchrone
Les insertions asynchrones sont prises en charge par la méthode Async. Cela permet à l’utilisateur d’indiquer si le client doit attendre que le serveur termine l’insertion ou si celui-ci peut répondre dès réception des données. Cela contrôle en pratique le paramètre wait_for_async_insert.Insertion en colonnes
Les insertions peuvent être effectuées au format en colonnes. Cela peut offrir des gains de performance si les données sont déjà organisées de cette façon, en évitant d’avoir à les convertir en lignes.Utilisation des structs
Pour les utilisateurs, les structs Golang offrent une représentation logique d’une ligne de données dans ClickHouse. Pour cela, l’interface native propose plusieurs fonctions pratiques.Select avec sérialisation
La méthode Select permet, en un seul appel, de sérialiser un ensemble de lignes de réponse dans une slice de structs.Lecture d’une struct
ScanStruct permet de mapper une seule ligne d’une requête vers une struct.
Ajout d’une struct
AppendStruct permet d’ajouter une struct à un lot existant et de l’interpréter comme une ligne complète. Pour cela, les colonnes de la struct doivent correspondre à celles de la table, tant par leur nom que par leur type. Toutes les colonnes doivent avoir un champ de struct équivalent, mais certains champs de struct peuvent ne pas avoir de colonne correspondante dans la table. Ils seront alors simplement ignorés.
Paramètres de requête côté serveur
Les paramètres de requête côté serveur de ClickHouse utilisent des caractères de substitution typés de la forme{name:Type}. La requête et les valeurs des paramètres étant envoyées séparément, les valeurs des paramètres ne sont pas interpolées dans le texte SQL.
Avec l’API ClickHouse, transmettez les paramètres via le contexte de la requête :
clickhouse.Named :
clickhouse.Named fonctionne également avec la syntaxe de liaison @name côté client : c’est le caractère de substitution utilisé dans la requête ({name:Type} ou @name) qui détermine le mécanisme employé.
Valeurs de type string et séquences d’échappement
L’interprétation d’une valeur de type string dépend de la manière dont vous la fournissez.clickhouse.Named (ou sql.Named) avec une valeur string/*string ou []byte/*[]byte utilise la valeur Go telle quelle comme valeur littérale du paramètre. Le driver échappe automatiquement les caractères de contrôle, de sorte que la valeur est restituée à l’identique, octet par octet, avec les deux protocoles. La présence d’un véritable saut de ligne ou d’une tabulation dans la valeur ne pose donc aucun problème :
clickhouse.Parameters / WithParameters contient toujours un texte de paramètre déjà sérialisé au format Escaped de ClickHouse. Ce texte n’est pas échappé automatiquement. Lors de l’analyse du paramètre, ClickHouse décode les séquences d’échappement introduites par un antislash : \n (saut de ligne), \t (tabulation), \r (retour chariot), \0 (octet nul) et \\ (antislash littéral). \N est le marqueur NULL portant sur la valeur entière pour les types nullable.
Go traite les littéraux de string interprétés ("...") avant que clickhouse-go ne les reçoive, tandis que les littéraux de string bruts (`...`) conservent les antislashs. Pour Parameters, rédigez le texte du paramètre comme suit :
N’utilisez pas
"line 1\nline 2" ni "column 1\tcolumn 2" pour construire Parameters : ces littéraux Go contiennent déjà un véritable saut de ligne ou une véritable tabulation. Or, dans le format Escaped de ClickHouse, les octets de saut de ligne et de tabulation servent de délimiteurs de champs ; le serveur rejette donc le paramètre, faute d’avoir pu l’analyser entièrement. Utilisez plutôt Named si vous souhaitez qu’une string Go soit traitée comme une valeur littérale.
Les valeurs de paramètre ne sont pas des littéraux SQL : pour un String de premier niveau passé via Named, transmettez la valeur sans guillemets SQL — utilisez hello, et non 'hello', sinon les guillemets feraient partie de la valeur. Les types composites conservent leur syntaxe textuelle, par exemple ['a', 'b'] pour un Array(String), que vous pouvez également transmettre via Named tant que le texte ne contient ni séquences d’échappement avec antislash ni caractères de contrôle bruts. Si le texte composite nécessite des séquences d’échappement \' pour des valeurs de string imbriquées, transmettez-le plutôt via Parameters.
Exemple complet avec l’API native
Liaison des paramètres
Le client prend en charge la liaison des paramètres pour les méthodesExec, Query et QueryRow. Comme le montre l’exemple ci-dessous, elle est compatible avec les paramètres nommés, numérotés et positionnels. Vous trouverez des exemples ci-dessous.
Cas particuliers
Par défaut, les slices sont développés en une liste de valeurs séparées par des virgules lorsqu’ils sont passés comme paramètre à une requête. Si vous devez injecter un ensemble de valeurs entre crochets[ ], utilisez ArraySet.
Si vous avez besoin de groupes/tuples, entourés de ( ), par exemple pour les utiliser avec des opérateurs IN, vous pouvez utiliser un GroupSet. Cela est particulièrement utile lorsque plusieurs groupes sont nécessaires, comme dans l’exemple ci-dessous.
Enfin, les champs DateTime64 nécessitent une précision afin de garantir que les paramètres sont correctement rendus. Cependant, le niveau de précision du champ est inconnu du client ; l’utilisateur doit donc le fournir. Pour simplifier cela, nous fournissons le paramètre DateNamed.
Utilisation du contexte
Les contextes Go permettent de transmettre des échéances, des signaux d’annulation et d’autres valeurs limitées à la portée d’une requête à travers les limites de l’API. Toutes les méthodes d’une connexion acceptent un contexte comme premier argument. Alors que les exemples précédents utilisaientcontext.Background(), vous pouvez exploiter cette fonctionnalité pour transmettre des paramètres et des échéances, ainsi que pour annuler des requêtes.
Le passage d’un contexte créé avec withDeadline permet d’imposer des limites de temps d’exécution aux requêtes. Notez qu’il s’agit d’un instant absolu et que l’expiration ne fera que libérer la connexion et envoyer un signal d’annulation à ClickHouse. WithCancel peut également être utilisé pour annuler explicitement une requête.
Les fonctions utilitaires clickhouse.WithQueryID et clickhouse.WithQuotaKey permettent de spécifier un identifiant de requête et une clé de quota. Les identifiants de requête peuvent être utiles pour suivre les requêtes dans les logs et à des fins d’annulation. Une clé de quota peut être utilisée pour imposer des limites d’utilisation de ClickHouse en fonction d’une valeur de clé unique — voir Gestion des quotas pour plus de détails.
Vous pouvez également utiliser le contexte pour vous assurer qu’un paramètre n’est appliqué qu’à une requête spécifique, plutôt qu’à l’ensemble de la connexion, comme indiqué dans Paramètres de connexion.
Enfin, vous pouvez contrôler la taille du tampon de blocs via clickhouse.WithBlockSize. Cela remplace le paramètre au niveau de la connexion BlockBufferSize et contrôle le nombre maximal de blocs décodés et conservés en mémoire à tout moment. Des valeurs plus élevées peuvent offrir davantage de parallélisation, au prix d’une consommation mémoire plus importante.
Des exemples de ce qui précède sont présentés ci-dessous.
Informations Progress, profile et log
Il est possible de demander des informations Progress, Profile et Log pour les requêtes. Les informations Progress indiquent des statistiques sur le nombre de lignes et d’octets lus et traités dans ClickHouse. À l’inverse, les informations Profile fournissent un résumé des données renvoyées au client, y compris les totaux d’octets (non compressés), de lignes et de blocs. Enfin, les informations Log fournissent des statistiques sur les threads, par exemple l’utilisation de la mémoire et le débit des données. Pour obtenir ces informations, l’utilisateur doit utiliser Context, auquel il peut transmettre des fonctions de rappel.Analyse dynamique
Il peut être nécessaire de lire des tables dont on ne connaît ni le schéma ni le type des champs renvoyés. C’est fréquent lorsqu’une analyse ad hoc des données est effectuée ou qu’un outillage générique est développé. Pour ce faire, les informations de type des colonnes sont disponibles dans les réponses aux requêtes. Elles peuvent être utilisées avec la réflexion en Go pour créer, à l’exécution, des instances de variables du type approprié, qui peuvent ensuite être passées à Scan.Tables externes
Les tables externes permettent au client d’envoyer des données à ClickHouse avec une requête SELECT. Ces données sont placées dans une table temporaire et peuvent être utilisées directement dans la requête lors de son exécution. Pour envoyer des données externes avec une requête, l’utilisateur doit créer une table externe viaext.NewTable avant de la transmettre via le contexte.
OpenTelemetry
ClickHouse prend en charge la propagation du trace context sur les transports TCP et HTTP. Lors de l’utilisation de TCP, le client sérialise le span dans le protocole binaire natif. Utilisezclickhouse.WithSpan pour associer un span à une requête via le contexte.
Limitation du transport HTTPBien que le serveur ClickHouse accepte les en-têtes HTTP standard
traceparent / tracestate, le transport HTTP de clickhouse-go ne les envoie pas actuellement — WithSpan n’a donc aucun effet en HTTP. Pour contourner ce problème, vous pouvez définir manuellement l’en-tête via HttpHeaders dans les options de connexion.