ПрограммированиеData Analyst / Backend разработчик

Какие подводные камни есть при использовании конструкции GROUP BY в SQL, особенно при агрегации и оптимизации сложных запросов?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

GROUP BY используется для группировки строк и агрегирования данных, но при неправильном применении может вызывать серьезные ошибки или неоптимальную работу.

Ключевые тонкости:

  • В SELECT допускаются только столбцы из GROUP BY или агрегатные функции.
  • В сложных запросах с несколькими JOIN'ами возможны дубли и неверная агрегация.
  • Формальный порядок: GROUP BY выполняется после WHERE и до HAVING.
  • При отсутствии индексирования по групповым столбцам запрос может работать очень медленно на больших объемах данных.
  • HAVING — фильтрует уже после группировки, а WHERE — до неё.

Пример:

SELECT customer_id, COUNT(*) as orders FROM orders WHERE order_date >= '2024-01-01' GROUP BY customer_id HAVING COUNT(*) > 10;

Вопрос с подвохом.

Можно ли в SELECT после GROUP BY ссылаться на поля, которые не были указаны ни в GROUP BY, ни в агрегатной функции?

Ответ: Нет, это приведёт к ошибке в большинстве SQL-реализаций (например, в MS SQL, PostgreSQL). Некоторые специфические БД могут показать случайное, неверное значение (особенно в MySQL с sql_mode 'ONLY_FULL_GROUP_BY' выключен), но это поведение некорректно и не гарантируется стандартом. Корректный пример:

SELECT department, AVG(salary) FROM employees GROUP BY department;

Примеры реальных ошибок из-за незнания тонкостей темы.


История

В e-commerce проекте отчет "выручка по товарам" готовили запросом SELECT sku, price, SUM(qty) FROM orders GROUP BY sku. Не учли: price не попал в GROUP BY и был вне агрегатной функции, результат — MySQL возвращал первое попавшееся значение цены, что при акции дало серьёзные ошибки в отчёте. Исправление — либо добавить price в GROUP BY, либо использовать агрегатную функцию.


История

В BI-проекте сложный отчет с несколькими JOIN и GROUP BY выполнялся по 80 минут вместо плановых 3. После анализа выяснили: отсутствовали индексы по полю из GROUP BY и фильтрации, создавались огромные временные таблицы для агрегации. Решение — оптимизация индексов и переписка запроса с табличными выражениями.


История

Разработчик применил HAVING для фильтрации значений по неагрегированному атрибуту пользователя. В результате сервер отработал группировку по всем данным, а потом убрал их по HAVING, снизив производительность. Исправили — вынесли эту проверку в WHERE, чтобы сужать выборку до агрегации.