Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

Moteur de table QueryRunner

Les enregistrements insérés dans une table QueryRunner correspondent à des requêtes que le moteur exécute. Le moteur peut être utilisé pour 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, les tests de performance, le fuzzing et les tests sur trafic miroir.

Créer une table

CREATE TABLE runner
(
    query String,
    database String,
    settings Map(LowCardinality(String), String)
)
ENGINE = QueryRunner
SETTINGS
    cluster = 'cluster_name',
    shard = '1',
    mode = 'asynchronous',
    threads = 4,
    max_queue_size = 1000
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | INVOKER | NONE }];

La table doit être créée avec un sous-ensemble des colonnes autorisées : query, database, settings. La colonne query est obligatoire, les autres colonnes étant facultatives.

Colonne Type Signification
query String La requête à exécuter.
database String La base de données par défaut de la requête. Si elle est vide, la base de données par défaut du serveur est utilisée.
settings Map(String, String) Les paramètres appliqués à la requête.

Paramètres du moteur

Paramètre Défaut Signification
cluster '' Nom du cluster auquel envoyer les requêtes. S'il est vide, les requêtes sont exécutées localement.
shard '1' Indice, indexé à partir de 1, du shard du cluster auquel envoyer les requêtes, ou 'random' pour sélectionner un shard aléatoire pour chaque requête, ou 'all' pour exécuter chaque requête sur tous les shards. Nécessite le paramètre cluster.
mode 'asynchronous' En mode synchronous, INSERT renvoie une fois que toutes les requêtes du lot inséré sont terminées. En mode asynchronous, INSERT renvoie dès que les requêtes sont placées en file d'attente.
threads 4 Nombre de threads en arrière-plan qui exécutent les requêtes.
max_queue_size 1000 Nombre maximal de requêtes en file d'attente. Lorsque la file d'attente est pleine, les nouvelles requêtes insérées sont ignorées et une erreur est consignée.

Détails

La table autorise uniquement les requêtes INSERT. Les requêtes sont exécutées en mode « fire and forget » : en cas d'exception, aucune nouvelle tentative n'est effectuée, et les résultats des requêtes SELECT sont ignorés (la seule façon de conserver les résultats est INSERT SELECT). Le succès de chaque requête peut être vérifié dans la table system.query_log, où les requêtes initiées par ce moteur sont marquées avec is_internal = 1 sur le serveur initiateur.

Les requêtes en file d'attente sont conservées en mémoire et ne survivent pas à un redémarrage du serveur. Lors de l'arrêt du serveur (ou d'un DROP/DETACH de la table), les requêtes qui n'ont pas encore démarré sont ignorées. Parmi les requêtes déjà en cours d'exécution, celles envoyées à un cluster sont annulées, tandis que celles exécutées localement sont attendues jusqu'à la fin de leur exécution.

Lorsqu'une requête à exécuter est elle-même un INSERT, ses données doivent être intégrées — INSERT ... VALUES (...), INSERT ... SELECT ..., ou INSERT ... FORMAT ... avec les données dans le texte de la requête. Un INSERT qui attend ses données d'un flux distinct n'est pas pris en charge.

Mode local et SQL SECURITY

Sans le paramètre cluster, les requêtes sont exécutées sur le serveur local. L'utilisateur sous l'identité duquel elles s'exécutent est déterminé par la clause SQL SECURITY :

  • INVOKER (par défaut) : les requêtes s'exécutent au nom de l'utilisateur qui a effectué l'INSERT.
  • DEFINER : les requêtes s'exécutent au nom de l'utilisateur DEFINER spécifié. Comme les requêtes insérées peuvent être arbitraires, accorder INSERT sur une telle table délègue tous les privilèges de cet utilisateur.
  • NONE : les requêtes s'exécutent avec un accès complet, sans utilisateur. Nécessite le privilège ALLOW_SQL_SECURITY_NONE lors de la création de la table.

Mode cluster

Lorsque le paramètre cluster est spécifié, les requêtes sont envoyées au cluster indiqué.

Le shard cible est sélectionné par shard : un index fixe indexé à partir de 1 ('1' par défaut), 'random' pour choisir un shard aléatoire pour chaque requête, ou 'all' pour exécuter chaque requête sur tous les shards du cluster. Une réplique au sein du shard est choisie selon le paramètre load_balancing du serveur.

La colonne database définit la base de données par défaut de la connexion au serveur distant. Comme la base de données par défaut n'est définie qu'une seule fois par connexion, chaque valeur distincte de database utilise son propre pool de connexions, qui est créé lors de la première utilisation puis réutilisé pendant toute la durée de vie de la table.

DEFINER et SQL SECURITY n'ont d'effet qu'en mode local, et les combiner avec le paramètre cluster constitue une erreur. Sur les serveurs distants, les requêtes sont authentifiées à l'aide des informations d'identification de la configuration du cluster et s'exécutent comme des requêtes initiales ordinaires : elles sont consignées dans system.query_log avec is_initial_query = 1 et leur propre query_id (sans lien avec l'INSERT qui les a produites). Sur le serveur initiateur, les requêtes envoyées sont consignées dans system.query_log avec is_internal = 1.

Comme le moteur ignore le résultat de la requête, il exécute toujours les requêtes envoyées avec discard_query_data = 1, de sorte que les données de résultat des requêtes SELECT ne sont pas transférées sur le réseau (cela remplace toute valeur discard_query_data définie dans la colonne settings).

Attendre la fin des requêtes

En mode asynchrone, vous pouvez utiliser la requête suivante pour bloquer jusqu’à ce que toutes les requêtes soumises à la table jusqu’à présent soient terminées :

SYSTEM WAIT QUERY RUNNER runner;

Exemple

Réexécuter des requêtes SELECT récentes à partir du journal des requêtes :

INSERT INTO runner (query, database, settings)
SELECT query, current_database, Settings
FROM system.query_log
WHERE type = 'QueryFinish' AND is_initial_query AND NOT is_internal AND query_kind = 'Select'
  AND event_time > now() - INTERVAL 1 HOUR;
Navigation