SELECT et INSERT sur une table Google BigQuery, y compris sur des jeux de données publics. La structure de la table est automatiquement déduite du schéma de la table BigQuery.
La lecture utilise l’API REST de BigQuery (tabledata.list) ; seules les tables natives peuvent donc être lues (les vues, les vues matérialisées et les tables externes ne sont pas prises en charge). L’écriture utilise les insertions en streaming (tabledata.insertAll), ce qui nécessite l’activation de la facturation pour le projet.
Syntaxe
Arguments
Les arguments
project, dataset, table et access_token peuvent également être fournis sous la forme key = value ; les arguments positionnels remplissent ces emplacements dans cet ordre. Indiquer un argument à la fois de manière positionnelle et sous forme de clé (ou indiquer deux fois la même clé) constitue une erreur.
Les arguments suivants peuvent être spécifiés sous la forme key = value (ou comme clés d’une collection nommée) :
Authentification
- Jeton d’accès. Tout jeton d’accès OAuth 2.0 valide, par exemple obtenu avec
gcloud auth print-access-token. Les jetons expirent rapidement (généralement au bout d’une heure) ; cette méthode est donc mieux adaptée à une utilisation interactive. - Clé de compte de service (recommandée pour les serveurs). Transmettez le contenu d’un fichier de clé créé dans Google Cloud IAM à l’aide de l’argument
service_account_key. ClickHouse signe un JWT avec la clé et l’échange contre un jeton d’accès, qu’il renouvelle automatiquement. - Jeton d’actualisation. Transmettez
client_id,client_secretetrefresh_token, par exemple à partir de~/.config/gcloud/application_default_credentials.jsonaprès avoir exécutégcloud auth application-default login.
BigQuery ou CREATE TABLE ... AS bigquery(...)) est enregistrée comme dépendance de la collection ; DROP NAMED COLLECTION est donc bloqué tant que la table existe.
Correspondance des types de données
Remarques :
- Le
DATETIMEde BigQuery n’a pas de fuseau horaire ; il est mappé surDateTime64(6, 'UTC')afin que la valeur affichée ne dépende pas du fuseau horaire du serveur. - Un
RECORDNULLABLEest mappé surNullable(Tuple(...)), afin qu’unNULLpour l’ensemble de l’enregistrement soit conservé commeNULLau lieu d’être réduit à unTuplede valeurs par défaut. Un tableauNULL(ou vide) devient un tableau vide, carArrayne peut pas être contenu dansNullabledans ClickHouse. Un tableau BigQuery ne peut pas contenir d’élémentsNULL(ARRAY<T>équivaut àARRAY<T NOT NULL>), donc le type d’élément d’un champREPEATEDn’est pasNullable(Array(T), ouArray(Tuple(...))pour un élémentRECORD) ; un élémentNULLdans une réponsetabledata.listest rejeté comme entrée malformée. - La lecture et l’écriture de colonnes
Nullable(Tuple(...))via la fonction de tablebigqueryfonctionnent sans paramètre supplémentaire. La création d’une table persistante utilisant le moteurBigQueryqui contient une telle colonne (que la structure soit inférée ou déclarée explicitement) nécessite le paramètreenable_nullable_tuple_type, comme pour toute colonneNullable(Tuple). Lors de la déclaration explicite des colonnes, un champRECORDpeut également être déclaré comme un simpleTuple(...)pour éviter ce paramètre, au prix de la conversion d’unNULLpour l’ensemble de l’enregistrement en tuple par défaut ; la seule différence acceptée par rapport au type inféré consiste à supprimer unNullablequi enveloppe leTupled’unRECORD, et uniquement pour ce même enregistrement — la nullabilité ne peut pas être déplacée vers un autre enregistrement, interne ou externe. GEOGRAPHYest mappé sur Geometry. BigQuery transfère une valeurGEOGRAPHYsous forme de texte WKT, qui est analysé à la lecture en l’alternative correspondante deGeometry(unVariantdePoint,MultiPoint,Ring,LineString,MultiLineString,PolygonetMultiPolygon), puis sérialisé à nouveau en WKT à l’écriture. UnGEOMETRYCOLLECTIONet une géométrie vide (telle quePOINT EMPTY) n’ont pas d’équivalent dansGeometry; la lecture d’une ligne contenant une telle valeur génère donc une erreur. CommeVariantpeut contenirNULLdirectement, un champGEOGRAPHYNULLABLEest mappé surGeometryet non surNullable(Geometry), etNULLest toujours préservé lors de l’aller-retour.JSONest mappé surStringplutôt que sur le type de données JSON, car le typeJSONde ClickHouse n’accepte qu’un objet ({...}) au niveau supérieur, alors qu’une valeurJSONBigQuery peut être n’importe quelle valeur JSON — un scalaire, un tableau ounull— et qu’une table contenant de telles valeurs ne pourrait donc pas être lue. De plus,JSONne peut pas être enveloppé dansNullable, de sorte qu’unNULLSQL dans une colonneNULLABLEne serait pas préservé. Le mappage versStringest sans perte ; les objets de niveau supérieur peuvent être convertis avecCAST(value AS JSON).- Les valeurs
BIGNUMERICdont la partie entière comporte plus de 38 chiffres ne tiennent pas dansDecimal(76, 38)et génèrent une erreur. - Les valeurs
TIMESTAMPetDATEhors de la plage prise en charge parDateTime64/Date32(années 1900 à 2299) ne sont pas prises en charge. - Les colonnes
RANGEsont en lecture seule.tabledata.insertAllattend une valeurRANGE<T>sous la forme d’un objet structuré{start, end}, qui ne peut pas être reconstruit à partir du mappage versString; l’insertion dans une colonneRANGEgénère donc une erreur. - Les valeurs
INT64sont envoyées àtabledata.insertAllsous forme de chaînes décimales, car l’API analyse les nombres JSON comme des nombres à virgule flottante double précision et corromprait sinon les valeurs hors de[-2^53 + 1, 2^53 - 1].
Exemples
gcloud :
Limitations
- Seules les tables BigQuery natives peuvent être lues. Les vues et les tables externes nécessitent l’exécution d’une tâche de requête BigQuery, ce que cette fonction ne fait pas.
- Les colonnes
RANGEpeuvent être lues (en tant queString), mais pas écrites : l’insertion dans une colonneRANGEgénère une erreur. - Une valeur
GEOGRAPHYcorrespondant à uneGEOMETRYCOLLECTIONou à une géométrie vide ne peut pas être représentée par le typeGeometry; la lecture d’une ligne qui en contient une génère donc une erreur. L’écriture d’unGeometryNULLdans un champGEOGRAPHYREQUIRED, ou comme élément d’un champGEOGRAPHYREPEATED, est rejetée, car BigQuery n’y accepte pas deNULL. - Les prédicats ne sont pas poussés vers la source :
tabledata.listne renvoie que les lignes d’une table et ne dispose d’aucun paramètre de filtrage (il accepte des options de pagination, de sélection de colonnes et de format). Or, le filtrage nécessiterait l’exécution d’une tâche de requête BigQuery, ce que cette fonction ne fait pas. Une conditionWHEREest donc appliquée dans ClickHouse après le téléchargement des lignes ; utilisez la sélection de colonnes pour réduire le volume de données transférées. - Un
LIMIT, en revanche, réduit bien la quantité de données lues. Les pages sont demandées à la demande, avecmaxResultsdéfini surmax_block_size, et aucune page supplémentaire n’est demandée dès que la requête dispose d’un nombre suffisant de lignes. Pour un simpleLIMIT n(sansWHERE,GROUP BYniORDER BY, et avecninférieur àmax_block_size), ClickHouse réduitmax_block_sizeàn, de sorte qu’une seule requête portant exactement surnlignes est effectuée ; sinon, la lecture s’arrête à la première limite de page au-delà de la limite, avec un dépassement inférieur à une page. - La lecture est liée au schéma observé lors de l’analyse de la requête en transmettant la liste explicite des colonnes à
tabledata.list. Pour une lecture très large dont la liste de colonnes dépasserait la limite de longueur de l’URL de requête (par exemple,SELECT *sur une table comptant des milliers de colonnes), la requête est rejetée plutôt que d’être effectuée sans cette liaison au schéma (une lecture non liée pourrait être désalignée par une modification concurrente du schéma) ; sélectionnez moins de colonnes afin que la liste tienne. Cette même limite de longueur d’URL est vérifiée avant chaque requête paginée (chaque page comporte unpageTokenopaque) ; ainsi, une lecture dont les pages ultérieures dépasseraient la limite est rejetée avec la même erreur au lieu d’échouer en cours de route. - Si la table BigQuery est modifiée après la lecture de son schéma, la requête est rejetée plutôt que de renvoyer ou d’écrire silencieusement des données non concordantes : le schéma actuel est récupéré à nouveau et comparé à celui analysé juste avant une lecture, puis de nouveau avant qu’un
INSERTne transmette sa première ligne. La fenêtre restante (une modification du schéma entre cette vérification et les requêtes qui la suivent) ne peut pas être éliminée, car le schéma et les données sont récupérés par des requêtes REST distinctes. - La comparaison s’effectue avec l’instantané du schéma utilisé lors de l’analyse de la requête. Cet instantané est pris lorsque la fonction de table résout sa structure ou, pour une table persistante (une table utilisant le moteur
BigQuery, ou une table créée avecCREATE TABLE ... AS bigquery(...), qui conserve ses colonnes de la même manière), lors de sa première lecture ou écriture aprèsCREATE,ATTACHou un redémarrage du serveur. Les métadonnées de la table conservent les colonnes ClickHouse mappées, et non le schéma BigQuery. Une modification du schéma effectuée pendant que la table était détachée (ou que le serveur était arrêté) est donc prise en compte par la requête suivante au lieu d’être rejetée : les colonnes déclarées sont toujours validées par rapport au schéma actuel, et les lignes sont décodées en fonction de celui-ci. Ainsi, une modification qui conserve les types ClickHouse mappés (STRINGversBYTES, par exemple) est lue selon les règles du nouveau type, avec le même type de colonne. - Les lignes écrites via des insertions en streaming arrivent dans le buffer de streaming BigQuery et peuvent mettre un certain temps à devenir visibles lors des lectures ultérieures.
- Un grand
INSERTest envoyé àtabledata.insertAllpar lots : au plus 500 lignes par requête, avec un découpage supplémentaire afin que chaque requête reste sous la limite de taille de 10 Mo imposée par BigQuery (une ligne unique dépassant cette limite est rejetée avec une erreur explicite). - Les écritures ne sont pas atomiques et une même requête
tabledata.insertAllpeut réussir partiellement : BigQuery peut valider certaines lignes d’une requête tout en rejetant les autres avecinsertErrors. Les requêtes sont également validées indépendamment les unes des autres ; un lot ultérieur peut donc être rejeté après acceptation de lots précédents. Dans les deux cas, la requête renvoie une erreur, mais les lignes déjà validées restent dans BigQuery. Afin de limiter les doublons, chaque ligne est envoyée avec uninsertIdstable dérivé de l’ID de requête et de la position ordinale de la ligne dans le flux. BigQuery l’utilise pour effectuer une déduplication au mieux pendant sa fenêtre d’insertion en flux. Unquery_iddépassant la limite de 128 caractères de l’insertIdBigQuery est haché en un préfixe de longueur fixe, qui reste stable pour cequery_id. Comme l’insertIddépend de la position ordinale, la déduplication n’est fiable que si la réexécution produit les lignes dans le même ordre : une nouvelle tentative d’un lot au niveau du transport est toujours sûre, et la réexécution du mêmeINSERTavec le mêmequery_idne permet la déduplication que si les lignes sont présentées dans le même ordre (par exemple, avec une insertion monothread ou un ordre déterministe — définissezmax_threads = 1etmax_insert_threads = 1pour unINSERT ... SELECTparallèle dont l’ordre des fragments pourrait autrement varier d’une tentative à l’autre).