HAVING

О HAVING и немного оптимизации

Вернёмся к нашей таблице data_analyzer.diagnosis_dst_meta из предыдущего примера. Добавим группировку по ключу партиционирования и отфильтруем данные двумя способами:

SELECT toYYYYMM(signed_dt), count() as cnt
FROM data_analyzer.diagnosis_dst_meta
GROUP BY toYYYYMM(signed_dt)
HAVING toYYYYMM(signed_dt) IN (202501, 202502, 202503)
SELECT toYYYYMM(signed_dt), count() as cnt FROM data_analyzer.diagnosis_dst_meta
WHERE toYYYYMM(signed_dt) IN (202501, 202502, 202503)
GROUP BY toYYYYMM(signed_dt)

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

Результаты

Мы видим, что результаты практически идентичны (только незначительное различие по памяти). Это произошло, потому что на самом деле первый запрос не был выполнен, как мы его задумали, а был оптимизирован кликхаусом (тут мы обсуждаем эту оптимизацию). Давайте в этом убедимся при помощи оператора EXPLAIN SYNTAX — эта конструкция показывает, как выглядит запрос после внутренней оптимизации:

EXPLAIN SYNTAX SELECT toYYYYMM(signed_dt), count() as cnt
FROM data_analyzer.diagnosis_dst_meta
GROUP BY toYYYYMM(signed_dt)
HAVING toYYYYMM(signed_dt) IN (202501, 202502, 202503)

EXPLAIN SYNTAX SELECT toYYYYMM(signed_dt), count() as cnt
FROM data_analyzer.diagnosis_dst_meta
WHERE toYYYYMM(signed_dt) IN (202501, 202502, 202503)
GROUP BY toYYYYMM(signed_dt)
Один результат в обоих случаях

Несмотря на то, что кликхаус исправляет такие ошибки пользователя, происходит это не всегда и спрогнозировать работу оптимизатора невозможно. Поэтому правильно использовать WHERE вместо HAVING если это возможно

Выводы

  • Не используйте HAVING там, где можно обойтись WHERE

  • Используйте EXPLAIN SYNTAX, чтобы увидеть, как запрос выглядит после обработки оптимизатором

Last updated