Движок MergeTree — это основной движок хранения в ClickHouse, оптимизированный для быстрого выполнения аналитических запросов на больших наборах данных. Он достигает высокой скорости выполнения запросов благодаря столбцовому хранению, сортировке по первичному ключу, разреженной индексации, фоновому слиянию, партиционированию и сжатию.


1. Ключевые оптимизации в MergeTree для производительности запросов

Особенность оптимизацииКак это улучшает производительность запросов
Столбцовое хранениеЗапросы читают только необходимые столбцы, что снижает диск I/O
Сортировка по первичному ключуДанные физически упорядочены, что ускоряет запросы по диапазону
Разреженная индексацияМинимизирует использование памяти, обеспечивая быстрый поиск
ПартиционированиеПропускает нерелевантные данные, уменьшая время выполнения запросов
Сжатие данныхСнижает объем хранимых данных и улучшает эффективность I/O
Фоновое слияниеОптимизирует хранение данных со временем, ускоряя выполнение запросов
Векторизованное выполнениеИспользует SIMD инструкции для параллельной обработки

2. Столбцовое хранение для быстрого чтения

В отличие от баз данных на основе строк (MySQL, PostgreSQL), ClickHouse хранит данные в столбцах, а не в строках.

  • Запросы читают только нужные столбцы, что снижает диск I/O.
  • Эффективное сжатие применяется для каждого столбца.

Пример: Запрос только одного столбца

`SELECT SUM(revenue) FROM sales WHERE event_time >= '2024-01-01';`

В хранилище на основе строк запрос сканирует все столбцы (что увеличивает I/O).
В MergeTree (столбцовое хранение) ClickHouse читает только столбец revenue → значительно быстрее!


3. Сортировка по первичному ключу и разреженная индексация

Как это работает:

  • Данные хранятся отсортированными по первичному ключу.
  • ClickHouse создает разреженный индекс, указывающий на каждую N-ю гранулу.

Пример: Поиск по индексу MergeTree

CREATE TABLE sales (
    id UInt32,
    event_time DateTime,
    revenue Float64
) ENGINE = MergeTree()
ORDER BY (event_time, id);
 
  • Данные физически упорядочены по event_time.
  • Запросы, фильтрующие по event_time, сканируют только релевантные секции.

Быстрая фильтрация по диапазону
Меньше использования памяти (поскольку хранится только разреженный индекс)


4. Партиционирование: снижение объема сканируемых данных

MergeTree поддерживает партиционирование, позволяя запросам пропускать целые партиции.

Пример: Создание партиционированной таблицы

CREATE TABLE sales (
    id UInt32,
    event_time DateTime,
    revenue Float64
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(event_time)
ORDER BY (event_time, id);
  • Партиционирование по месяцам означает, что запрос для января 2024 года сканирует только 1/12 данных.

Значительное сокращение времени выполнения запроса
Легко удалять партиции для соблюдения политик хранения данных


5. Фоновое слияние для оптимизации хранения

Как работает слияние:

  • Данные записываются в мелкие части.
  • Процесс фонового слияния периодически объединяет их в более крупные и оптимизированные части.
  • Это поддерживает эффективное хранение и предотвращает фрагментацию.

Ускоряет запросы за счет уменьшения числа мелких, неэффективных файлов
Обеспечивает оптимальную скорость чтения со временем


6. Сжатие: снижение объема хранения и улучшение скорости запросов

MergeTree поддерживает несколько алгоритмов сжатия:

Алгоритм сжатияЛучше всего дляКак работает
LZ4 (по умолчанию)Общего назначенияБыстрое сжатие/распаковка, низкое использование процессора
ZSTD (Zstandard)Высокое сжатиеБолее ресурсоемкое, но лучшее сжатие
DeltaЦелочисленные данные (ID, временные метки)Хранит разницу между последовательными значениями
GorillaЧисла с плавающей запятойЭффективное хранение сенсорных данных, значений временных рядов
T64Малоценные целочисленные значенияОптимизирован для повторяющихся целых чисел

Сжатые данные требуют меньшего числа чтений с диска
Меньше использования места для больших наборов данных


7. Векторизованное выполнение (SIMD-оптимизированные запросы)

MergeTree обрабатывает данные пакетами (векторами) вместо построчной обработки:

  • Использует SIMD (Single Instruction, Multiple Data), чтобы обрабатывать несколько значений за один цикл процессора.
  • Оптимизировано для быстрых агрегаций.

Колоссальное ускорение аналитических запросов
✅ Запросы типа SUM(), AVG(), COUNT() выполняются гораздо быстрее


8. Рабочий процесс оптимизации выполнения запросов

1️⃣ Запрос анализируется.
2️⃣ Поиск разреженного индекса определяет релевантные гранулы.
3️⃣ Обрезка партиций пропускает ненужные партиции.
4️⃣ Векторизованное выполнение ускоряет вычисления.


9. Резюме: Почему MergeTree быстрый

Столбцовое хранение снижает I/O
Сортировка по первичному ключу ускоряет запросы по диапазону
Разреженные индексы минимизируют нагрузку на память
Партиционирование обрезает нерелевантные данные
Фоновое слияние поддерживает оптимальное хранение данных
Сжатие снижает объем данных и ускоряет чтение
Векторизованное выполнение ускоряет агрегации