Оператор облегчённого UPDATE
Облегчённые обновления в данный момент находятся на стадии бета-тестирования. Если вы столкнётесь с проблемами, пожалуйста, создайте issue в репозитории ClickHouse.
Оператор облегчённого UPDATE обновляет строки в таблице [db.]table, которые соответствуют выражению filter_expr.
Он называется «облегчённым обновлением», чтобы противопоставить его запросу ALTER TABLE ... UPDATE, который является ресурсоёмким процессом и полностью перезаписывает столбцы в частях данных.
Он доступен только для семейства движков таблиц MergeTree.
filter_expr должен иметь тип UInt8. Этот запрос обновляет значения указанных столбцов, устанавливая их равными значениям соответствующих выражений в строках, для которых filter_expr принимает ненулевое значение.
Значения приводятся к типу столбца с помощью оператора CAST. Обновление столбцов, используемых при вычислении первичного ключа или ключа партиционирования, не поддерживается.
Примеры
Облегчённые обновления не обновляют данные немедленно
Облегчённый UPDATE реализован с использованием патч‑частей (patch parts) — специального типа частей данных, которые содержат только обновлённые столбцы и строки.
Облегчённый UPDATE создаёт патч‑части, но не изменяет исходные данные физически в хранилище немедленно.
Процесс обновления аналогичен запросу INSERT ... SELECT ..., но запрос UPDATE возвращается только после завершения создания патч‑частей.
Обновлённые значения:
- Сразу видны в запросах
SELECTблагодаря применению патчей - Физически материализуются только во время последующих слияний и мутаций
- Автоматически удаляются, когда во всех активных частях патчи материализованы
Требования к лёгким обновлениям
Лёгкие обновления поддерживаются для движков MergeTree, ReplacingMergeTree, CollapsingMergeTree и их вариантов Replicated и Shared.
Чтобы использовать лёгкие обновления, необходимо включить материализацию столбцов _block_number и _block_offset с помощью настроек таблицы enable_block_number_column и enable_block_offset_column.
Легковесные операции удаления
Запрос легковесного DELETE может быть выполнен как легковесный UPDATE вместо мутации ALTER UPDATE. Поведение легковесного DELETE определяется настройкой lightweight_delete_mode.
Особенности производительности
Преимущества легковесных обновлений:
- Задержка обновления сопоставима с задержкой запроса
INSERT ... SELECT ... - Записываются только обновлённые столбцы и значения, а не целые столбцы в частях данных
- Нет необходимости ждать завершения текущих слияний/мутаций, поэтому задержка обновления предсказуема
- Возможна параллельная обработка легковесных обновлений
Потенциальное влияние на производительность:
- Создаёт накладные расходы для запросов
SELECT, которым необходимо применять патчи - Пропускающие индексы не будут использоваться для столбцов в частях данных, к которым должны быть применены патчи. Проекции не будут использоваться, если для таблицы есть части-патчи, включая части данных, к которым не нужно применять патчи.
- Слишком частые небольшие обновления могут привести к ошибке «too many parts» («слишком много частей»). Рекомендуется объединять несколько обновлений в один запрос, например, поместив идентификаторы для обновления в один оператор
INв условииWHERE - Легковесные обновления предназначены для обновления небольшого количества строк (до примерно 10% таблицы). Если необходимо обновить больший объём, рекомендуется использовать мутацию
ALTER TABLE ... UPDATE
Одновременные операции
Легковесные обновления не дожидаются завершения уже выполняющихся слияний и мутаций, в отличие от тяжёлых мутаций.
Согласованность одновременных легковесных обновлений контролируется настройками update_sequential_consistency и update_parallel_mode.
Права на выполнение UPDATE
UPDATE требует привилегии ALTER UPDATE. Чтобы разрешить выполнение операторов UPDATE для конкретной таблицы определённому пользователю, выполните:
Подробности реализации
Patch parts аналогичны обычным партам, но содержат только обновлённые столбцы и несколько системных столбцов:
_part— имя исходного парта_part_offset— номер строки в исходном парте_block_number— номер блока строки в исходном парте_block_offset— смещение блока строки в исходном парте_data_version— версия обновлённых данных (номер блока, выделенный для запросаUPDATE)
В среднем это даёт около 40 байт (несжатых данных) накладных расходов на обновлённую строку в patch parts.
Системные столбцы помогают находить строки в исходном парте, которые должны быть обновлены.
Системные столбцы связаны с виртуальными столбцами в исходном парте, которые добавляются при чтении, если patch parts должны быть применены.
Patch parts сортируются по _part и _part_offset.
Patch parts принадлежат другим партициям, чем исходный парт.
Идентификатор партиции patch part — patch-<hash of column names in patch part>-<original_partition_id>.
Таким образом, patch parts с разными столбцами хранятся в разных партициях.
Например, три обновления SET x = 1 WHERE <cond>, SET y = 1 WHERE <cond> и SET x = 1, y = 1 WHERE <cond> создадут три patch parts в трёх разных партициях.
Patch parts могут сливаться друг с другом, чтобы уменьшить количество применяемых патчей при запросах SELECT и снизить накладные расходы. Слияние patch parts использует алгоритм слияния replacing с _data_version в качестве столбца версии.
Таким образом, patch parts всегда хранят последнюю версию для каждой обновлённой строки в парте.
Лёгкие обновления (lightweight updates) не ждут завершения текущих слияний (merges) и мутаций (mutations) и всегда используют текущий снепшот data parts для выполнения обновления и формирования patch part. Из‑за этого возможны два варианта применения patch parts.
Например, если мы читаем парт A, нам нужно применить patch part X:
- если
Xсодержит сам партA. Это происходит, еслиAне участвовал в merge в момент выполненияUPDATE; - если
Xсодержит партыBиC, которые покрываются партомA. Это происходит, если merge (B,C) ->Aвыполнялся в момент выполненияUPDATE.
Для этих двух случаев, соответственно, есть два способа применения patch parts:
- слияние по отсортированным столбцам
_part,_part_offset; - join по столбцам
_block_number,_block_offset.
Режим join медленнее и требует больше памяти, чем режим merge, но используется реже.
Связанные материалы
ALTER UPDATE— «тяжёлые» операцииUPDATE- Lightweight
DELETE— «лёгкие» операцииDELETE