Перейти к основному содержанию

Проверка первичного ключа

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

Создание таблицы

Рассмотрим простую таблицу:
Обратите внимание, что в качестве второго элемента наш ключ сортировки содержит toUnixTimestamp(timestamp).

Загрузка данных

Заполните эту таблицу 100 млн строками:

Базовая фильтрация

Если отфильтровать по коду, в выводе будет видно количество просканированных строк — 49.15 thousand. Обратите внимание, что это лишь часть от общего числа в 100 млн строк.
Кроме того, использование индекса можно подтвердить с помощью конструкции EXPLAIN indexes=1:
Обратите внимание, что количество просканированных гранул 8012 составляет лишь часть от общего числа 12209. Раздел, выделенный ниже, подтверждает, что используется первичный ключ.
Гранулы — это единицы обработки данных в ClickHouse; каждая из них обычно содержит 8192 строк. Подробнее о гранулах и о том, как выполняется их фильтрация, см. в этом руководстве.
Фильтрация по ключам, расположенным позже в ключе сортировки, менее эффективна, чем по ключам, расположенным раньше в кортеже. Почему это так, см. здесь

Фильтрация по нескольким ключам

Предположим, что мы фильтруем по code и timestamp:
В этом случае оба ключа сортировки используются для фильтрации строк, поэтому нужно прочитать лишь 87 гранул.

Использование ключей при сортировке

ClickHouse также может использовать ключи сортировки для эффективной сортировки. В частности, Если включена настройка optimize_read_in_order (по умолчанию она включена), сервер ClickHouse использует индекс таблицы и читает данные в порядке, заданном ключом ORDER BY. Это позволяет не считывать все данные, если указан LIMIT. Поэтому запросы к большим объемам данных с небольшим LIMIT выполняются быстрее. Подробнее см. здесь и здесь. Однако для этого используемые ключи должны быть согласованы. Например, рассмотрим такой запрос:
Мы можем убедиться с помощью EXPLAIN pipeline, что эта оптимизация здесь не используется:
Строка MergeTreeSelect(pool: ReadPool, algorithm: Thread) здесь указывает не на использование оптимизации, а на обычное чтение. Это связано с тем, что в качестве ключа сортировки таблицы используется toUnixTimestamp(Timestamp), а НЕ timestamp. Устранение этого несоответствия решает проблему:
Последнее изменение 12 июня 2026 г.