GROUP BY и агрегатные функции
агрегатные функции считают, суммируют и находят максимумы по группам строк.
Почему это важно: Аналитика, дашборды, статистика — всё это строится на агрегации. Без GROUP BY приходится тащить данные в приложение и считать там, что медленнее.
Главная идея
GROUP BY группирует строки по значению столбца; агрегатные функции (COUNT, SUM, AVG, MAX, MIN) вычисляют значение для каждой группы.
Как это выглядит на практике
- SELECT category, COUNT(*) FROM products GROUP BY category — количество товаров по категориям.
- SELECT user_id, SUM(amount) FROM orders GROUP BY user_id — сумма заказов на пользователя.
- HAVING SUM(amount) > 1000 фильтрует уже сгруппированные результаты.
- ORDER BY total DESC LIMIT 10 — топ-10 покупателей по сумме.
Что происходит под капотом
- В SELECT можно указывать только столбцы из GROUP BY или агрегатные функции — иначе запрос некорректен.
- COUNT(*) считает все строки; COUNT(column) — только строки, где column не NULL.
- HAVING выполняется после GROUP BY; WHERE — до. Фильтруйте через WHERE там, где возможно.
- Агрегация на больших таблицах без индексов требует full table scan — это медленно.
Типичные ошибки и заблуждения
- Ошибка: HAVING и WHERE взаимозаменяемы. WHERE фильтрует строки до агрегации, HAVING — после.
- Ошибка: COUNT(*) и COUNT(id) всегда одинаковы. COUNT(column) игнорирует NULL.
- Ошибка: GROUP BY возвращает отсортированные результаты. Без ORDER BY порядок не гарантирован.
- Ошибка: агрегатные запросы всегда медленные. С правильными индексами и покрывающими индексами — нет.
Ключевые выводы
- GROUP BY группирует строки; агрегатные функции считают значения для каждой группы.
- HAVING фильтрует после группировки; WHERE — до.
- COUNT(*) считает строки; COUNT(col) — строки без NULL.
- Выносите фильтрацию в WHERE, а не HAVING — это эффективнее.
Термины урока
Связь с работой backend-разработчика
Считайте статистику в SQL, а не в коде приложения. БД оптимизирована для агрегации больших объёмов данных; загрузка тысяч строк в память приложения для подсчёта — антипаттерн.
Мини-разбор реальной ситуации
Дашборд аналитики тянет все заказы за год (100 000 строк) в Rails, считает суммы в Ruby и возвращает JSON. Запрос занимает 8 секунд. Замена на SELECT user_id, SUM(amount) FROM orders GROUP BY user_id выполняется за 120 мс в БД.
Что запомнить
- Агрегируйте в SQL, а не в приложении.
- WHERE быстрее HAVING — используйте его для фильтрации строк.
- GROUP BY без ORDER BY не гарантирует порядок результатов.
Итог
GROUP BY и агрегатные функции переносят вычисления туда, где данные — в базу. Это быстрее, проще и масштабируемее, чем обработка в коде приложения.