> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> Записи, вставленные в таблицу `QueryRunner`, представляют собой запросы, которые движок выполняет либо локально, либо на удаленном кластере в режиме «fire and forget».

# Движок таблицы QueryRunner

Записи, вставленные в таблицу `QueryRunner`, представляют собой запросы, которые выполняет движок.
Движок можно использовать для асинхронного выполнения запросов, батчевого выполнения сгенерированных запросов,
отправки запросов в удаленные кластеры, запуска бенчмарков, фаззинга и тестирования с теневым трафиком.

<div id="creating-a-table">
  ## Создание таблицы
</div>

```sql theme={null}
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 }];
```

Таблица должна быть создана с подмножеством допустимых столбцов: `query`, `database`, `settings`.
Столбец `query` обязателен, остальные столбцы — необязательны.

| Столбец    | Type                  | Значение                                                                                                   |
| ---------- | --------------------- | ---------------------------------------------------------------------------------------------------------- |
| `query`    | `String`              | Запрос, который нужно выполнить.                                                                           |
| `database` | `String`              | База данных по умолчанию для запроса. Если значение пустое, используется база данных сервера по умолчанию. |
| `settings` | `Map(String, String)` | Настройки, применяемые к запросу.                                                                          |

<div id="engine-settings">
  ## Настройки движка
</div>

| Setting          | Default          | Meaning                                                                                                                                                                                                                               |
| ---------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cluster`        | `''`             | Имя кластера, в который отправляются запросы. Если значение пустое, запросы выполняются локально.                                                                                                                                     |
| `shard`          | `'1'`            | Индекс сегмента кластера, начиная с 1, в который отправляются запросы, или `'random'` для выбора случайного сегмента для каждого запроса, или `'all'`, чтобы выполнять каждый запрос на каждом сегменте. Требует настройки `cluster`. |
| `mode`           | `'asynchronous'` | В режиме `synchronous` INSERT возвращает управление после завершения всех запросов из вставленного батча. В режиме `asynchronous` INSERT возвращает управление, как только запросы поставлены в очередь.                              |
| `threads`        | `4`              | Количество фоновых потоков, выполняющих запросы.                                                                                                                                                                                      |
| `max_queue_size` | `1000`           | Максимальное количество запросов в очереди. Когда очередь заполнена, новые запросы отбрасываются, а ошибка записывается в журнал.                                                                                                     |

<div id="details">
  ## Подробности
</div>

Таблица допускает только запросы `INSERT`.
Запросы выполняются в режиме "fire and forget": в случае исключения повторных попыток не выполняется,
а результаты запросов `SELECT` отбрасываются (единственный способ сохранить результаты — `INSERT SELECT`).
Успешность каждого запроса можно проверить в таблице `system.query_log`, где запросы, инициированные
этим движком, помечаются как `is_internal = 1` на инициирующем сервере.

Поставленные в очередь запросы хранятся в памяти и не сохраняются после перезапуска сервера. При остановке сервера
(или `DROP`/`DETACH` таблицы) запросы, которые еще не начали выполняться, отбрасываются. Из
запросов, которые уже выполняются, отправленные в кластер отменяются, а выполняющиеся
локально продолжают выполняться до завершения.

Если выполняемый запрос сам является `INSERT`, его данные должны быть указаны прямо в нем — `INSERT ... VALUES (...)`,
`INSERT ... SELECT ...` или `INSERT ... FORMAT ...` с данными в тексте запроса. `INSERT`, который
ожидает данные из отдельного потока, не поддерживается.

<div id="local-mode-and-sql-security">
  ## Локальный режим и безопасность SQL
</div>

Без настройки `cluster` запросы выполняются на локальном сервере.
Пользователь, от имени которого они выполняются, определяется конструкцией `безопасность SQL`:

* `INVOKER` (по умолчанию): запросы выполняются от имени пользователя, который выполнил INSERT.
* `DEFINER`: запросы выполняются от имени указанного пользователя `DEFINER`. Поскольку такие запросы могут быть произвольными, предоставление `INSERT` на такую таблицу делегирует все привилегии пользователя `DEFINER`.
* `NONE`: запросы выполняются с полным доступом, без пользователя. При создании таблицы требуется grant `ALLOW_SQL_SECURITY_NONE`.

<div id="cluster-mode">
  ## Режим кластера
</div>

Когда указана настройка `cluster`, запросы отправляются в указанный кластер.

Целевой сегмент выбирается с помощью `shard`: это может быть фиксированный индекс с нумерацией с 1 (по умолчанию `'1'`), `'random'` для выбора
случайного сегмента для каждого запроса или `'all'` для выполнения каждого запроса на каждом сегменте кластера. Реплика внутри
сегмента выбирается в соответствии с настройкой `load_balancing` сервера.

Столбец `database` задаёт базу данных по умолчанию для соединения с удалённым сервером. Поскольку
база данных по умолчанию задаётся один раз для каждого соединения, каждое отдельное значение `database` использует собственный
пул соединений, который создаётся при первом использовании и затем повторно используется в течение всего времени жизни таблицы.

`DEFINER` и `безопасность SQL` действуют только в локальном режиме, а их сочетание с
настройкой `cluster` приводит к ошибке. На удалённых серверах запросы проходят аутентификацию с использованием
учётных данных из конфигурации кластера и выполняются как обычные исходные запросы: они записываются в
`system.query_log` с `is_initial_query = 1` и собственным `query_id` (не связанным с INSERT, который
их создал). На инициирующем сервере отправленные запросы записываются в `system.query_log`
с `is_internal = 1`.

Поскольку движок отбрасывает результаты запросов, он всегда выполняет отправленные запросы с
`discard_query_data = 1`, поэтому данные результата SELECT-запросов не передаются по сети
(это переопределяет любое значение `discard_query_data`, заданное в столбце `settings`).

<div id="waiting-for-queries-to-finish">
  ## Ожидание завершения запросов
</div>

В асинхронном режиме можно использовать следующий запрос, чтобы блокировать выполнение до тех пор, пока не завершатся все запросы, к этому моменту отправленные в таблицу:

```sql theme={null}
SYSTEM WAIT QUERY RUNNER runner;
```

<div id="example">
  ## Пример
</div>

Повторное выполнение последних запросов `SELECT` из журнала запросов:

```sql theme={null}
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;
```
