🧭 Почему primary index в ClickHouse — это не обычный primary key

🔥 Главная мысль

Очень частая ошибка — переносить мышление из PostgreSQL, MySQL или MS SQL в ClickHouse.

Кажется, что primary key везде должен означать одно и то же: уникальность строки + быстрый поиск конкретной записи.

Но в ClickHouse это не так.

В ClickHouse primary index — это не “индекс на каждую строку”, а разреженный индекс по гранулам данных.

Его задача — не найти одну запись как можно быстрее, а как можно раньше понять, какие большие куски данных можно вообще не читать.

Именно поэтому primary index в ClickHouse — это часть аналитической архитектуры, а не просто ограничение уникальности.

➕ Плюсы и минусы

🟢 Плюсы:

• хорошо работает на больших объёмах данных • экономит память по сравнению с классическими построчными индексами • ускоряет аналитические запросы за счёт отсечения ненужных гранул • хорошо подходит под OLAP-нагрузку, где читают миллионы строк, а не одну запись

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

🔴 Минусы:

• это не механизм уникальности как в классическом primary key • он не создан для точечного поиска одной строки по произвольному полю • если выбрать плохой ключ сортировки, пользы будет мало • он не покрывает все сценарии фильтрации, особенно текстовый поиск, regex и сложные проверки на вхождение

Пример минуса: если ты ждёшь, что ClickHouse мгновенно найдёт одну запись по user_id так же, как OLTP-база по b-tree индексу, то это часто будет ложное ожидание.

🧪 Живые примеры

Сначала коротко: primary index в ClickHouse хранит не значение для каждой строки, а min/max значения на гранулу.

Гранула — это блок строк что по умолчанию равна — 8192 строки.

Что это значит на практике:

• ClickHouse хранит данные блоками • для каждого блока понимает диапазон значений • если блок под условие не подходит — он пропускается • если подходит — читается уже сам блок данных

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

Пример для минуса: если в таблице нужен поиск одной конкретной строки по полю, которое не связано с порядком сортировки, primary index может почти не помочь.

Пример из жизни: представь огромный архив документов, где на коробках написан только диапазон дат, а не список всех файлов внутри. Ты не знаешь точное место каждого документа, но очень быстро понимаешь, какие коробки даже не нужно открывать.

Вот так и работает primary index в ClickHouse.

🏗 Архитектурная мысль

В больших компаниях primary index в ClickHouse рассматривают не как аналог primary key из OLTP, а как способ правильно организовать чтение данных.

Сначала думают не про уникальность, а про другое:

• по каким полям чаще всего фильтруют • как данные будут сортироваться при записи • какие диапазонные условия будут в WHERE • какие запросы должны отсекать максимум лишнего чтения

Почему это важно:

• ClickHouse работает на очень больших объёмах • классический построчный индекс был бы слишком дорогим по памяти • для аналитики важнее быстро отсечь ненужные куски данных, чем хранить “путь к каждой строке” • основной индекс тесно связан с ORDER BY и физическим порядком данных в MergeTree-таблице

Риски:

• думать, что PRIMARY KEY в ClickHouse гарантирует уникальность • выбирать ключ “как в OLTP” • не учитывать, что индекс работает по гранулам, а не по строкам • пытаться решать primary index’ом задачи текстового поиска или regex

✅ Вывод

Primary index в ClickHouse — это не “уникальный ключ строки”, а “механизм не читать лишние данные” ⚡️

✅ Подходит: для OLAP, витрин, BI, больших таблиц, диапазонных фильтров

❌ Не подходит: как замена классическому primary key из OLTP

🧭 Почему primary index в ClickHouse — это не обычный primary key
🔥 Главная мысль
Очень частая ошибка —
переносить мышление из PostgreSQL, MySQL или MS SQL в ClickHouse | Сетка — социальная сеть от hh.ru