Почему UPDATE в ClickHouse плохая идея 👎 (и чем его заменить)
⚠️полезно для собесов👇
Многие приходят в ClickHouse из классических баз типа Postgres и поэтому очень хочется написать привычный UPDATE. В ClickHouse это очень плохая идея! 🚮
ClickHouse - это OLAP. Он создан для быстрой записи и чтения миллиардов строк, а не для того, чтобы менять одну ячейку в середине таблицы.
Почему обычный UPDATE — это дорого?
Классические обновления в ClickHouse работают через мутации. Если упростить: база не меняет значение на месте, а переписывает целые куски данных (parts) на диске. Хотели поменять статус у пары юзеров - заставили сервер перелопатить гигабайты данных ☹️ Если таких апдейтов много, очередь мутаций забьет диск и база просто встанет.
Как делать правильно:
1️⃣ReplacingMergeTree для Upsert-сценариев.
Не обновляем старую строку, а вставляем новую версию. ClickHouse сам схлопнет их при фоновом мерже. Идеально для CDC-потоков и профилей пользователей. Да, в запросах может понадобиться FINAL, но это честная цена за производительность.
2️⃣Append-only для событий.
Если у заказа меняется статус (создан -> оплачен -> доставлен), не надо менять одну строку. Пишите историю событий. Текущее состояние вынимается через argMax за доли секунды.
3️⃣Агрегаты через Materialized Views.
Вместо того чтобы обновлять счетчик покупок, пишите сырые события, а суммы считайте через агрегирующие движки (AggregatingMergeTree).
4️⃣CollapsingMergeTree. Он работает через специальную колонку Sign: строка с Sign = 1 считается актуальным состоянием, а строка с Sign = -1 “отменяет” старую запись. При merge ClickHouse схлопывает такие пары строк с одинаковым ключом. Это полезно, когда у вас поток изменений устроен как добавить новое состояние и погасить старое, но для базового upsert чаще проще начать с ReplacingMergeTree.
Было полезно, ставьте 🔥
⚠️полезно для собесов👇
Многие приходят в ClickHouse из классических баз типа Postgres и поэтому очень хочется написать привычный UPDATE. В ClickHouse это очень плохая идея! 🚮
ClickHouse - это OLAP. Он создан для быстрой записи и чтения миллиардов строк, а не для того, чтобы менять одну ячейку в середине таблицы.
Почему обычный UPDATE — это дорого?
Классические обновления в ClickHouse работают через мутации. Если упростить: база не меняет значение на месте, а переписывает целые куски данных (parts) на диске. Хотели поменять статус у пары юзеров - заставили сервер перелопатить гигабайты данных ☹️ Если таких апдейтов много, очередь мутаций забьет диск и база просто встанет.
Как делать правильно:
1️⃣ReplacingMergeTree для Upsert-сценариев.
Не обновляем старую строку, а вставляем новую версию. ClickHouse сам схлопнет их при фоновом мерже. Идеально для CDC-потоков и профилей пользователей. Да, в запросах может понадобиться FINAL, но это честная цена за производительность.
2️⃣Append-only для событий.
Если у заказа меняется статус (создан -> оплачен -> доставлен), не надо менять одну строку. Пишите историю событий. Текущее состояние вынимается через argMax за доли секунды.
3️⃣Агрегаты через Materialized Views.
Вместо того чтобы обновлять счетчик покупок, пишите сырые события, а суммы считайте через агрегирующие движки (AggregatingMergeTree).
4️⃣CollapsingMergeTree. Он работает через специальную колонку Sign: строка с Sign = 1 считается актуальным состоянием, а строка с Sign = -1 “отменяет” старую запись. При merge ClickHouse схлопывает такие пары строк с одинаковым ключом. Это полезно, когда у вас поток изменений устроен как добавить новое состояние и погасить старое, но для базового upsert чаще проще начать с ReplacingMergeTree.
Итог: ClickHouse любит не изменения старых строк, а правильную модель записи новых.
Было полезно, ставьте 🔥