Выбор стратегии обновления
- Использование специализированных движков таблиц, которые выполняют обновления через вставки
- Использование декларативных обновлений, таких как операторы
UPDATE ... SETилиALTER TABLE ... UPDATE
Когда использовать специализированные движки таблиц
Поскольку движки таблиц семейства MergeTree выполняют слияние частей данных в фоновом режиме, они обеспечивают согласованность в конечном счёте, и при запросах к таблице нужно использовать ключевое слово
FINAL, чтобы на промежуточном этапе обеспечить корректную дедупликацию.
Существуют и другие типы движков, но именно эти используются чаще всего.
Когда использовать декларативные обновления
Обновления с помощью специализированных движков таблиц
ReplacingMergeTree
ReplacingMergeTree выполняет дедупликацию строк с одинаковым ключом сортировки во время фоновых слияний, оставляя только самую новую версию.
FINAL или эквивалентную логику запроса. Модификатор FINAL добавляет к запросу дополнительную нагрузку в диапазоне 21–550% в зависимости от данных.
ReplacingMergeTree не может обновлять значения ключа сортировки. Он также поддерживает столбец Deleted для логических удалений.
Подробнее: руководство по ReplacingMergeTree | справочник по ReplacingMergeTree
CoalescingMergeTree
Nullable. Как и в случае с ReplacingMergeTree, для получения корректных результатов после коалесценции используйте FINAL.
Этот движок доступен начиная с ClickHouse 25.6.
Подробнее: CoalescingMergeTree
CollapsingMergeTree
CollapsingMergeTree использует столбец Sign, чтобы указать ClickHouse, как обрабатывать строки во время слияний. Если в столбец Sign вставляется значение -1, строка схлопывается (удаляется) при наличии соответствующей строки с +1. Строки для обновления определяются на основе ключа сортировки, заданного в выражении ORDER BY при создании таблицы.
ReplacingMergeTree, CollapsingMergeTree позволяет изменять значения ключа сортировки. Он хорошо подходит для обратимых операций с семантикой отмены, таких как финансовые транзакции или отслеживание состояния в игре.
Описанный выше подход к обновлению требует, чтобы приложение хранило состояние на стороне клиента, чтобы можно было вставить строку отмены. Хотя с точки зрения ClickHouse это наиболее эффективный вариант, при масштабировании работа с ним может быть сложной. Кроме того, для получения корректных результатов в запросах нужна агрегация с умножением на знак.
Декларативные обновления
Мутации
ALTER TABLE ... UPDATE) перезаписывают все части, содержащие строки, удовлетворяющие выражению WHERE.
WHERE.
Этот процесс не является атомарным.
Части заменяются мутированными версиями, как только те становятся готовы, и SELECT-запрос, который начинает выполняться во время мутации, увидит данные как из уже мутированных частей, так и из частей, которые еще не были мутированы.
Отслеживать состояние прогресса можно через таблицу system.mutations.
Подробнее: ALTER TABLE UPDATE
Мутации на лету
ALTER TABLE ... UPDATE вам может потребоваться подождать, пока они будут применены фоновым процессом, прежде чем измененные значения отобразятся в результатах запросов.
ClickHouse позволяет изменить это поведение с помощью “мутаций на лету”.
Когда мутации на лету включены, обновленные строки сразу помечаются как обновленные, и последующие запросы SELECT автоматически возвращают измененные значения.
Мутации на лету можно включить для таблиц семейства MergeTree, включив настройку уровня запроса apply_mutations_on_fly.
Пример
Пример
Давайте создадим таблицу и выполним несколько мутаций:Проверим результат обновлений с помощью запроса Обратите внимание: при запросе к новой таблице значения в строках еще не обновились:Теперь посмотрим, что произойдет, если включить мутации на лету:Теперь запрос
SELECT:SELECT сразу возвращает корректный результат, без ожидания применения мутаций:Влияние на производительность
SELECT-запросов. Однако обратите внимание: в фоновом режиме мутации по-прежнему асинхронно материализуются, а это ресурсоемкий процесс.
Если в течение некоторого интервала времени число отправленных мутаций постоянно превышает число мутаций, обрабатываемых в фоновом режиме, очередь нематериализованных мутаций, которые нужно применить, будет продолжать расти. В конечном итоге это приведет к снижению производительности SELECT-запросов.
Мы рекомендуем включать настройку apply_mutations_on_fly вместе с другими настройками уровня MergeTree, такими как number_of_mutations_to_throw и number_of_mutations_to_delay, чтобы ограничить бесконтрольный рост числа нематериализованных мутаций.
Поддержка подзапросов и недетерминированных функций
mutations_max_literal_size_to_replace). Поддерживаются только константные недетерминированные функции (например, функция now()).
Это поведение контролируется следующими настройками:
Легковесные обновления
UPDATE и сразу создает патч-части, не дожидаясь слияний. Обновленные значения сразу видны в запросах SELECT за счет применения патчей, но физически материализуются только во время последующих слияний. Это делает легковесные обновления оптимальным вариантом для обновления небольшого процента строк (до ~10% таблицы) с предсказуемой latency. Бенчмарки показывают, что они могут быть до 23 раз быстрее, чем мутации.
Компромисс заключается в том, что запросы SELECT требуют дополнительных затрат при применении патчей, а патч-части учитываются в лимитах на части. При превышении порога ~10% накладные расходы на применение патчей при чтении растут пропорционально, поэтому для более крупных обновлений синхронные мутации эффективнее.
Подробнее: Легковесный UPDATE
Мутации на лету
Мутации на лету позволяют обновлять строки так, что последующие запросыSELECT автоматически возвращают изменённые значения, не дожидаясь фоновой обработки. Тем самым устраняется ограничение атомарности, присущее обычным мутациям.
SELECT должен быть включен параметр apply_mutations_on_fly = 1. Условия мутации хранятся в ClickHouse Keeper, который держит всё в памяти, и применяются на лету во время выполнения запросов.
Обратите внимание, что для обновления данных всё равно используется мутация — просто она не материализуется сразу. Мутация по-прежнему будет применяться в фоновом режиме как асинхронный процесс и создаёт такую же существенную нагрузку, как и обычная мутация. Выражения, которые можно использовать с этой операцией, также ограничены (см. подробности).
Подробнее: Мутации на лету