Принудительное завершение запроса
Для принудительной остановки выполнения запросов и прерывания мутаций ADQM/ClickHouse предоставляет команды KILL QUERY и KILL MUTATION.
KILL QUERY
Хотя ADQM/ClickHouse является высокопроизводительной СУБД, плохо оптимизированные запросы (например, полное сканирование больших наборов данных, применение неэффективных индексов или неоптимизированные операции JOIN) могут выполняться достаточно долго, потреблять много ресурсов и блокировать критически важные процессы. В таких случаях может возникнуть необходимость остановить выполнение запроса — используйте для этого команду KILL QUERY.
|
РЕКОМЕНДАЦИЯ
Возможные способы ускорения выполнения запросов можно посмотреть в статье Повышение производительности запросов.
|
Базовый синтаксис запроса KILL QUERY:
KILL QUERY [ON CLUSTER <cluster_name>] WHERE <where_expr> [ASYNC|SYNC|TEST] [FORMAT <output_format>];
где:
-
[ON CLUSTER <cluster_name>]— необязательное выражение, которое используется, чтобы указать имя кластера, когда нужно выполнить прерывание запроса на всех узлах кластера. -
WHERE <where_expr>— обязательное выражение, определяющее критерии отбора запросов, которые необходимо завершить.Выявить выполняющиеся слишком долго и/или потребляющие много памяти запросы можно с помощью системной таблицы system.processes, которая содержит информацию о выполняющихся в настоящее время запросах и их состояниях. Например, вы можете использовать поля
query_id,user,elapsed,memory_usageи другие релевантные поля этой таблицы для идентификации запроса, выполнение которого необходимо остановить:SELECT query_id, user, elapsed, memory_usage FROM system.processes ORDER BY elapsed DESC;В качестве альтернативы
SELECT * FROM system.processesможно использовать команду:SHOW PROCESSLIST; -
[ASYNC|SYNC|TEST]— ключевое слово, указывающее должна ли командаKILL QUERYвыполняться асинхронно, синхронно или в тестовом режиме:-
ASYNC(по умолчанию) — команда не ждет подтверждения о том, что выполнение указанных запросов остановлено. -
SYNC— команда ожидает завершения всех указанных запросов и отображает информацию о каждом процессе по мере его завершения. -
TEST— тестовый запуск командыKILL QUERY, который позволяет проверить права пользователя и посмотреть, какие запросы будут остановлены командой, без их фактического завершения.
-
-
[FORMAT <output_format>]— необязательное выражение, указывающее формат вывода результата операции завершения запроса.
Результат выполнения команды KILL QUERY содержит столбец kill_status, возможные значения которого включают:
-
finished— выполнение запроса было успешно остановлено; -
waiting— ожидание завершения запроса после отправки ему сигнала на завершение; -
cant_cancel— сигнал на завершение не может быть отправлен; -
pending— запрос еще не инициализирован; -
unknown_status— статус операции прерывания запроса неизвестен.
Чтобы пользователь мог прерывать выполнение запросов других пользователей, у него должна быть привилегия KILL QUERY. Пользователи с правами только на чтение могут прерывать исключительно свои запросы.
Пример
|
ПРИМЕЧАНИЕ
В данном примере используются два пользовательских аккаунта ADQM:
|
-
В двух отдельных сессиях clickhouse-client от имени пользователя default запустите запрос для тестирования, который будет выполняться бесконечно, например:
SELECT count() FROM system.numbers;Во время выполнения запроса в клиенте будет показан идентификатор запроса и прогресс выполнения.
-
Сессия 1:
SELECT count() FROM system.numbers Query id: 6d522fb4-97db-45e4-9565-3158edb5a281 ↖ Progress: 398.17 billion rows, 3.19 TB (3.40 billion rows/s., 27.22 GB/s.) (1.0 CPU) Press the space key to toggle the display of the progress table.
-
Сессия 2:
SELECT count() FROM system.numbers Query id: f38506fd-4923-4bd2-8668-e6affdaa61c4 ↖ Progress: 403.64 billion rows, 3.23 TB (3.41 billion rows/s., 27.24 GB/s.) (1.0 CPU) Press the space key to toggle the display of the progress table.
-
-
Откройте еще одну сессию клиента
clickhouse-clientот имени пользователяadqm_user. Посмотрите список незавершенных запросов, запущенных пользователемdefault, и длительность их выполнения на текущий момент:SELECT query_id, user, elapsed, query FROM system.processes WHERE user='default' ORDER BY elapsed DESC;┌─query_id─────────────────────────────┬─user────┬────elapsed─┬─query───────────────────────────────┐ 1. │ 6d522fb4-97db-45e4-9565-3158edb5a281 │ default │ 133.361736 │ SELECT count() FROM system.numbers; │ 2. │ f38506fd-4923-4bd2-8668-e6affdaa61c4 │ default │ 125.132542 │ SELECT count() FROM system.numbers; │ └──────────────────────────────────────┴─────────┴────────────┴─────────────────────────────────────┘
-
Также от имени пользователя
adqm_userвыполните принудительное завершение запросов одним из способов, перечисленных ниже.-
Завершение запроса по его идентификатору:
KILL QUERY WHERE query_id = '6d522fb4-97db-45e4-9565-3158edb5a281';Результат выполнения команды
KILL QUERY:┌─kill_status─┬─query_id────────────────────────────┬─user────┬─query───────────────────────────────┐ 1. │ waiting │ 6d522fb4-97db-45e4-9565-3158edb5a281│ default │ SELECT count() FROM system.numbers; │ └─────────────┴─────────────────────────────────────┴─────────┴─────────────────────────────────────┘
Столбец
kill_statusсодержит значениеwaiting, так как запросKILL QUERYпо умолчанию выполняется в асинхронном режиме, то есть возвращает результат сразу, не дожидаясь фактического завершения указанного запроса. -
Завершение всех запросов, запущенных пользователем
default:KILL QUERY WHERE user = 'default';┌─kill_status─┬─query_id─────────────────────────────┬─user────┬─query───────────────────────────────┐ 1. │ waiting │ 6d522fb4-97db-45e4-9565-3158edb5a281 │ default │ SELECT count() FROM system.numbers; │ 2. │ waiting │ f38506fd-4923-4bd2-8668-e6affdaa61c4 │ default │ SELECT count() FROM system.numbers; │ └─────────────┴──────────────────────────────────────┴─────────┴─────────────────────────────────────┘
Перед тем как вызывать команду для прерывания запросов, можно выполнить
KILL QUERYс модификаторомTEST, чтобы убедиться, что у пользователяadqm_userесть права на остановку запросов, запущенных другим пользователем, и посмотреть, какие именно запросы будет отменять эта команда:KILL QUERY WHERE user = 'default' TEST;┌─kill_status────┬─query_id─────────────────────────────┬─user────┬─query───────────────────────────────┐ 1. │ unknown_status │ 6d522fb4-97db-45e4-9565-3158edb5a281 │ default │ SELECT count() FROM system.numbers; │ 2. │ unknown_status │ f38506fd-4923-4bd2-8668-e6affdaa61c4 │ default │ SELECT count() FROM system.numbers; │ └────────────────┴──────────────────────────────────────┴─────────┴─────────────────────────────────────┘
Если у пользователя недостаточно прав на прерывание запросов другого пользователя, клиент выведет соответствующее сообщение, например:
DB::Exception: User adqm_user attempts to kill query created by default. (ACCESS_DENIED). -
Завершение всех выполняющихся в данный момент запросов, длительность которых превышает 90 секунд:
KILL QUERY WHERE elapsed > 90;
-
KILL MUTATION
Мутации в ADQM/ClickHouse (операции изменения/удаления данных ALTER TABLE … UPDATE/DELETE) подразумевают перезапись больших фрагментов данных и могут быть довольно ресурсозатратными. После запуска мутации ее нельзя откатить, выполнение мутации будет продолжаться даже после перезапуска сервера, но можно явно прервать операцию мутации с помощью команды KILL MUTATION (например, если мутация выполняется очень долго или в ней больше нет необходимости). Прерывание мутации отменяет ее дальнейшую обработку, но все изменения, уже примененные к данным, остаются — поэтому рекомендуется использовать KILL MUTATION осторожно, особенно в production-системах, так как это может повлиять на целостность данных.
Синтаксис запроса KILL MUTATION:
KILL MUTATION [ON CLUSTER <cluster_name>] WHERE <where_expr> [ASYNC|SYNC|TEST] [FORMAT <output_format>];
где:
-
[ON CLUSTER <cluster_name>]— имя кластера, на всех узлах которого нужно остановить выполнение мутации. -
WHERE <where_expr>— обязательное выражение для выбора мутаций, выполнение которых необходимо прервать. Мутации, которые не завершились на текущий момент и потенциально могут быть проблемными, можно посмотреть в таблице system.mutations (строки с условиемis_done = 0). В выражении<where_expr>можно использовать значения столбцовdatabase,table,mutation_idи других столбцов этой таблицы, чтобы указать мутации для прерывания командойKILL MUTATION. -
[ASYNC|SYNC|TEST]— ключевое слово, указывающее должна ли командаKILL MUTATIONвыполняться асинхронно, синхронно или в тестовом режиме (аналогично KILL QUERY). -
[FORMAT <output_format>]— необязательное выражение, указывающее формат вывода результата операции прерывания мутации.
Так же как для KILL QUERY, в результате команды KILL MUTATION выводится столбец kill_status, значение которого показывает статус выполнения операции прерывания мутации.
Для прерывания мутации через команду KILL MUTATION необходимо иметь те же права, что требуются для запуска этой мутации. Например, чтобы остановить мутацию ALTER DELETE, необходимо иметь права ALTER DELETE, ALTER TABLE или ALTER. Для выполнения KILL MUTATION ON CLUSTER необходимо иметь права на выполнение всех типов мутаций (ALTER UPDATE, ALTER DELETE, ALTER MATERIALIZE COLUMN, ALTER MATERIALIZE INDEX, ALTER MATERIALIZE TTL) с областью действия ON *.*, поскольку при запуске запроса в кластере система сначала проверяет права доступа и не знает какие конкретно мутации будет завершать команда KILL MUTATION до начала ее выполнения.
Пример
-
Получите список мутаций, которые находятся в процессе выполнения:
SELECT * FROM system.mutations WHERE is_done = 0;Следующий запрос возвращает список активных мутаций в кластере (замените
<cluster_name>на имя своего кластера):SELECT * FROM clusterAllReplicas('<cluster_name>', system.mutations) WHERE is_done = 0; -
Выполните прерывание мутаций, фильтруя их в запросе
KILL MUTATIONпо значениям из таблицыsystem.mutations.-
Прерывание всех незаконченных мутаций в таблице
my_tableбазы данныхmy_databaseв кластереmy_cluster:KILL MUTATION ON CLUSTER my_cluster WHERE database = 'my_database' AND table = 'my_table' AND is_done = 0; -
Завершение конкретной мутации с идентификатором
mutation_2.txtв таблицеmy_tableбазы данныхmy_database:KILL MUTATION WHERE database = 'my_database' AND table = 'my_table' AND mutation_id = 'mutation_2.txt' AND is_done = 0;Пример вывода результата запроса на прерывание мутации (где
<mutation_query_text>— текст команды на изменение/удаление данных,UPDATE…илиDELETE…):┌─kill_status─┬─database─────┬─table────┬─mutation_id────┬─command─────────────────┐ 1. │ waiting │ my_database │ my_table │ mutation_2.txt │ (<mutation_query_text>) │ └─────────────┴──────────────┴──────────┴────────────────┴─────────────────────────┘
-
Известная проблема
Не все запросы могут быть прерваны командой KILL QUERY. Эта команда не останавливает выполнение запроса фактически, а только устанавливает флаг на прерывание, который проверяется самим запросом в определенные моменты его выполнения (обычно после завершения обработки одного блока конвейера выполнения запроса и перед началом другого). Запрос не может быть остановлен, если он "застрял" на этапе, где этот флаг не проверяется (например, при вычислении скалярного значения подзапроса, которое выполняется на этапе анализа запроса, вне основного конвейера выполнения запроса). В случаях, когда запрос невозможно прервать с помощью KILL QUERY, единственным способом его завершить может быть перезапуск сервера ClickHouse.