> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-fix-nav-issues.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Мутации удаления

> Страница с описанием мутаций удаления — запросов ALTER, которые удаляют данные из таблицы

Мутации удаления — это запросы `ALTER`, которые удаляют данные из таблицы. Прежде всего, к ним относятся запросы вроде `ALTER TABLE DELETE` и т. д. Выполнение таких запросов создаёт новые изменённые версии частей данных. Это означает, что такие команды приводят к перезаписи целых частей данных для всех данных, которые были вставлены до мутации, а значит — к большому количеству запросов на запись.

<Info>
  При удалении можно избежать такого большого количества запросов на запись, если использовать специализированные движки таблиц, например [ReplacingMergeTree](/ru/concepts/features/operations/update/replacing-merge-tree) или [CollapsingMergeTree](/ru/reference/engines/table-engines/mergetree-family/collapsingmergetree), вместо стандартного движка таблицы MergeTree.
</Info>

Оператор легковесного `DELETE` удаляет строки из таблицы `[db.]table`, соответствующие выражению `expr`. Он доступен только для таблиц семейства \*MergeTree.

```sql theme={null}
DELETE FROM [db.]table [ON CLUSTER cluster] [IN PARTITION partition_expr] WHERE expr;
```

Это называется "легковесный `DELETE`", чтобы отличать его от команды [ALTER TABLE ... DELETE](/ru/reference/statements/alter/delete), которая является ресурсоёмкой операцией.

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

```sql theme={null}
-- Удаляет все строки из таблицы `hits`, где столбец `Title` содержит текст `hello`
DELETE FROM hits WHERE Title LIKE '%hello%';
```

<div id="lightweight-delete-does-not-delete-data-immediately">
  ## Легковесный `DELETE` не удаляет данные сразу
</div>

Легковесный `DELETE` реализован как [мутация](/ru/reference/statements/alter#mutations): она помечает строки как удалённые, но не удаляет их физически сразу.

По умолчанию команды `DELETE` дожидаются завершения пометки строк как удалённых, и только после этого возвращают результат. Это может занять много времени, если объём данных велик. В качестве альтернативы можно запустить удаление асинхронно в фоновом режиме с помощью настройки [`lightweight_deletes_sync`](/ru/reference/settings/session-settings#lightweight_deletes_sync). Если она отключена, оператор `DELETE` вернётся сразу, но данные могут по-прежнему быть видны в запросах, пока фоновая мутация не завершится.

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

Если вам нужно гарантировать удаление данных из хранилища в предсказуемые сроки, рассмотрите возможность использования настройки таблицы [`min_age_to_force_merge_seconds`](/ru/reference/settings/merge-tree-settings#min_age_to_force_merge_seconds). Либо можно использовать команду [ALTER TABLE ... DELETE](/ru/reference/statements/alter/delete). Обратите внимание, что удаление данных с помощью `ALTER TABLE ... DELETE` может потребовать значительных ресурсов, так как при этом пересоздаются все затронутые части.

<div id="deleting-large-amounts-of-data">
  ## Удаление больших объёмов данных
</div>

Удаление больших объёмов данных может отрицательно сказаться на производительности ClickHouse. Если вам нужно удалить из таблицы все строки, рассмотрите возможность использовать команду [`TRUNCATE TABLE`](/ru/reference/statements/truncate).

Если вы ожидаете частых удалений, рассмотрите возможность использовать [пользовательский ключ партиционирования](/ru/reference/engines/table-engines/mergetree-family/custom-partitioning-key). В этом случае можно использовать команду [`ALTER TABLE ... DROP PARTITION`](/ru/reference/statements/alter/partition#drop-partitionpart), чтобы быстро удалить все строки, относящиеся к этой партиции.

<div id="limitations-of-lightweight-delete">
  ## Ограничения легковесного `DELETE`
</div>

<div id="lightweight-deletes-with-projections">
  ### Легковесные `DELETE` с проекциями
</div>

По умолчанию `DELETE` не работает с таблицами, содержащими проекции. Это связано с тем, что операция `DELETE` может затрагивать строки в проекции. Однако это поведение можно изменить с помощью [настройки MergeTree](/ru/reference/settings/merge-tree-settings) `lightweight_mutation_projection_mode`.

<div id="performance-considerations-when-using-lightweight-delete">
  ## Особенности производительности при использовании легковесного `DELETE`
</div>

**Удаление больших объёмов данных с помощью легковесного оператора `DELETE` может негативно сказаться на производительности запросов SELECT.**

На производительность легковесного `DELETE` также могут негативно влиять следующие факторы:

* Сложное условие `WHERE` в запросе `DELETE`.
* Если очередь мутаций заполнена множеством других мутаций, это может привести к проблемам с производительностью, поскольку все мутации таблицы выполняются последовательно.
* Затронутая таблица содержит очень большое число частей данных.
* Большой объём данных в компактных частях. В компактной части все столбцы хранятся в одном файле.

<div id="delete-permissions">
  ## Разрешения для DELETE
</div>

Для выполнения `DELETE` требуется привилегия `ALTER DELETE`. Чтобы разрешить пользователю выполнять операторы `DELETE` для конкретной таблицы, выполните следующую команду:

```sql theme={null}
GRANT ALTER DELETE ON db.table to username;
```

<div id="how-lightweight-deletes-work-internally-in-clickhouse">
  ## Как в ClickHouse внутренне работает легковесный DELETE
</div>

1. **К затронутым строкам применяется «маска»**

   Когда выполняется запрос `DELETE FROM table ...`, ClickHouse сохраняет маску, в которой каждая строка помечается как «существующая» или «удалённая». Такие «удалённые» строки исключаются из последующих запросов. Однако физически строки удаляются только позже, во время последующих слияний. Запись этой маски гораздо менее затратна, чем выполнение запроса `ALTER TABLE ... DELETE`.

   Маска реализована в виде скрытого системного столбца `_row_exists`, который хранит `True` для всех видимых строк и `False` для удалённых. Этот столбец присутствует в части только если в ней были удалены некоторые строки. Если в части все значения равны `True`, этот столбец отсутствует.

2. **Запросы `SELECT` преобразуются с учётом маски**

   Когда в запросе используется замаскированный столбец, запрос `SELECT ... FROM table WHERE condition` внутренне дополняется предикатом по `_row_exists` и преобразуется в:

   ```sql theme={null}
   SELECT ... FROM table PREWHERE _row_exists WHERE condition
   ```

   Во время выполнения столбец `_row_exists` считывается, чтобы определить, какие строки не нужно возвращать. Если удалённых строк много, ClickHouse может определить, какие гранулы можно полностью пропустить при чтении остальных столбцов.

3. **Запросы `DELETE` преобразуются в запросы `ALTER TABLE ... UPDATE`**

   `DELETE FROM table WHERE condition` преобразуется в мутацию `ALTER TABLE table UPDATE _row_exists = 0 WHERE condition`.

   Внутренне эта мутация выполняется в два шага:

   1. Для каждой отдельной части выполняется команда `SELECT count() FROM table WHERE condition`, чтобы определить, затронута ли эта часть.

   2. На основе результатов этих команд затем изменяются затронутые части, а для незатронутых создаются жёсткие ссылки. В случае широких частей столбец `_row_exists` обновляется для каждой строки, а файлы всех остальных столбцов связываются жёсткими ссылками. Для компактных частей все столбцы перезаписываются, потому что они хранятся вместе в одном файле.

   Из описанных выше шагов видно, что легковесный `DELETE`, использующий технику маскирования, работает быстрее традиционного `ALTER TABLE ... DELETE`, потому что не требует перезаписи файлов всех столбцов в затронутых частях.

<div id="related-content">
  ## Материалы по теме
</div>

* Блог: [Handling Updates and Deletes in ClickHouse](https://clickhouse.com/blog/handling-updates-and-deletes-in-clickhouse)
