Что такое слияние частей в ClickHouse?
ClickHouse работает быстро не только при выполнении запросов, но и при вставке данных благодаря своему уровню хранения, который устроен схожим образом с LSM-деревьями: ① Вставки (в таблицы семейства движков MergeTree) создают отсортированные неизменяемые части данных. ② Вся обработка данных переносится в фоновые слияния частей. Это делает запись данных малозатратной и высокоэффективной. Чтобы контролировать количество частей в таблице и реализовать описанное в пункте ② выше, ClickHouse непрерывно объединяет (в пределах каждой партиции) меньшие части в более крупные в фоновом режиме, пока их сжатый размер не достигнет примерно ~150 GB. Следующая диаграмма схематично показывает этот фоновый процесс слияния:
merge level части увеличивается на единицу с каждым очередным слиянием. Уровень 0 означает, что часть новая и еще не была объединена. Части, объединенные в более крупные, помечаются как неактивные и затем удаляются через настраиваемый промежуток времени (по умолчанию 8 минут). Со временем это образует дерево слитых частей. Отсюда и название таблицы MergeTree.
Мониторинг слияний
/merges и позволяет визуализировать все слияния частей для таблицы из нашего примера:
На записи панели мониторинга выше показан весь процесс — от первоначальных вставок данных до итогового слияния в одну часть: ① Количество активных частей. ② Слияния частей, визуально представленные прямоугольниками (их размер отражает размер части). ③ Усиление записи.
Параллельные слияния
Каждый поток слияния выполняет цикл: ① Определяет, какие части сливать следующими, и загружает их в память. ② Объединяет части в памяти в одну более крупную часть. ③ Записывает слитую часть на диск. Вернитесь к ① Обратите внимание: увеличение числа ядер CPU и объема оперативной памяти позволяет повысить пропускную способность фоновых слияний.
Слияния с оптимизацией по памяти
Механика слияния
Слияние частей выполняется в несколько этапов: ① Декомпрессия и загрузка: сжатые бинарные файлы столбцов из частей, подлежащих слиянию, распаковываются и загружаются в память. ② Слияние: Данные сливаются в более крупные файлы столбцов. ③ Индексация: Для слитых файлов столбцов создаётся новый разреженный первичный индекс. ④ Сжатие и хранение: Новые файлы столбцов и индекс сжимаются и сохраняются в новом каталоге, который представляет слитую часть данных. Дополнительные метаданные в частях данных, такие как вторичные индексы пропуска данных, статистика столбцов, контрольные суммы и min-max-индексы, также пересоздаются на основе слитых файлов столбцов. Для простоты мы опустили эти детали. Механика этапа ② зависит от конкретного движка MergeTree, поскольку разные движки выполняют слияние по-разному. Например, устаревшие строки могут агрегироваться или заменяться. Как уже упоминалось, такой подход переносит всю обработку данных в фоновые слияния, обеспечивая сверхбыстрые вставки за счёт того, что операции записи остаются лёгкими и эффективными. Далее мы кратко рассмотрим механику слияния в конкретных движках семейства MergeTree.
Стандартные слияния
DDL-оператор на схеме выше создаёт таблицу
MergeTree с ключом сортировки (town, street), то есть данные на диске сортируются по этим столбцам, и на их основе создаётся разреженный первичный индекс.
① Распакованные предварительно отсортированные столбцы таблицы ② объединяются с сохранением глобального порядка сортировки, заданного ключом сортировки таблицы, ③ создаётся новый разреженный первичный индекс, а ④ объединённые файлы столбцов и индекс сжимаются и сохраняются на диске как новая часть данных.
Слияния в ReplacingMergeTree
DDL-оператор на диаграмме выше создаёт таблицу
ReplacingMergeTree с ключом сортировки (town, street, id), то есть данные на диске сортируются по этим столбцам, а соответствующим образом строится разреженный первичный индекс.
На этапе ② слияние происходит так же, как и в стандартной таблице MergeTree: объединяются распакованные, предварительно отсортированные столбцы с сохранением глобального порядка сортировки.
Однако ReplacingMergeTree удаляет дублирующиеся строки с одинаковым ключом сортировки, сохраняя только самую новую строку по временной метке создания части, в которой она находится.
Суммирующие слияния
DDL-оператор на схеме выше определяет таблицу
SummingMergeTree, где town используется как ключ сортировки. Это означает, что данные на диске сортируются по этому столбцу и на его основе создаётся разреженный первичный индекс.
На этапе слияния ② ClickHouse заменяет все строки с одинаковым ключом сортировки одной строкой, суммируя значения числовых столбцов.
Слияния с агрегацией
SummingMergeTree, приведённый выше, — это специализированный вариант таблицы AggregatingMergeTree, который позволяет выполнять автоматическое инкрементальное преобразование данных, применяя любую из 90+ функций агрегации при слиянии частей:
DDL-оператор на диаграмме выше создаёт таблицу
AggregatingMergeTree, в которой town используется как ключ сортировки, что гарантирует упорядочивание данных по этому столбцу на диске и создание соответствующего разреженного первичного индекса.
Во время ② слияния ClickHouse заменяет все строки с одинаковым ключом сортировки одной строкой, в которой хранятся Промежуточные состояния агрегации (например, sum и count для avg()). Эти состояния обеспечивают точные результаты благодаря инкрементальным фоновым слияниям.