Раздел 38 · ClickHouse и аналитические базы

ORDER BY и первичный ключ: ключ к скорости

junior~15 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

В прошлом уроке мы узнали, что каждая часть MergeTree отсортирована по ключу ORDER BY. Зачем вообще сортировать? Колоночное хранение уже экономит на колонках. Сортировка экономит на строках: она позволяет не читать куски таблицы, где нужных строк точно нет. Это самый важный рычаг скорости в ClickHouse, и выбирают его один раз, при создании таблицы.

Телефонный справочник

Бумажный справочник отсортирован по фамилии. Чтобы найти всех Ивановых, ты открываешь книгу посередине, видишь «М», листаешь назад, ещё раз делишь пополам и через несколько шагов попадаешь на нужную страницу. Читать всю книгу не надо.

А теперь найди всех, у кого номер кончается на 42. Сортировка по фамилии здесь бесполезна: такие люди разбросаны по всей книге, и читать придётся каждую страницу.

Сверху каждой страницы справочника напечатана первая фамилия на ней. По этим заголовкам и ищут. Записывать в оглавление каждую фамилию не нужно, хватит одной на страницу. Именно так устроен индекс ClickHouse.

Гранулы и метки

ClickHouse делит каждую часть на гранулы: куски по 8192 строки подряд. Гранула для ClickHouse как страница справочника: меньше гранулы он не читает. Нужна одна строка, прочитается вся гранула.

Для каждой гранулы ClickHouse запоминает значения ключа ORDER BY в её первой строке. Это метка, заголовок страницы. Все метки части вместе образуют разреженный индекс: одна запись на восемь тысяч строк. Таблица на миллиард строк получает индекс примерно на 120 тысяч меток, он легко помещается в память.

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

Ключ из нескольких колонок

Таблица заказов «Гонца» создана с ORDER BY (zone_id, created_at). Строки отсортированы сначала по зоне, а внутри зоны по времени. Как справочник, отсортированный по фамилии, а внутри фамилии по имени.

Отсюда правило, которое надо запомнить:

  • условие на первую колонку ключа (zone_id = 3) работает отлично: все заказы зоны лежат подряд;
  • условие на первую и вторую (zone_id = 3 AND created_at >= '2026-06-01') ещё лучше;
  • условие только на вторую (created_at >= '2026-06-30') помогает слабо: заказы за 30 июня есть в каждой из двенадцати зон, то есть в двенадцати местах таблицы;
  • условие на колонку не из ключа (courier_id = 23) не помогает совсем: читается вся таблица.

урок из курса

Урок из курса «ClickHouse и аналитические базы». Курс покупается один раз и остаётся навсегда: 500 ₽.

Оплата пока не подключена: премиум и курсы открываются промокодом.