В прошлом уроке мы узнали, что каждая часть 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 ₽.
Оплата пока не подключена: премиум и курсы открываются промокодом.