← Назад к вопросам

Что такое гранулярный индекс в ClickHouse?

3.0 Senior🔥 61 комментариев
#Базы данных

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое гранулярный индекс в ClickHouse?

Гранулярный индекс — это фундаментальный механизм индексации данных в ClickHouse, тесно связанный с его архитектурой хранения и обработки. В отличие от традиционных B-деревьев в реляционных СУБД, гранулярный индекс работает на уровне гранул — неделимых блоков данных, которые являются минимальной единицей чтения с диска при выполнении запросов. Эта концепция лежит в основе высокой производительности ClickHouse при аналитических запросах.

Как устроен гранулярный индекс?

Гранула формируется в процессе записи данных и состоит из двух ключевых элементов:

  • Первичный ключ (Primary Key): Определяет порядок сортировки данных на диске. Это не уникальный идентификатор записи, а способ физического упорядочивания строк.
  • Индексные метки (Data Marks): Для каждой гранулы (обычно 8192 строки по умолчанию) создаются «метки» — указатели на начало блока данных этой гранулы на диске. Метка содержит значения первичного ключа для первой строки каждой гранулы.

Вот упрощённая схема:

-- Пример таблицы с первичным ключом
CREATE TABLE events
(
    event_date Date,
    user_id UInt64,
    event_type String
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(event_date)
ORDER BY (event_date, user_id); -- Первичный ключ (может быть длиннее)
-- Размер гранулы по умолчанию: index_granularity = 8192 строк

На диске данные будут отсортированы сначала по event_date, затем по user_id. Гранулярный индекс состоит из меток, каждая из которых хранит значения event_date и user_id для первой строки каждой новой гранулы (например, строк 1, 8193, 16385...).

Принцип работы: фильтрация на основе меток

При выполнении запроса с условием WHERE по полям первичного ключа, ClickHouse использует гранулярный индекс следующим образом:

  1. Сканирование индекса в памяти: Система последовательно читает массив индексных меток, загруженный в RAM.
  2. Пропуск гранул (Data Skipping): Для каждой метки проверяется, попадают ли значения её первой строки в диапазон условий WHERE. Если нет, вся гранула из 8192 строк пропускается, и её данные не считываются с диска.
  3. Чтение только релевантных гранул: Если условие может выполняться для строк внутри гранулы, её данные считываются с диска целиком, после чего внутри гранулы выполняется точная фильтрация.

Допустим, выполняется запрос:

SELECT count() FROM events WHERE event_date = '2023-12-01' AND user_id = 12345;

ClickHouse пройдётся по меткам, быстро определит, какие гранулы могут содержать строки с этой датой и user_id, и прочитает только их, минуя все остальные.

Ключевые характеристики и особенности

  • Разреженность (Sparsity): Индекс хранит информацию лишь о первой строке каждой гранулы, а не о каждой строке. Это делает его очень компактным (часто помещается в оперативной памяти) и быстрым для сканирования.
  • Эффективность для диапазонных запросов: Идеально подходит для операторов =, >, <, IN, LIKE (если строки лексикографически отсортированы) по префиксам первичного ключа. Эффективность падает, если условие не использует префикс ключа.
  • Материализованная физическая сортировка: Высокая производительность гранулярного индекса напрямую зависит от корректного проектирования ORDER BY (первичного ключа) под шаблоны запросов. Данные должны быть отсортированы так, чтобы часто используемые фильтры группировали строки вместе.
  • Настройка гранулярности: Параметр index_granularity (по умолчанию 8192) можно изменить:
    ENGINE = MergeTree ORDER BY ... SETTINGS index_granularity = 4096;
    
    Меньшая гранулярность → точнее фильтрация и меньше лишних данных читается, но больше меток и накладных расходов. Большая гранулярность → компактнее индекс, но больше данных читается «вхолостую».
  • Отличие от вторичных индексов: Помимо первичного, ClickHouse поддерживает скалярные (минимум/максимум) и пропускающие (skipping) индексы. Они работают поверх гранулярного индекса, храня агрегированную информацию (например, min/max значения столбца) для каждой гранулы, что позволяет ещё эффективнее отсекать неподходящие блоки.

Преимущества и недостатки

Преимущества (+):

  • Скорость: Сканирование в памяти и массовый пропуск блоков данных.
  • Эффективность по памяти: Компактный размер.
  • Предсказуемость: Производительность линейно зависит от объёма отфильтрованных данных.

Недостатки (-):

  • Нет точечного поиска: Не может найти одну строку — всегда читается целиком гранула.
  • Зависимость от сортировки: Неэффективен, если условия запроса не соответствуют порядку ключа.
  • Только для столбцов первичного ключа: Для фильтрации по другим столбцам требуется full scan или дополнительные индексы.

Итог: Гранулярный индекс — это не индекс в классическом понимании, а механизм coarse-grained фильтрации на уровне блоков, который использует физическую сортировку данных для минимизации операций ввода-вывода. Его правильное использование через тщательный выбор ORDER BY — ключ к достижению максимальной производительности ClickHouse в аналитических workloads.