WHERE
Фильтрация
В этой главе мы рассмотрим разные примеры фильтрации и сравним их между собой.
Фильтрация по ключу сортировки
Посмотрим последние строки DDL таблицы, которую мы будем рассматривать. Здесь — подробнее о DDL.
... # код создания таблицы
PRIMARY KEY patient_id -- индекс
ORDER BY patient_id -- ключ сортировки
SETTINGS index_granularity = 8192;
Посмотрим, насколько меняется потребление ресурсов при фильтрации. Есть такой запрос, где происходит фильтрация по полю patient_gender:
SELECT patient_id FROM m_students.v_students_light_1;
SELECT patient_id FROM m_students.v_students_light_1 WHERE patient_gender = 'ж';

При фильтрации по полю patient_gender происходит чтение дополнительной колонки, отсюда увеличивается потребление памяти. Количество прочитанных строк в обоих случаях одинаково — это вся таблица. Затраты оперативной памяти отличаются незначительно. Поле patient_gender не является ключом сортировки и при фильтрации по нему читается вся таблица.
Посмотрим следующий пример фильтрации — в первом случае мы фильтруем по полю dn_id (не является ключом сортировки), а во втором случае — по полю patient_id (т.е. по ключу сортировки):
SELECT dn_id FROM m_students.v_students_light_1 WHERE dn_id IN (<list>)
SELECT patient_id FROM m_students.v_students_light_1 WHERE patient_id IN (<list>)
Списки dn_id и patient_id — это случайно выбранные 10 id из всей таблицы.

Мы видим насколько снижено потребление ресурсов при фильтрации по ключу сортировки — patient_id. Обратите внимание, что в таком случае не требуется прочтение всей таблицы.
Фильтрация по ключу партиционирования
Если таблица партиционирована (подробнее), то нужно фильтровать в первую очередь по ключу партиционирования, а затем по ключу сортировки.
Для примера возьмем партиционированную таблицу data_analyzer.diagnosis_dst_meta. Всего в таблице примерно 1.36 миллиарда строк. Заглянем в DDL таблицы:
... # код создания таблицы
PARTITION BY toYYYYMM(signed_dt)
PRIMARY KEY (document_class_id,
document_id)
ORDER BY (document_class_id,
document_id,
xpath,
line_id)
SETTINGS index_granularity = 8192;
Сначала попробуем отфильтровать данные НЕ по ключу партиционирования: по колонке document_created:
SELECT document_id FROM data_analyzer.diagnosis_dst_meta
WHERE document_created > '2025-03-10' # колонка с датой
AND type = 'основной диагноз' # просто пример фильтрации по обычному полю

Потребление ресурсов значительное, потому что читается вся таблица (см. количество прочитанных строк).
Теперь попробуем фильтровать по ключу партиционирования:
SELECT document_id FROM data_analyzer.diagnosis_dst_meta
WHERE signed_dt > '2025-03-10' # ключ партиционирования
AND type = 'основной диагноз'

Обратите внимание, читается гораздо меньше строк, потому что кликхаус сразу идёт только в нужные партиции, а остальные ему читать не нужно. Потребление оперативной памяти — примерно в 35 раз меньше.
Проведём последний эксперимент в этой секции, попробуем профильтровать те же партиции, но будем использовать фильтрацию по ключу сортировки document_class_id вместо фильтрации по полю type:
SELECT document_id FROM data_analyzer.diagnosis_dst_meta
WHERE signed_dt > '2025-03-10' # ключ партиционирования
AND document_class_id IN (<список из class_id>) # ключ сортировки

Обратите внимание, что несмотря на то, что количество строк в результате запроса больше (2.2 млн против 1.93 млн) мы потратили меньше ресурсов и прочли меньше строк.
Порядок в секции WHERE важен — используйте сначала ключ партиционирования, затем ключ сортировки, затем другие фильтрации. Хотя ClickHouse оптимизирует фильтрацию даже если вы нарушите порядок, хорошим тоном является соблюдать такой порядок фильтрации в запросе.
Выводы
Используйте фильтрацию по ключу партиционирования и ключам сортировки, если это возможно
Порядок фильтрации в WHERE следующий: ключ партиционирования, ключ сортировки, остальные поля
Last updated