🕷️ Crawler Inspector

URL Lookup

Direct Parameter Lookup

Raw Queries and Responses

1. Shard Calculation

Query:
Response:
Calculated Shard: 89 (from laksa010)

2. Crawled Status Check

Query:
Response:

3. Robots.txt Check

Query:
Response:

4. Spam/Ban Check

Query:
Response:

5. Seen Status Check

ℹ️ Skipped - page is already crawled

📄
INDEXABLE
CRAWLED
2 days ago
🤖
ROBOTS ALLOWED

Page Info Filters

FilterStatusConditionDetails
HTTP statusPASSdownload_http_code = 200HTTP 200
Age cutoffPASSdownload_stamp > now() - 6 MONTH0.1 months ago
History dropPASSisNull(history_drop_reason)No drop reason
Spam/banPASSfh_dont_index != 1 AND ml_spam_score = 0ml_spam_score=0
CanonicalPASSmeta_canonical IS NULL OR = '' OR = src_unparsedNot set

Page Details

PropertyValue
URLhttps://clickhouse.com/docs/ru/sql-reference/statements/select/group-by
Last Crawled2026-04-06 21:09:06 (2 days ago)
First Indexed2022-04-23 02:04:24 (3 years ago)
HTTP Status Code200
Meta TitleОператор GROUP BY | ClickHouse Docs
Meta DescriptionДокументация по оператору GROUP BY
Meta Canonicalnull
Boilerpipe Text
Оператор GROUP BY переводит запрос SELECT в режим агрегации, который работает следующим образом: Оператор GROUP BY содержит список выражений (или одно выражение, которое рассматривается как список длины один). Этот список выступает в роли "ключа группировки", а каждое отдельное выражение далее называется "ключевым выражением". Все выражения в операторах SELECT , HAVING и ORDER BY должны вычисляться на основе ключевых выражений или на основе агрегатных функций над неклю́чевыми выражениями (включая обычные столбцы). Другими словами, каждый столбец, выбранный из таблицы, должен использоваться либо в ключевом выражении, либо внутри агрегатной функции, но не одновременно в обоих местах. Результат агрегирующего запроса SELECT будет содержать столько строк, сколько было уникальных значений "ключа группировки" в исходной таблице. Обычно это существенно уменьшает число строк, зачастую на порядки, но не обязательно: количество строк останется прежним, если все значения "ключа группировки" были различны. Если нужно группировать данные в таблице по номерам столбцов вместо их имен, включите настройку enable_positional_arguments . Примечание Существует дополнительный способ выполнения агрегации над таблицей. Если в запросе столбцы таблицы встречаются только внутри агрегатных функций, оператор GROUP BY можно опустить, и будет подразумеваться агрегация по пустому набору ключей. Такие запросы всегда возвращают ровно одну строку. Обработка NULL ​ При группировке ClickHouse интерпретирует NULL как значение, и NULL == NULL . Это отличается от обработки NULL в большинстве других контекстов. Ниже приведён пример, иллюстрирующий это. Предположим, у вас есть следующая таблица: ┌─x─┬────y─┐ │ 1 │ 2 │ │ 2 │ ᴺᵁᴸᴸ │ │ 3 │ 2 │ │ 3 │ 3 │ │ 3 │ ᴺᵁᴸᴸ │ └───┴──────┘ Запрос SELECT sum(x), y FROM t_null_big GROUP BY y приводит к следующему результату: ┌─sum(x)─┬────y─┐ │ 4 │ 2 │ │ 3 │ 3 │ │ 5 │ ᴺᵁᴸᴸ │ └────────┴──────┘ Видно, что GROUP BY для y = NULL суммировал x так, как если бы NULL было этим значением. Если указать в GROUP BY несколько ключей, в результате вы получите все комбинации выборки, как если бы NULL рассматривался как конкретное значение. Модификатор ROLLUP ​ Модификатор ROLLUP используется для вычисления промежуточных итогов для ключевых выражений в соответствии с их порядком в списке GROUP BY . Строки с промежуточными итогами добавляются после результирующей таблицы. Промежуточные итоги вычисляются в обратном порядке: сначала — для последнего ключевого выражения в списке, затем для предыдущего и так далее до первого ключевого выражения. В строках с промежуточными итогами значения уже «сгруппированных» ключевых выражений устанавливаются в значение 0 или пустую строку. Примечание Имейте в виду, что предложение HAVING может повлиять на результаты промежуточных итогов. Пример Рассмотрим таблицу t: ┌─year─┬─month─┬─day─┐ │ 2019 │ 1 │ 5 │ │ 2019 │ 1 │ 15 │ │ 2020 │ 1 │ 5 │ │ 2020 │ 1 │ 15 │ │ 2020 │ 10 │ 5 │ │ 2020 │ 10 │ 15 │ └──────┴───────┴─────┘ Запрос: SELECT year , month , day , count ( * ) FROM t GROUP BY ROLLUP ( year , month , day ) ; Поскольку секция GROUP BY содержит три ключевых выражения, результат включает четыре таблицы с промежуточными итогами, «свёрнутыми» справа налево: GROUP BY year, month, day ; GROUP BY year, month (и столбец day заполняется нулями); GROUP BY year (теперь оба столбца month и day заполняются нулями); и общие итоги (и все три столбца с ключевыми выражениями заполнены нулями). ┌─year─┬─month─┬─day─┬─count()─┐ │ 2020 │ 10 │ 15 │ 1 │ │ 2020 │ 1 │ 5 │ 1 │ │ 2019 │ 1 │ 5 │ 1 │ │ 2020 │ 1 │ 15 │ 1 │ │ 2019 │ 1 │ 15 │ 1 │ │ 2020 │ 10 │ 5 │ 1 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 2019 │ 1 │ 0 │ 2 │ │ 2020 │ 1 │ 0 │ 2 │ │ 2020 │ 10 │ 0 │ 2 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 2019 │ 0 │ 0 │ 2 │ │ 2020 │ 0 │ 0 │ 4 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 0 │ 0 │ 0 │ 6 │ └──────┴───────┴─────┴─────────┘ Этот же запрос можно записать и с использованием ключевого слова WITH . SELECT year , month , day , count ( * ) FROM t GROUP BY year , month , day WITH ROLLUP ; См. также Параметр group_by_use_nulls для обеспечения совместимости со стандартом SQL. Модификатор CUBE ​ Модификатор CUBE используется для вычисления промежуточных итогов для каждой комбинации ключевых выражений в списке GROUP BY . Строки с промежуточными итогами добавляются после результирующей таблицы. В строках с промежуточными итогами значения всех «сгруппированных» ключевых выражений устанавливаются в 0 или пустую строку. Примечание Имейте в виду, что предложение HAVING может влиять на результаты промежуточных итогов. Пример Рассмотрим таблицу t: ┌─year─┬─month─┬─day─┐ │ 2019 │ 1 │ 5 │ │ 2019 │ 1 │ 15 │ │ 2020 │ 1 │ 5 │ │ 2020 │ 1 │ 15 │ │ 2020 │ 10 │ 5 │ │ 2020 │ 10 │ 15 │ └──────┴───────┴─────┘ Запрос: SELECT year , month , day , count ( * ) FROM t GROUP BY CUBE ( year , month , day ) ; Так как секция GROUP BY содержит три ключевых выражения, результат содержит восемь таблиц с промежуточными итогами для всех комбинаций ключевых выражений: GROUP BY year, month, day GROUP BY year, month GROUP BY year, day GROUP BY year GROUP BY month, day GROUP BY month GROUP BY day и общие итоги. Столбцы, не включённые в GROUP BY , заполняются нулями. ┌─year─┬─month─┬─day─┬─count()─┐ │ 2020 │ 10 │ 15 │ 1 │ │ 2020 │ 1 │ 5 │ 1 │ │ 2019 │ 1 │ 5 │ 1 │ │ 2020 │ 1 │ 15 │ 1 │ │ 2019 │ 1 │ 15 │ 1 │ │ 2020 │ 10 │ 5 │ 1 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 2019 │ 1 │ 0 │ 2 │ │ 2020 │ 1 │ 0 │ 2 │ │ 2020 │ 10 │ 0 │ 2 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 2020 │ 0 │ 5 │ 2 │ │ 2019 │ 0 │ 5 │ 1 │ │ 2020 │ 0 │ 15 │ 2 │ │ 2019 │ 0 │ 15 │ 1 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 2019 │ 0 │ 0 │ 2 │ │ 2020 │ 0 │ 0 │ 4 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 0 │ 1 │ 5 │ 2 │ │ 0 │ 10 │ 15 │ 1 │ │ 0 │ 10 │ 5 │ 1 │ │ 0 │ 1 │ 15 │ 2 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 0 │ 1 │ 0 │ 4 │ │ 0 │ 10 │ 0 │ 2 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 0 │ 0 │ 5 │ 3 │ │ 0 │ 0 │ 15 │ 3 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 0 │ 0 │ 0 │ 6 │ └──────┴───────┴─────┴─────────┘ Тот же запрос можно записать и с использованием ключевого слова WITH . SELECT year , month , day , count ( * ) FROM t GROUP BY year , month , day WITH CUBE ; См. также Настройка group_by_use_nulls для совместимости со стандартом SQL. Модификатор WITH TOTALS ​ Если указан модификатор WITH TOTALS , будет вычислена дополнительная строка. В этой строке ключевые столбцы будут содержать значения по умолчанию (нули или пустые строки), а столбцы с агрегирующими функциями — значения, вычисленные по всем строкам (итоговые значения). Эта дополнительная строка создаётся только в форматах JSON* , TabSeparated* и Pretty* , отдельно от остальных строк: В форматах XML и JSON* эта строка выводится как отдельное поле totals . В форматах TabSeparated* , CSV* и Vertical строка следует после основного результата, предваряемая пустой строкой (после остальных данных). В форматах Pretty* строка выводится как отдельная таблица после основного результата. В формате Template строка выводится в соответствии с указанным шаблоном. В остальных форматах она недоступна. Примечание totals выводится в результатах запросов SELECT и не выводится в INSERT INTO ... SELECT . WITH TOTALS может работать по-разному, когда присутствует HAVING . Поведение зависит от настройки totals_mode . Настройка обработки totals ​ По умолчанию totals_mode = 'before_having' . В этом случае totals вычисляется по всем строкам, включая те, которые не проходят по условиям HAVING и max_rows_to_group_by . Другие варианты включают в totals только строки, прошедшие через HAVING, и по-разному ведут себя при настройках max_rows_to_group_by и group_by_overflow_mode = 'any' . after_having_exclusive – не включать строки, которые не прошли через max_rows_to_group_by . Другими словами, в totals будет меньше или столько же строк, сколько было бы, если бы max_rows_to_group_by был опущен. after_having_inclusive – включать в totals все строки, которые не прошли через max_rows_to_group_by . Другими словами, в totals будет больше или столько же строк, сколько было бы, если бы max_rows_to_group_by был опущен. after_having_auto – подсчитать количество строк, прошедших через HAVING. Если оно больше определённого порога (по умолчанию 50%), включить в totals все строки, которые не прошли через max_rows_to_group_by . В противном случае не включать их. totals_auto_threshold – по умолчанию 0.5. Коэффициент для after_having_auto . Если max_rows_to_group_by и group_by_overflow_mode = 'any' не используются, все варианты after_having эквивалентны, и можно использовать любой из них (например, after_having_auto ). Вы можете использовать WITH TOTALS во вложенных подзапросах, включая подзапросы в предложении JOIN (в этом случае соответствующие итоговые значения объединяются). GROUP BY ALL ​ GROUP BY ALL эквивалентен перечислению в предложении SELECT всех выражений, которые не являются агрегатными функциями. Например: SELECT a * 2 , b , count ( c ) , FROM t GROUP BY ALL то же самое, что SELECT a * 2 , b , count ( c ) , FROM t GROUP BY a * 2 , b В особом случае, когда есть функция, в которой в качестве аргументов используются и агрегатные функции, и другие поля, ключи GROUP BY будут содержать максимально возможное число неагрегатных полей, которые можно из этой функции извлечь. Например: SELECT substring ( a , 4 , 2 ) , substring ( substring ( a , 1 , 2 ) , 1 , count ( b ) ) FROM t GROUP BY ALL то же самое, что SELECT substring ( a , 4 , 2 ) , substring ( substring ( a , 1 , 2 ) , 1 , count ( b ) ) FROM t GROUP BY substring ( a , 4 , 2 ) , substring ( a , 1 , 2 ) Примеры ​ Пример: SELECT count ( ) , median ( FetchTiming > 60 ? 60 : FetchTiming ) , count ( ) - sum ( Refresh ) FROM hits В отличие от MySQL (и в соответствии со стандартом SQL), вы не можете получить значение столбца, не участвующего ни в ключе, ни в агрегатной функции (за исключением константных выражений). В качестве обходного решения можно использовать агрегатную функцию any (получить первое встретившееся значение) или min/max . Пример: SELECT domainWithoutWWW ( URL ) AS domain , count ( ) , any ( Title ) AS title -- getting the first occurred page header for each domain. FROM hits GROUP BY domain Для каждого различного значения ключа оператор GROUP BY вычисляет набор значений агрегатных функций. Модификатор GROUPING SETS ​ Это самый общий модификатор. Он позволяет вручную задавать несколько наборов ключей агрегации (grouping sets). Агрегация выполняется отдельно для каждого grouping set, после чего все результаты объединяются. Если столбец не входит в grouping set, он заполняется значением по умолчанию. Другими словами, модификаторы, описанные выше, могут быть выражены с помощью GROUPING SETS . Несмотря на то, что запросы с модификаторами ROLLUP , CUBE и GROUPING SETS синтаксически эквивалентны, их производительность может отличаться. Когда GROUPING SETS старается выполнять все варианты агрегации параллельно, ROLLUP и CUBE выполняют финальное слияние агрегатов в одном потоке. В ситуации, когда исходные столбцы содержат значения по умолчанию, может быть сложно определить, является ли строка частью агрегации, в которой эти столбцы используются как ключи, или нет. Чтобы решить эту проблему, необходимо использовать функцию GROUPING . Пример Следующие два запроса эквивалентны. -- Query 1 SELECT year , month , day , count ( * ) FROM t GROUP BY year , month , day WITH ROLLUP ; -- Query 2 SELECT year , month , day , count ( * ) FROM t GROUP BY GROUPING SETS ( ( year , month , day ) , ( year , month ) , ( year ) , ( ) ) ; См. также настройку group_by_use_nulls для обеспечения совместимости со стандартом SQL. Подробности реализации ​ Агрегация — одна из важнейших функций колоночной СУБД, и, следовательно, её реализация является одной из наиболее оптимизированных частей ClickHouse. По умолчанию агрегация выполняется в памяти с использованием хеш-таблицы. Для неё существует более 40 специализаций, которые выбираются автоматически в зависимости от типов данных «ключа группировки». Оптимизация GROUP BY в зависимости от сортировочного ключа таблицы ​ Агрегацию можно выполнять более эффективно, если таблица отсортирована по некоторому ключу, а выражение GROUP BY содержит как минимум префикс сортировочного ключа или инъективные функции. В этом случае, когда из таблицы читается новый ключ, промежуточный результат агрегации может быть финализирован и отправлен клиенту. Такое поведение включается настройкой optimize_aggregation_in_order . Подобная оптимизация снижает потребление памяти во время агрегации, но в некоторых случаях может замедлить выполнение запроса. GROUP BY во внешней памяти ​ Вы можете включить сброс временных данных на диск, чтобы ограничить использование памяти во время GROUP BY . Настройка max_bytes_before_external_group_by определяет порог потребления ОЗУ, при достижении которого временные данные GROUP BY начинают сбрасываться в файловую систему. Если установлено значение 0 (по умолчанию), механизм отключён. В качестве альтернативы вы можете задать max_bytes_ratio_before_external_group_by , что позволяет задействовать внешнюю память для GROUP BY только после того, как запрос достигнет определённого порога использованной памяти. При использовании max_bytes_before_external_group_by мы рекомендуем установить max_memory_usage примерно вдвое выше (или max_bytes_ratio_before_external_group_by=0.5 ). Это необходимо, потому что агрегация состоит из двух этапов: чтение данных и формирование промежуточных данных (1) и слияние промежуточных данных (2). Сброс данных в файловую систему может происходить только на этапе 1. Если временные данные не были сброшены, то на этапе 2 может потребоваться до такого же объёма памяти, как и на этапе 1. Например, если max_memory_usage было установлено в 10000000000 и вы хотите использовать внешнюю агрегацию, имеет смысл задать max_bytes_before_external_group_by равным 10000000000, а max_memory_usage — 20000000000. Когда внешняя агрегация срабатывает (если был хотя бы один сброс временных данных), максимальное потребление ОЗУ лишь немного превышает max_bytes_before_external_group_by . При распределённой обработке запросов внешняя агрегация выполняется на удалённых серверах. Чтобы сервер, инициирующий запрос, использовал лишь небольшое количество ОЗУ, установите distributed_aggregation_memory_efficient в 1. При слиянии данных, сброшенных на диск, а также при слиянии результатов с удалённых серверов при включённой настройке distributed_aggregation_memory_efficient , используется до 1/256 * число_потоков от общего объёма ОЗУ. Когда внешняя агрегация включена, если объём данных меньше max_bytes_before_external_group_by (то есть данные не были сброшены), запрос выполняется так же быстро, как и без внешней агрегации. Если какие-либо временные данные были сброшены, время выполнения будет в несколько раз больше (примерно в три раза). Если после GROUP BY используется ORDER BY с LIMIT , то объём используемой ОЗУ зависит от количества данных в LIMIT , а не во всей таблице. Но если у ORDER BY нет LIMIT , не забудьте включить внешнюю сортировку ( max_bytes_before_external_sort ).
Markdown
[Перейти к основному содержимому](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#__docusaurus_skipToContent_fallback) [![ClickHouse](https://clickhouse.com/docs/ru/img/ch_logo_docs.svg)](https://clickhouse.com/) - [Продукты](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by) - [ClickHouse Cloud Оптимальный способ работы с ClickHouse. Доступно в AWS, GCP и Azure.](https://clickhouse.com/cloud) - [ClickHouse Разверните базу данных с помощью открытой версии ClickHouse. ClickHouse](https://clickhouse.com/clickhouse) - [Ознакомьтесь с более чем 100 интеграциями.](https://clickhouse.com/integrations) [Ознакомьтесь с более чем 100 интеграциями.](https://clickhouse.com/integrations) - [Сценарии использования](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by) - [Аналитика в режиме реального времени](https://clickhouse.com/use-cases/real-time-analytics) - [Машинное обучение и генеративный ИИ](https://clickhouse.com/use-cases/machine-learning-and-data-science) - [Бизнес-аналитика](https://clickhouse.com/use-cases/data-warehousing) - [Логи, события и трейсы](https://clickhouse.com/use-cases/observability) - [Все сценарии использования](https://clickhouse.com/use-cases) [Все сценарии использования](https://clickhouse.com/use-cases) - [Документация](https://clickhouse.com/docs) - [Ресурсы](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by) - [Блог](https://clickhouse.com/blog) - [Events](https://clickhouse.com/company/events) - [Learning and certification](https://clickhouse.com/learn) - [Сравнение](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by) - [BigQuery](https://clickhouse.com/comparison/bigquery) - [Redshift](https://clickhouse.com/comparison/redshift) - [Snowflake](https://clickhouse.com/comparison/snowflake) - [Видео](https://clickhouse.com/videos) - [Демонстрация](https://clickhouse.com/demos) - [Цены](https://clickhouse.com/pricing) - [Контакты](https://clickhouse.com/company/contact?loc=nav) [46\.7k](https://github.com/ClickHouse/ClickHouse?utm_source=clickhouse&utm_medium=website&utm_campaign=website-nav) [Поиск`Ctrl``K`](https://clickhouse.com/docs/ru/search) [Sign in](https://console.clickhouse.cloud/signIn?loc=docs-nav-signIn-cta&glxid=cc54624f-a4f6-4e65-adff-0c7278dbe5e7&pagePath=%2Fdocs%2Fru%2Fsql-reference%2Fstatements%2Fselect%2Fgroup-by&origPath=%2Fdocs%2Fru%2Fsql-reference%2Fstatements%2Fselect%2Fgroup-by&utm_ga=GA1.1.65304570.1775509748) [Get started](https://console.clickhouse.cloud/signUp?loc=docs-nav-signUp-cta&glxid=cc54624f-a4f6-4e65-adff-0c7278dbe5e7&pagePath=%2Fdocs%2Fru%2Fsql-reference%2Fstatements%2Fselect%2Fgroup-by&origPath=%2Fdocs%2Fru%2Fsql-reference%2Fstatements%2Fselect%2Fgroup-by&utm_ga=GA1.1.65304570.1775509748) [Начать работу](https://clickhouse.com/docs/ru/introduction-clickhouse) [Cloud](https://clickhouse.com/docs/ru/cloud/overview) [Управление данными](https://clickhouse.com/docs/ru/updating-data) [Администрирование сервера](https://clickhouse.com/docs/ru/guides/manage-and-deploy-index) [Справочник](https://clickhouse.com/docs/ru/sql-reference) [Интеграции](https://clickhouse.com/docs/ru/integrations) [ClickStack](https://clickhouse.com/docs/ru/use-cases/observability/clickstack/overview) [chDB](https://clickhouse.com/docs/ru/chdb) [О продукте](https://clickhouse.com/docs/ru/about) [База знаний](https://clickhouse.com/docs/ru/knowledgebase) [Русский](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by) - [Русский](https://clickhouse.com/docs/sql-reference/statements/select/group-by) - [English](https://clickhouse.com/docs/en/sql-reference/statements/select/group-by) - [日本語](https://clickhouse.com/docs/jp/sql-reference/statements/select/group-by) - [中文](https://clickhouse.com/docs/zh/sql-reference/statements/select/group-by) - [한국어](https://clickhouse.com/docs/ko/sql-reference/statements/select/group-by) [Перейти к основному содержимому](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#__docusaurus_skipToContent_fallback) [![ClickHouse](https://clickhouse.com/docs/ru/img/ch_logo_docs.svg)](https://clickhouse.com/) - [Продукты](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by) - [ClickHouse Cloud Оптимальный способ работы с ClickHouse. Доступно в AWS, GCP и Azure.](https://clickhouse.com/cloud) - [ClickHouse Разверните базу данных с помощью открытой версии ClickHouse. ClickHouse](https://clickhouse.com/clickhouse) - [Ознакомьтесь с более чем 100 интеграциями.](https://clickhouse.com/integrations) [Ознакомьтесь с более чем 100 интеграциями.](https://clickhouse.com/integrations) - [Сценарии использования](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by) - [Аналитика в режиме реального времени](https://clickhouse.com/use-cases/real-time-analytics) - [Машинное обучение и генеративный ИИ](https://clickhouse.com/use-cases/machine-learning-and-data-science) - [Бизнес-аналитика](https://clickhouse.com/use-cases/data-warehousing) - [Логи, события и трейсы](https://clickhouse.com/use-cases/observability) - [Все сценарии использования](https://clickhouse.com/use-cases) [Все сценарии использования](https://clickhouse.com/use-cases) - [Документация](https://clickhouse.com/docs) - [Ресурсы](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by) - [Блог](https://clickhouse.com/blog) - [Events](https://clickhouse.com/company/events) - [Learning and certification](https://clickhouse.com/learn) - [Сравнение](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by) - [BigQuery](https://clickhouse.com/comparison/bigquery) - [Redshift](https://clickhouse.com/comparison/redshift) - [Snowflake](https://clickhouse.com/comparison/snowflake) - [Видео](https://clickhouse.com/videos) - [Демонстрация](https://clickhouse.com/demos) - [Цены](https://clickhouse.com/pricing) - [Контакты](https://clickhouse.com/company/contact?loc=nav) [46\.7k](https://github.com/ClickHouse/ClickHouse?utm_source=clickhouse&utm_medium=website&utm_campaign=website-nav) [Поиск`Ctrl``K`](https://clickhouse.com/docs/ru/search) [Sign in](https://console.clickhouse.cloud/signIn?loc=docs-nav-signIn-cta&glxid=cc54624f-a4f6-4e65-adff-0c7278dbe5e7&pagePath=%2Fdocs%2Fru%2Fsql-reference%2Fstatements%2Fselect%2Fgroup-by&origPath=%2Fdocs%2Fru%2Fsql-reference%2Fstatements%2Fselect%2Fgroup-by&utm_ga=GA1.1.65304570.1775509748) [Get started](https://console.clickhouse.cloud/signUp?loc=docs-nav-signUp-cta&glxid=cc54624f-a4f6-4e65-adff-0c7278dbe5e7&pagePath=%2Fdocs%2Fru%2Fsql-reference%2Fstatements%2Fselect%2Fgroup-by&origPath=%2Fdocs%2Fru%2Fsql-reference%2Fstatements%2Fselect%2Fgroup-by&utm_ga=GA1.1.65304570.1775509748) [Начать работу](https://clickhouse.com/docs/ru/introduction-clickhouse) [Cloud](https://clickhouse.com/docs/ru/cloud/overview) [Управление данными](https://clickhouse.com/docs/ru/updating-data) [Администрирование сервера](https://clickhouse.com/docs/ru/guides/manage-and-deploy-index) [Справочник](https://clickhouse.com/docs/ru/sql-reference) [Интеграции](https://clickhouse.com/docs/ru/integrations) [ClickStack](https://clickhouse.com/docs/ru/use-cases/observability/clickstack/overview) [chDB](https://clickhouse.com/docs/ru/chdb) [О продукте](https://clickhouse.com/docs/ru/about) [База знаний](https://clickhouse.com/docs/ru/knowledgebase) [Русский](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by) - [Русский](https://clickhouse.com/docs/sql-reference/statements/select/group-by) - [English](https://clickhouse.com/docs/en/sql-reference/statements/select/group-by) - [日本語](https://clickhouse.com/docs/jp/sql-reference/statements/select/group-by) - [中文](https://clickhouse.com/docs/zh/sql-reference/statements/select/group-by) - [한국어](https://clickhouse.com/docs/ko/sql-reference/statements/select/group-by) [Поиск`Ctrl``K`](https://clickhouse.com/docs/ru/search) - [Введение](https://clickhouse.com/docs/ru/sql-reference) - [Синтаксис](https://clickhouse.com/docs/ru/sql-reference/syntax) - [Форматы ввода и вывода данных](https://clickhouse.com/docs/ru/sql-reference/formats) - [Типы данных](https://clickhouse.com/docs/ru/sql-reference/data-types) - [Команды](https://clickhouse.com/docs/ru/sql-reference/statements) - [SELECT](https://clickhouse.com/docs/ru/sql-reference/statements/select) - [ALL](https://clickhouse.com/docs/ru/sql-reference/statements/select/all) - [APPLY](https://clickhouse.com/docs/ru/sql-reference/statements/select/apply-modifier) - [ARRAY JOIN](https://clickhouse.com/docs/ru/sql-reference/statements/select/array-join) - [DISTINCT](https://clickhouse.com/docs/ru/sql-reference/statements/select/distinct) - [EXCEPT](https://clickhouse.com/docs/ru/sql-reference/statements/select/except) - [EXCEPT](https://clickhouse.com/docs/ru/sql-reference/statements/select/except-modifier) - [FORMAT](https://clickhouse.com/docs/ru/sql-reference/statements/select/format) - [FROM](https://clickhouse.com/docs/ru/sql-reference/statements/select/from) - [GROUP BY](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by) - [HAVING](https://clickhouse.com/docs/ru/sql-reference/statements/select/having) - [INTERSECT](https://clickhouse.com/docs/ru/sql-reference/statements/select/intersect) - [INTO OUTFILE](https://clickhouse.com/docs/ru/sql-reference/statements/select/into-outfile) - [JOIN](https://clickhouse.com/docs/ru/sql-reference/statements/select/join) - [LIMIT BY](https://clickhouse.com/docs/ru/sql-reference/statements/select/limit-by) - [LIMIT](https://clickhouse.com/docs/ru/sql-reference/statements/select/limit) - [OFFSET](https://clickhouse.com/docs/ru/sql-reference/statements/select/offset) - [ORDER BY](https://clickhouse.com/docs/ru/sql-reference/statements/select/order-by) - [PREWHERE](https://clickhouse.com/docs/ru/sql-reference/statements/select/prewhere) - [QUALIFY](https://clickhouse.com/docs/ru/sql-reference/statements/select/qualify) - [REPLACE](https://clickhouse.com/docs/ru/sql-reference/statements/select/replace-modifier) - [SAMPLE](https://clickhouse.com/docs/ru/sql-reference/statements/select/sample) - [UNION](https://clickhouse.com/docs/ru/sql-reference/statements/select/union) - [WHERE](https://clickhouse.com/docs/ru/sql-reference/statements/select/where) - [WITH](https://clickhouse.com/docs/ru/sql-reference/statements/select/with) - [INSERT INTO](https://clickhouse.com/docs/ru/sql-reference/statements/insert-into) - [CREATE](https://clickhouse.com/docs/ru/sql-reference/statements/create) - [ALTER](https://clickhouse.com/docs/ru/sql-reference/statements/alter) - [DELETE](https://clickhouse.com/docs/ru/sql-reference/statements/delete) - [SYSTEM](https://clickhouse.com/docs/ru/sql-reference/statements/system) - [SHOW](https://clickhouse.com/docs/ru/sql-reference/statements/show) - [GRANT](https://clickhouse.com/docs/ru/sql-reference/statements/grant) - [EXPLAIN](https://clickhouse.com/docs/ru/sql-reference/statements/explain) - [REVOKE](https://clickhouse.com/docs/ru/sql-reference/statements/revoke) - [UPDATE](https://clickhouse.com/docs/ru/sql-reference/statements/update) - [ATTACH](https://clickhouse.com/docs/ru/sql-reference/statements/attach) - [CHECK TABLE](https://clickhouse.com/docs/ru/sql-reference/statements/check-table) - [DESCRIBE TABLE](https://clickhouse.com/docs/ru/sql-reference/statements/describe-table) - [DETACH](https://clickhouse.com/docs/ru/sql-reference/statements/detach) - [DROP](https://clickhouse.com/docs/ru/sql-reference/statements/drop) - [EXISTS](https://clickhouse.com/docs/ru/sql-reference/statements/exists) - [KILL](https://clickhouse.com/docs/ru/sql-reference/statements/kill) - [OPTIMIZE](https://clickhouse.com/docs/ru/sql-reference/statements/optimize) - [RENAME](https://clickhouse.com/docs/ru/sql-reference/statements/rename) - [EXCHANGE](https://clickhouse.com/docs/ru/sql-reference/statements/exchange) - [SET](https://clickhouse.com/docs/ru/sql-reference/statements/set) - [SET ROLE](https://clickhouse.com/docs/ru/sql-reference/statements/set-role) - [TRUNCATE](https://clickhouse.com/docs/ru/sql-reference/statements/truncate) - [EXECUTE AS](https://clickhouse.com/docs/ru/sql-reference/statements/execute_as) - [PARALLEL WITH](https://clickhouse.com/docs/ru/sql-reference/statements/parallel_with) - [USE](https://clickhouse.com/docs/ru/sql-reference/statements/use) - [WATCH](https://clickhouse.com/docs/ru/sql-reference/statements/watch) - [MOVE](https://clickhouse.com/docs/ru/sql-reference/statements/move) - [CHECK GRANT](https://clickhouse.com/docs/ru/sql-reference/statements/check-grant) - [UNDROP](https://clickhouse.com/docs/ru/sql-reference/statements/undrop) - [Операторы](https://clickhouse.com/docs/ru/sql-reference/operators) - [Движки](https://clickhouse.com/docs/ru/engines) - [Движки баз данных](https://clickhouse.com/docs/ru/engines/database-engines) - [Движки таблиц](https://clickhouse.com/docs/ru/engines/table-engines) - [Функции](https://clickhouse.com/docs/ru/sql-reference/functions) - [Обычные функции](https://clickhouse.com/docs/ru/sql-reference/functions/regular-functions) - [Агрегатные функции](https://clickhouse.com/docs/ru/sql-reference/aggregate-functions) - [Табличные функции](https://clickhouse.com/docs/ru/sql-reference/table-functions) - [Оконные функции](https://clickhouse.com/docs/ru/sql-reference/window-functions) - [Форматы](https://clickhouse.com/docs/ru/interfaces/formats) - [Озера данных](https://clickhouse.com/docs/ru/sql-reference/datalakes) - [Введение](https://clickhouse.com/docs/ru/sql-reference) - [Команды](https://clickhouse.com/docs/ru/sql-reference/statements) - [SELECT](https://clickhouse.com/docs/ru/sql-reference/statements/select) - GROUP BY ###### Этот документ переведён с помощью ИИ. Нашли ошибку в переводе? Сообщите о ней и помогите нам улучшить документацию. [Сообщить о проблеме](https://github.com/ClickHouse/clickhouse-docs/issues/new?template=translation_issue.yaml) # Оператор GROUP BY Оператор `GROUP BY` переводит запрос `SELECT` в режим агрегации, который работает следующим образом: - Оператор `GROUP BY` содержит список выражений (или одно выражение, которое рассматривается как список длины один). Этот список выступает в роли "ключа группировки", а каждое отдельное выражение далее называется "ключевым выражением". - Все выражения в операторах [SELECT](https://clickhouse.com/docs/ru/sql-reference/statements/select), [HAVING](https://clickhouse.com/docs/ru/sql-reference/statements/select/having) и [ORDER BY](https://clickhouse.com/docs/ru/sql-reference/statements/select/order-by) **должны** вычисляться на основе ключевых выражений **или** на основе [агрегатных функций](https://clickhouse.com/docs/ru/sql-reference/aggregate-functions) над неклю́чевыми выражениями (включая обычные столбцы). Другими словами, каждый столбец, выбранный из таблицы, должен использоваться либо в ключевом выражении, либо внутри агрегатной функции, но не одновременно в обоих местах. - Результат агрегирующего запроса `SELECT` будет содержать столько строк, сколько было уникальных значений "ключа группировки" в исходной таблице. Обычно это существенно уменьшает число строк, зачастую на порядки, но не обязательно: количество строк останется прежним, если все значения "ключа группировки" были различны. Если нужно группировать данные в таблице по номерам столбцов вместо их имен, включите настройку [enable\_positional\_arguments](https://clickhouse.com/docs/ru/operations/settings/settings#enable_positional_arguments). Примечание Существует дополнительный способ выполнения агрегации над таблицей. Если в запросе столбцы таблицы встречаются только внутри агрегатных функций, оператор `GROUP BY` можно опустить, и будет подразумеваться агрегация по пустому набору ключей. Такие запросы всегда возвращают ровно одну строку. ## Обработка NULL[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#null-processing "Прямая ссылка на Обработка NULL") При группировке ClickHouse интерпретирует [NULL](https://clickhouse.com/docs/ru/sql-reference/syntax#null) как значение, и `NULL == NULL`. Это отличается от обработки `NULL` в большинстве других контекстов. Ниже приведён пример, иллюстрирующий это. Предположим, у вас есть следующая таблица: ``` ┌─x─┬────y─┐ │ 1 │ 2 │ │ 2 │ ᴺᵁᴸᴸ │ │ 3 │ 2 │ │ 3 │ 3 │ │ 3 │ ᴺᵁᴸᴸ │ └───┴──────┘ ``` Запрос `SELECT sum(x), y FROM t_null_big GROUP BY y` приводит к следующему результату: ``` ┌─sum(x)─┬────y─┐ │ 4 │ 2 │ │ 3 │ 3 │ │ 5 │ ᴺᵁᴸᴸ │ └────────┴──────┘ ``` Видно, что `GROUP BY` для `y = NULL` суммировал `x` так, как если бы `NULL` было этим значением. Если указать в `GROUP BY` несколько ключей, в результате вы получите все комбинации выборки, как если бы `NULL` рассматривался как конкретное значение. ## Модификатор ROLLUP[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#rollup-modifier "Прямая ссылка на Модификатор ROLLUP") Модификатор `ROLLUP` используется для вычисления промежуточных итогов для ключевых выражений в соответствии с их порядком в списке `GROUP BY`. Строки с промежуточными итогами добавляются после результирующей таблицы. Промежуточные итоги вычисляются в обратном порядке: сначала — для последнего ключевого выражения в списке, затем для предыдущего и так далее до первого ключевого выражения. В строках с промежуточными итогами значения уже «сгруппированных» ключевых выражений устанавливаются в значение `0` или пустую строку. Примечание Имейте в виду, что предложение [HAVING](https://clickhouse.com/docs/ru/sql-reference/statements/select/having) может повлиять на результаты промежуточных итогов. **Пример** Рассмотрим таблицу t: ``` ┌─year─┬─month─┬─day─┐ │ 2019 │ 1 │ 5 │ │ 2019 │ 1 │ 15 │ │ 2020 │ 1 │ 5 │ │ 2020 │ 1 │ 15 │ │ 2020 │ 10 │ 5 │ │ 2020 │ 10 │ 15 │ └──────┴───────┴─────┘ ``` Запрос: ``` SELECT year, month, day, count(*) FROM t GROUP BY ROLLUP(year, month, day); ``` Поскольку секция `GROUP BY` содержит три ключевых выражения, результат включает четыре таблицы с промежуточными итогами, «свёрнутыми» справа налево: - `GROUP BY year, month, day`; - `GROUP BY year, month` (и столбец `day` заполняется нулями); - `GROUP BY year` (теперь оба столбца `month` и `day` заполняются нулями); - и общие итоги (и все три столбца с ключевыми выражениями заполнены нулями). ``` ┌─year─┬─month─┬─day─┬─count()─┐ │ 2020 │ 10 │ 15 │ 1 │ │ 2020 │ 1 │ 5 │ 1 │ │ 2019 │ 1 │ 5 │ 1 │ │ 2020 │ 1 │ 15 │ 1 │ │ 2019 │ 1 │ 15 │ 1 │ │ 2020 │ 10 │ 5 │ 1 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 2019 │ 1 │ 0 │ 2 │ │ 2020 │ 1 │ 0 │ 2 │ │ 2020 │ 10 │ 0 │ 2 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 2019 │ 0 │ 0 │ 2 │ │ 2020 │ 0 │ 0 │ 4 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 0 │ 0 │ 0 │ 6 │ └──────┴───────┴─────┴─────────┘ ``` Этот же запрос можно записать и с использованием ключевого слова `WITH`. ``` SELECT year, month, day, count(*) FROM t GROUP BY year, month, day WITH ROLLUP; ``` **См. также** - Параметр [group\_by\_use\_nulls](https://clickhouse.com/docs/ru/operations/settings/settings#group_by_use_nulls) для обеспечения совместимости со стандартом SQL. ## Модификатор CUBE[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#cube-modifier "Прямая ссылка на Модификатор CUBE") Модификатор `CUBE` используется для вычисления промежуточных итогов для каждой комбинации ключевых выражений в списке `GROUP BY`. Строки с промежуточными итогами добавляются после результирующей таблицы. В строках с промежуточными итогами значения всех «сгруппированных» ключевых выражений устанавливаются в `0` или пустую строку. Примечание Имейте в виду, что предложение [HAVING](https://clickhouse.com/docs/ru/sql-reference/statements/select/having) может влиять на результаты промежуточных итогов. **Пример** Рассмотрим таблицу t: ``` ┌─year─┬─month─┬─day─┐ │ 2019 │ 1 │ 5 │ │ 2019 │ 1 │ 15 │ │ 2020 │ 1 │ 5 │ │ 2020 │ 1 │ 15 │ │ 2020 │ 10 │ 5 │ │ 2020 │ 10 │ 15 │ └──────┴───────┴─────┘ ``` Запрос: ``` SELECT year, month, day, count(*) FROM t GROUP BY CUBE(year, month, day); ``` Так как секция `GROUP BY` содержит три ключевых выражения, результат содержит восемь таблиц с промежуточными итогами для всех комбинаций ключевых выражений: - `GROUP BY year, month, day` - `GROUP BY year, month` - `GROUP BY year, day` - `GROUP BY year` - `GROUP BY month, day` - `GROUP BY month` - `GROUP BY day` - и общие итоги. Столбцы, не включённые в `GROUP BY`, заполняются нулями. ``` ┌─year─┬─month─┬─day─┬─count()─┐ │ 2020 │ 10 │ 15 │ 1 │ │ 2020 │ 1 │ 5 │ 1 │ │ 2019 │ 1 │ 5 │ 1 │ │ 2020 │ 1 │ 15 │ 1 │ │ 2019 │ 1 │ 15 │ 1 │ │ 2020 │ 10 │ 5 │ 1 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 2019 │ 1 │ 0 │ 2 │ │ 2020 │ 1 │ 0 │ 2 │ │ 2020 │ 10 │ 0 │ 2 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 2020 │ 0 │ 5 │ 2 │ │ 2019 │ 0 │ 5 │ 1 │ │ 2020 │ 0 │ 15 │ 2 │ │ 2019 │ 0 │ 15 │ 1 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 2019 │ 0 │ 0 │ 2 │ │ 2020 │ 0 │ 0 │ 4 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 0 │ 1 │ 5 │ 2 │ │ 0 │ 10 │ 15 │ 1 │ │ 0 │ 10 │ 5 │ 1 │ │ 0 │ 1 │ 15 │ 2 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 0 │ 1 │ 0 │ 4 │ │ 0 │ 10 │ 0 │ 2 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 0 │ 0 │ 5 │ 3 │ │ 0 │ 0 │ 15 │ 3 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 0 │ 0 │ 0 │ 6 │ └──────┴───────┴─────┴─────────┘ ``` Тот же запрос можно записать и с использованием ключевого слова `WITH`. ``` SELECT year, month, day, count(*) FROM t GROUP BY year, month, day WITH CUBE; ``` **См. также** - Настройка [group\_by\_use\_nulls](https://clickhouse.com/docs/ru/operations/settings/settings#group_by_use_nulls) для совместимости со стандартом SQL. ## Модификатор WITH TOTALS[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#with-totals-modifier "Прямая ссылка на Модификатор WITH TOTALS") Если указан модификатор `WITH TOTALS`, будет вычислена дополнительная строка. В этой строке ключевые столбцы будут содержать значения по умолчанию (нули или пустые строки), а столбцы с агрегирующими функциями — значения, вычисленные по всем строкам (итоговые значения). Эта дополнительная строка создаётся только в форматах `JSON*`, `TabSeparated*` и `Pretty*`, отдельно от остальных строк: - В форматах `XML` и `JSON*` эта строка выводится как отдельное поле `totals`. - В форматах `TabSeparated*`, `CSV*` и `Vertical` строка следует после основного результата, предваряемая пустой строкой (после остальных данных). - В форматах `Pretty*` строка выводится как отдельная таблица после основного результата. - В формате `Template` строка выводится в соответствии с указанным шаблоном. - В остальных форматах она недоступна. Примечание `totals` выводится в результатах запросов `SELECT` и не выводится в `INSERT INTO ... SELECT`. `WITH TOTALS` может работать по-разному, когда присутствует [HAVING](https://clickhouse.com/docs/ru/sql-reference/statements/select/having). Поведение зависит от настройки `totals_mode`. ### Настройка обработки `totals`[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#configuring-totals-processing "Прямая ссылка на configuring-totals-processing") По умолчанию `totals_mode = 'before_having'`. В этом случае `totals` вычисляется по всем строкам, включая те, которые не проходят по условиям HAVING и `max_rows_to_group_by`. Другие варианты включают в `totals` только строки, прошедшие через HAVING, и по-разному ведут себя при настройках `max_rows_to_group_by` и `group_by_overflow_mode = 'any'`. `after_having_exclusive` – не включать строки, которые не прошли через `max_rows_to_group_by`. Другими словами, в `totals` будет меньше или столько же строк, сколько было бы, если бы `max_rows_to_group_by` был опущен. `after_having_inclusive` – включать в `totals` все строки, которые не прошли через `max_rows_to_group_by`. Другими словами, в `totals` будет больше или столько же строк, сколько было бы, если бы `max_rows_to_group_by` был опущен. `after_having_auto` – подсчитать количество строк, прошедших через HAVING. Если оно больше определённого порога (по умолчанию 50%), включить в `totals` все строки, которые не прошли через `max_rows_to_group_by`. В противном случае не включать их. `totals_auto_threshold` – по умолчанию 0.5. Коэффициент для `after_having_auto`. Если `max_rows_to_group_by` и `group_by_overflow_mode = 'any'` не используются, все варианты `after_having` эквивалентны, и можно использовать любой из них (например, `after_having_auto`). Вы можете использовать `WITH TOTALS` во вложенных подзапросах, включая подзапросы в предложении [JOIN](https://clickhouse.com/docs/ru/sql-reference/statements/select/join) (в этом случае соответствующие итоговые значения объединяются). ## GROUP BY ALL[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#group-by-all "Прямая ссылка на GROUP BY ALL") `GROUP BY ALL` эквивалентен перечислению в предложении SELECT всех выражений, которые не являются агрегатными функциями. Например: ``` SELECT a * 2, b, count(c), FROM t GROUP BY ALL ``` то же самое, что ``` SELECT a * 2, b, count(c), FROM t GROUP BY a * 2, b ``` В особом случае, когда есть функция, в которой в качестве аргументов используются и агрегатные функции, и другие поля, ключи `GROUP BY` будут содержать максимально возможное число неагрегатных полей, которые можно из этой функции извлечь. Например: ``` SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY ALL ``` то же самое, что ``` SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY substring(a, 4, 2), substring(a, 1, 2) ``` ## Примеры[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#examples "Прямая ссылка на Примеры") Пример: ``` SELECT count(), median(FetchTiming > 60 ? 60 : FetchTiming), count() - sum(Refresh) FROM hits ``` В отличие от MySQL (и в соответствии со стандартом SQL), вы не можете получить значение столбца, не участвующего ни в ключе, ни в агрегатной функции (за исключением константных выражений). В качестве обходного решения можно использовать агрегатную функцию `any` (получить первое встретившееся значение) или `min/max`. Пример: ``` SELECT domainWithoutWWW(URL) AS domain, count(), any(Title) AS title -- getting the first occurred page header for each domain. FROM hits GROUP BY domain ``` Для каждого различного значения ключа оператор `GROUP BY` вычисляет набор значений агрегатных функций. ## Модификатор GROUPING SETS[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#grouping-sets-modifier "Прямая ссылка на Модификатор GROUPING SETS") Это самый общий модификатор. Он позволяет вручную задавать несколько наборов ключей агрегации (grouping sets). Агрегация выполняется отдельно для каждого grouping set, после чего все результаты объединяются. Если столбец не входит в grouping set, он заполняется значением по умолчанию. Другими словами, модификаторы, описанные выше, могут быть выражены с помощью `GROUPING SETS`. Несмотря на то, что запросы с модификаторами `ROLLUP`, `CUBE` и `GROUPING SETS` синтаксически эквивалентны, их производительность может отличаться. Когда `GROUPING SETS` старается выполнять все варианты агрегации параллельно, `ROLLUP` и `CUBE` выполняют финальное слияние агрегатов в одном потоке. В ситуации, когда исходные столбцы содержат значения по умолчанию, может быть сложно определить, является ли строка частью агрегации, в которой эти столбцы используются как ключи, или нет. Чтобы решить эту проблему, необходимо использовать функцию `GROUPING`. **Пример** Следующие два запроса эквивалентны. ``` -- Query 1 SELECT year, month, day, count(*) FROM t GROUP BY year, month, day WITH ROLLUP; -- Query 2 SELECT year, month, day, count(*) FROM t GROUP BY GROUPING SETS ( (year, month, day), (year, month), (year), () ); ``` **См. также** - настройку [group\_by\_use\_nulls](https://clickhouse.com/docs/ru/operations/settings/settings#group_by_use_nulls) для обеспечения совместимости со стандартом SQL. ## Подробности реализации[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#implementation-details "Прямая ссылка на Подробности реализации") Агрегация — одна из важнейших функций колоночной СУБД, и, следовательно, её реализация является одной из наиболее оптимизированных частей ClickHouse. По умолчанию агрегация выполняется в памяти с использованием хеш-таблицы. Для неё существует более 40 специализаций, которые выбираются автоматически в зависимости от типов данных «ключа группировки». ### Оптимизация GROUP BY в зависимости от сортировочного ключа таблицы[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#group-by-optimization-depending-on-table-sorting-key "Прямая ссылка на Оптимизация GROUP BY в зависимости от сортировочного ключа таблицы") Агрегацию можно выполнять более эффективно, если таблица отсортирована по некоторому ключу, а выражение `GROUP BY` содержит как минимум префикс сортировочного ключа или инъективные функции. В этом случае, когда из таблицы читается новый ключ, промежуточный результат агрегации может быть финализирован и отправлен клиенту. Такое поведение включается настройкой [optimize\_aggregation\_in\_order](https://clickhouse.com/docs/ru/operations/settings/settings#optimize_aggregation_in_order). Подобная оптимизация снижает потребление памяти во время агрегации, но в некоторых случаях может замедлить выполнение запроса. ### GROUP BY во внешней памяти[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#group-by-in-external-memory "Прямая ссылка на GROUP BY во внешней памяти") Вы можете включить сброс временных данных на диск, чтобы ограничить использование памяти во время `GROUP BY`. Настройка [max\_bytes\_before\_external\_group\_by](https://clickhouse.com/docs/ru/operations/settings/settings#max_bytes_before_external_group_by) определяет порог потребления ОЗУ, при достижении которого временные данные `GROUP BY` начинают сбрасываться в файловую систему. Если установлено значение 0 (по умолчанию), механизм отключён. В качестве альтернативы вы можете задать [max\_bytes\_ratio\_before\_external\_group\_by](https://clickhouse.com/docs/ru/operations/settings/settings#max_bytes_ratio_before_external_group_by), что позволяет задействовать внешнюю память для `GROUP BY` только после того, как запрос достигнет определённого порога использованной памяти. При использовании `max_bytes_before_external_group_by` мы рекомендуем установить `max_memory_usage` примерно вдвое выше (или `max_bytes_ratio_before_external_group_by=0.5`). Это необходимо, потому что агрегация состоит из двух этапов: чтение данных и формирование промежуточных данных (1) и слияние промежуточных данных (2). Сброс данных в файловую систему может происходить только на этапе 1. Если временные данные не были сброшены, то на этапе 2 может потребоваться до такого же объёма памяти, как и на этапе 1. Например, если [max\_memory\_usage](https://clickhouse.com/docs/ru/operations/settings/settings#max_memory_usage) было установлено в 10000000000 и вы хотите использовать внешнюю агрегацию, имеет смысл задать `max_bytes_before_external_group_by` равным 10000000000, а `max_memory_usage` — 20000000000. Когда внешняя агрегация срабатывает (если был хотя бы один сброс временных данных), максимальное потребление ОЗУ лишь немного превышает `max_bytes_before_external_group_by`. При распределённой обработке запросов внешняя агрегация выполняется на удалённых серверах. Чтобы сервер, инициирующий запрос, использовал лишь небольшое количество ОЗУ, установите `distributed_aggregation_memory_efficient` в 1. При слиянии данных, сброшенных на диск, а также при слиянии результатов с удалённых серверов при включённой настройке `distributed_aggregation_memory_efficient`, используется до `1/256 * число_потоков` от общего объёма ОЗУ. Когда внешняя агрегация включена, если объём данных меньше `max_bytes_before_external_group_by` (то есть данные не были сброшены), запрос выполняется так же быстро, как и без внешней агрегации. Если какие-либо временные данные были сброшены, время выполнения будет в несколько раз больше (примерно в три раза). Если после `GROUP BY` используется [ORDER BY](https://clickhouse.com/docs/ru/sql-reference/statements/select/order-by) с [LIMIT](https://clickhouse.com/docs/ru/sql-reference/statements/select/limit), то объём используемой ОЗУ зависит от количества данных в `LIMIT`, а не во всей таблице. Но если у `ORDER BY` нет `LIMIT`, не забудьте включить внешнюю сортировку (`max_bytes_before_external_sort`). [Назад FROM](https://clickhouse.com/docs/ru/sql-reference/statements/select/from) [Далее HAVING](https://clickhouse.com/docs/ru/sql-reference/statements/select/having) - [Обработка NULL](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#null-processing) - [Модификатор ROLLUP](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#rollup-modifier) - [Модификатор CUBE](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#cube-modifier) - [Модификатор WITH TOTALS](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#with-totals-modifier) - [Настройка обработки `totals`](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#configuring-totals-processing) - [GROUP BY ALL](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#group-by-all) - [Примеры](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#examples) - [Модификатор GROUPING SETS](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#grouping-sets-modifier) - [Подробности реализации](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#implementation-details) - [Оптимизация GROUP BY в зависимости от сортировочного ключа таблицы](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#group-by-optimization-depending-on-table-sorting-key) - [GROUP BY во внешней памяти](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#group-by-in-external-memory) Was this page helpful? ###### Try ClickHouse Cloud for FREE Separation of storage and compute, automatic scaling, built-in SQL console, and lots more. \$300 in free credits when signing up. [Try it for Free](https://console.clickhouse.cloud/signUp?loc=doc-card-banner&glxid=cc54624f-a4f6-4e65-adff-0c7278dbe5e7&pagePath=%2Fdocs%2Fru%2Fsql-reference%2Fstatements%2Fselect%2Fgroup-by&origPath=%2Fdocs%2Fru%2Fsql-reference%2Fstatements%2Fselect%2Fgroup-by&utm_ga=GA1.1.65304570.1775509748) © 2016–2026 ClickHouse, Inc. [Товарный знак](https://clickhouse.com/legal/trademark-policy)·[Конфиденциальность](https://clickhouse.com/legal/privacy-policy)·[Безопасность](https://trust.clickhouse.com/)·[Условия использования](https://clickhouse.com/legal/agreements/terms-of-service) ![](https://static.scarf.sh/a.png?x-pxid=e6377503-591b-4886-9398-e69c7fee0b91) © 2016–2026 ClickHouse, Inc. [Товарный знак](https://clickhouse.com/legal/trademark-policy)·[Конфиденциальность](https://clickhouse.com/legal/privacy-policy)·[Безопасность](https://trust.clickhouse.com/)·[Условия использования](https://clickhouse.com/legal/agreements/terms-of-service) ![](https://static.scarf.sh/a.png?x-pxid=e6377503-591b-4886-9398-e69c7fee0b91) [![ClickHouse](https://clickhouse.com/docs/ru/img/ch_logo_docs.svg)](https://clickhouse.com/) RU - Начать работу▼ - Cloud▼ - Управление данными▼ - Администрирование сервера▼ - Справочник▼ - Интеграции▼ - ClickStack▼ - chDB▼ - О продукте▼ [![ClickHouse](https://clickhouse.com/docs/ru/img/ch_logo_docs.svg)](https://clickhouse.com/) RU main-menu - Введение▼ - [Синтаксис](https://clickhouse.com/docs/ru/sql-reference/syntax) - [Форматы ввода и вывода данных](https://clickhouse.com/docs/ru/sql-reference/formats) - Типы данных▼ - Команды▼ - SELECT▼ - [ALL](https://clickhouse.com/docs/ru/sql-reference/statements/select/all) - [APPLY](https://clickhouse.com/docs/ru/sql-reference/statements/select/apply-modifier) - [ARRAY JOIN](https://clickhouse.com/docs/ru/sql-reference/statements/select/array-join) - [DISTINCT](https://clickhouse.com/docs/ru/sql-reference/statements/select/distinct) - [EXCEPT](https://clickhouse.com/docs/ru/sql-reference/statements/select/except) - [EXCEPT](https://clickhouse.com/docs/ru/sql-reference/statements/select/except-modifier) - [FORMAT](https://clickhouse.com/docs/ru/sql-reference/statements/select/format) - [FROM](https://clickhouse.com/docs/ru/sql-reference/statements/select/from) - [GROUP BY](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by) - [HAVING](https://clickhouse.com/docs/ru/sql-reference/statements/select/having) - [INTERSECT](https://clickhouse.com/docs/ru/sql-reference/statements/select/intersect) - [INTO OUTFILE](https://clickhouse.com/docs/ru/sql-reference/statements/select/into-outfile) - [JOIN](https://clickhouse.com/docs/ru/sql-reference/statements/select/join) - [LIMIT BY](https://clickhouse.com/docs/ru/sql-reference/statements/select/limit-by) - [LIMIT](https://clickhouse.com/docs/ru/sql-reference/statements/select/limit) - [OFFSET](https://clickhouse.com/docs/ru/sql-reference/statements/select/offset) - [ORDER BY](https://clickhouse.com/docs/ru/sql-reference/statements/select/order-by) - [PREWHERE](https://clickhouse.com/docs/ru/sql-reference/statements/select/prewhere) - [QUALIFY](https://clickhouse.com/docs/ru/sql-reference/statements/select/qualify) - [REPLACE](https://clickhouse.com/docs/ru/sql-reference/statements/select/replace-modifier) - [SAMPLE](https://clickhouse.com/docs/ru/sql-reference/statements/select/sample) - [UNION](https://clickhouse.com/docs/ru/sql-reference/statements/select/union) - [WHERE](https://clickhouse.com/docs/ru/sql-reference/statements/select/where) - [WITH](https://clickhouse.com/docs/ru/sql-reference/statements/select/with) - [INSERT INTO](https://clickhouse.com/docs/ru/sql-reference/statements/insert-into) - CREATE▼ - ALTER▼ - [DELETE](https://clickhouse.com/docs/ru/sql-reference/statements/delete) - [SYSTEM](https://clickhouse.com/docs/ru/sql-reference/statements/system) - [SHOW](https://clickhouse.com/docs/ru/sql-reference/statements/show) - [GRANT](https://clickhouse.com/docs/ru/sql-reference/statements/grant) - [EXPLAIN](https://clickhouse.com/docs/ru/sql-reference/statements/explain) - [REVOKE](https://clickhouse.com/docs/ru/sql-reference/statements/revoke) - [UPDATE](https://clickhouse.com/docs/ru/sql-reference/statements/update) - [ATTACH](https://clickhouse.com/docs/ru/sql-reference/statements/attach) - [CHECK TABLE](https://clickhouse.com/docs/ru/sql-reference/statements/check-table) - [DESCRIBE TABLE](https://clickhouse.com/docs/ru/sql-reference/statements/describe-table) - [DETACH](https://clickhouse.com/docs/ru/sql-reference/statements/detach) - [DROP](https://clickhouse.com/docs/ru/sql-reference/statements/drop) - [EXISTS](https://clickhouse.com/docs/ru/sql-reference/statements/exists) - [KILL](https://clickhouse.com/docs/ru/sql-reference/statements/kill) - [OPTIMIZE](https://clickhouse.com/docs/ru/sql-reference/statements/optimize) - [RENAME](https://clickhouse.com/docs/ru/sql-reference/statements/rename) - [EXCHANGE](https://clickhouse.com/docs/ru/sql-reference/statements/exchange) - [SET](https://clickhouse.com/docs/ru/sql-reference/statements/set) - [SET ROLE](https://clickhouse.com/docs/ru/sql-reference/statements/set-role) - [TRUNCATE](https://clickhouse.com/docs/ru/sql-reference/statements/truncate) - [EXECUTE AS](https://clickhouse.com/docs/ru/sql-reference/statements/execute_as) - [PARALLEL WITH](https://clickhouse.com/docs/ru/sql-reference/statements/parallel_with) - [USE](https://clickhouse.com/docs/ru/sql-reference/statements/use) - [WATCH](https://clickhouse.com/docs/ru/sql-reference/statements/watch) - [MOVE](https://clickhouse.com/docs/ru/sql-reference/statements/move) - [CHECK GRANT](https://clickhouse.com/docs/ru/sql-reference/statements/check-grant) - [UNDROP](https://clickhouse.com/docs/ru/sql-reference/statements/undrop) - Операторы▼ - Движки▼ - Функции▼ - Форматы▼ - [Озера данных](https://clickhouse.com/docs/ru/sql-reference/datalakes)
Readable Markdown
Оператор `GROUP BY` переводит запрос `SELECT` в режим агрегации, который работает следующим образом: - Оператор `GROUP BY` содержит список выражений (или одно выражение, которое рассматривается как список длины один). Этот список выступает в роли "ключа группировки", а каждое отдельное выражение далее называется "ключевым выражением". - Все выражения в операторах [SELECT](https://clickhouse.com/docs/ru/sql-reference/statements/select), [HAVING](https://clickhouse.com/docs/ru/sql-reference/statements/select/having) и [ORDER BY](https://clickhouse.com/docs/ru/sql-reference/statements/select/order-by) **должны** вычисляться на основе ключевых выражений **или** на основе [агрегатных функций](https://clickhouse.com/docs/ru/sql-reference/aggregate-functions) над неклю́чевыми выражениями (включая обычные столбцы). Другими словами, каждый столбец, выбранный из таблицы, должен использоваться либо в ключевом выражении, либо внутри агрегатной функции, но не одновременно в обоих местах. - Результат агрегирующего запроса `SELECT` будет содержать столько строк, сколько было уникальных значений "ключа группировки" в исходной таблице. Обычно это существенно уменьшает число строк, зачастую на порядки, но не обязательно: количество строк останется прежним, если все значения "ключа группировки" были различны. Если нужно группировать данные в таблице по номерам столбцов вместо их имен, включите настройку [enable\_positional\_arguments](https://clickhouse.com/docs/ru/operations/settings/settings#enable_positional_arguments). Примечание Существует дополнительный способ выполнения агрегации над таблицей. Если в запросе столбцы таблицы встречаются только внутри агрегатных функций, оператор `GROUP BY` можно опустить, и будет подразумеваться агрегация по пустому набору ключей. Такие запросы всегда возвращают ровно одну строку. ## Обработка NULL[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#null-processing "Прямая ссылка на Обработка NULL") При группировке ClickHouse интерпретирует [NULL](https://clickhouse.com/docs/ru/sql-reference/syntax#null) как значение, и `NULL == NULL`. Это отличается от обработки `NULL` в большинстве других контекстов. Ниже приведён пример, иллюстрирующий это. Предположим, у вас есть следующая таблица: ``` ┌─x─┬────y─┐ │ 1 │ 2 │ │ 2 │ ᴺᵁᴸᴸ │ │ 3 │ 2 │ │ 3 │ 3 │ │ 3 │ ᴺᵁᴸᴸ │ └───┴──────┘ ``` Запрос `SELECT sum(x), y FROM t_null_big GROUP BY y` приводит к следующему результату: ``` ┌─sum(x)─┬────y─┐ │ 4 │ 2 │ │ 3 │ 3 │ │ 5 │ ᴺᵁᴸᴸ │ └────────┴──────┘ ``` Видно, что `GROUP BY` для `y = NULL` суммировал `x` так, как если бы `NULL` было этим значением. Если указать в `GROUP BY` несколько ключей, в результате вы получите все комбинации выборки, как если бы `NULL` рассматривался как конкретное значение. ## Модификатор ROLLUP[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#rollup-modifier "Прямая ссылка на Модификатор ROLLUP") Модификатор `ROLLUP` используется для вычисления промежуточных итогов для ключевых выражений в соответствии с их порядком в списке `GROUP BY`. Строки с промежуточными итогами добавляются после результирующей таблицы. Промежуточные итоги вычисляются в обратном порядке: сначала — для последнего ключевого выражения в списке, затем для предыдущего и так далее до первого ключевого выражения. В строках с промежуточными итогами значения уже «сгруппированных» ключевых выражений устанавливаются в значение `0` или пустую строку. Примечание Имейте в виду, что предложение [HAVING](https://clickhouse.com/docs/ru/sql-reference/statements/select/having) может повлиять на результаты промежуточных итогов. **Пример** Рассмотрим таблицу t: ``` ┌─year─┬─month─┬─day─┐ │ 2019 │ 1 │ 5 │ │ 2019 │ 1 │ 15 │ │ 2020 │ 1 │ 5 │ │ 2020 │ 1 │ 15 │ │ 2020 │ 10 │ 5 │ │ 2020 │ 10 │ 15 │ └──────┴───────┴─────┘ ``` Запрос: ``` SELECT year, month, day, count(*) FROM t GROUP BY ROLLUP(year, month, day); ``` Поскольку секция `GROUP BY` содержит три ключевых выражения, результат включает четыре таблицы с промежуточными итогами, «свёрнутыми» справа налево: - `GROUP BY year, month, day`; - `GROUP BY year, month` (и столбец `day` заполняется нулями); - `GROUP BY year` (теперь оба столбца `month` и `day` заполняются нулями); - и общие итоги (и все три столбца с ключевыми выражениями заполнены нулями). ``` ┌─year─┬─month─┬─day─┬─count()─┐ │ 2020 │ 10 │ 15 │ 1 │ │ 2020 │ 1 │ 5 │ 1 │ │ 2019 │ 1 │ 5 │ 1 │ │ 2020 │ 1 │ 15 │ 1 │ │ 2019 │ 1 │ 15 │ 1 │ │ 2020 │ 10 │ 5 │ 1 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 2019 │ 1 │ 0 │ 2 │ │ 2020 │ 1 │ 0 │ 2 │ │ 2020 │ 10 │ 0 │ 2 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 2019 │ 0 │ 0 │ 2 │ │ 2020 │ 0 │ 0 │ 4 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 0 │ 0 │ 0 │ 6 │ └──────┴───────┴─────┴─────────┘ ``` Этот же запрос можно записать и с использованием ключевого слова `WITH`. ``` SELECT year, month, day, count(*) FROM t GROUP BY year, month, day WITH ROLLUP; ``` **См. также** - Параметр [group\_by\_use\_nulls](https://clickhouse.com/docs/ru/operations/settings/settings#group_by_use_nulls) для обеспечения совместимости со стандартом SQL. ## Модификатор CUBE[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#cube-modifier "Прямая ссылка на Модификатор CUBE") Модификатор `CUBE` используется для вычисления промежуточных итогов для каждой комбинации ключевых выражений в списке `GROUP BY`. Строки с промежуточными итогами добавляются после результирующей таблицы. В строках с промежуточными итогами значения всех «сгруппированных» ключевых выражений устанавливаются в `0` или пустую строку. Примечание Имейте в виду, что предложение [HAVING](https://clickhouse.com/docs/ru/sql-reference/statements/select/having) может влиять на результаты промежуточных итогов. **Пример** Рассмотрим таблицу t: ``` ┌─year─┬─month─┬─day─┐ │ 2019 │ 1 │ 5 │ │ 2019 │ 1 │ 15 │ │ 2020 │ 1 │ 5 │ │ 2020 │ 1 │ 15 │ │ 2020 │ 10 │ 5 │ │ 2020 │ 10 │ 15 │ └──────┴───────┴─────┘ ``` Запрос: ``` SELECT year, month, day, count(*) FROM t GROUP BY CUBE(year, month, day); ``` Так как секция `GROUP BY` содержит три ключевых выражения, результат содержит восемь таблиц с промежуточными итогами для всех комбинаций ключевых выражений: - `GROUP BY year, month, day` - `GROUP BY year, month` - `GROUP BY year, day` - `GROUP BY year` - `GROUP BY month, day` - `GROUP BY month` - `GROUP BY day` - и общие итоги. Столбцы, не включённые в `GROUP BY`, заполняются нулями. ``` ┌─year─┬─month─┬─day─┬─count()─┐ │ 2020 │ 10 │ 15 │ 1 │ │ 2020 │ 1 │ 5 │ 1 │ │ 2019 │ 1 │ 5 │ 1 │ │ 2020 │ 1 │ 15 │ 1 │ │ 2019 │ 1 │ 15 │ 1 │ │ 2020 │ 10 │ 5 │ 1 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 2019 │ 1 │ 0 │ 2 │ │ 2020 │ 1 │ 0 │ 2 │ │ 2020 │ 10 │ 0 │ 2 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 2020 │ 0 │ 5 │ 2 │ │ 2019 │ 0 │ 5 │ 1 │ │ 2020 │ 0 │ 15 │ 2 │ │ 2019 │ 0 │ 15 │ 1 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 2019 │ 0 │ 0 │ 2 │ │ 2020 │ 0 │ 0 │ 4 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 0 │ 1 │ 5 │ 2 │ │ 0 │ 10 │ 15 │ 1 │ │ 0 │ 10 │ 5 │ 1 │ │ 0 │ 1 │ 15 │ 2 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 0 │ 1 │ 0 │ 4 │ │ 0 │ 10 │ 0 │ 2 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 0 │ 0 │ 5 │ 3 │ │ 0 │ 0 │ 15 │ 3 │ └──────┴───────┴─────┴─────────┘ ┌─year─┬─month─┬─day─┬─count()─┐ │ 0 │ 0 │ 0 │ 6 │ └──────┴───────┴─────┴─────────┘ ``` Тот же запрос можно записать и с использованием ключевого слова `WITH`. ``` SELECT year, month, day, count(*) FROM t GROUP BY year, month, day WITH CUBE; ``` **См. также** - Настройка [group\_by\_use\_nulls](https://clickhouse.com/docs/ru/operations/settings/settings#group_by_use_nulls) для совместимости со стандартом SQL. ## Модификатор WITH TOTALS[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#with-totals-modifier "Прямая ссылка на Модификатор WITH TOTALS") Если указан модификатор `WITH TOTALS`, будет вычислена дополнительная строка. В этой строке ключевые столбцы будут содержать значения по умолчанию (нули или пустые строки), а столбцы с агрегирующими функциями — значения, вычисленные по всем строкам (итоговые значения). Эта дополнительная строка создаётся только в форматах `JSON*`, `TabSeparated*` и `Pretty*`, отдельно от остальных строк: - В форматах `XML` и `JSON*` эта строка выводится как отдельное поле `totals`. - В форматах `TabSeparated*`, `CSV*` и `Vertical` строка следует после основного результата, предваряемая пустой строкой (после остальных данных). - В форматах `Pretty*` строка выводится как отдельная таблица после основного результата. - В формате `Template` строка выводится в соответствии с указанным шаблоном. - В остальных форматах она недоступна. Примечание `totals` выводится в результатах запросов `SELECT` и не выводится в `INSERT INTO ... SELECT`. `WITH TOTALS` может работать по-разному, когда присутствует [HAVING](https://clickhouse.com/docs/ru/sql-reference/statements/select/having). Поведение зависит от настройки `totals_mode`. ### Настройка обработки `totals`[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#configuring-totals-processing "Прямая ссылка на configuring-totals-processing") По умолчанию `totals_mode = 'before_having'`. В этом случае `totals` вычисляется по всем строкам, включая те, которые не проходят по условиям HAVING и `max_rows_to_group_by`. Другие варианты включают в `totals` только строки, прошедшие через HAVING, и по-разному ведут себя при настройках `max_rows_to_group_by` и `group_by_overflow_mode = 'any'`. `after_having_exclusive` – не включать строки, которые не прошли через `max_rows_to_group_by`. Другими словами, в `totals` будет меньше или столько же строк, сколько было бы, если бы `max_rows_to_group_by` был опущен. `after_having_inclusive` – включать в `totals` все строки, которые не прошли через `max_rows_to_group_by`. Другими словами, в `totals` будет больше или столько же строк, сколько было бы, если бы `max_rows_to_group_by` был опущен. `after_having_auto` – подсчитать количество строк, прошедших через HAVING. Если оно больше определённого порога (по умолчанию 50%), включить в `totals` все строки, которые не прошли через `max_rows_to_group_by`. В противном случае не включать их. `totals_auto_threshold` – по умолчанию 0.5. Коэффициент для `after_having_auto`. Если `max_rows_to_group_by` и `group_by_overflow_mode = 'any'` не используются, все варианты `after_having` эквивалентны, и можно использовать любой из них (например, `after_having_auto`). Вы можете использовать `WITH TOTALS` во вложенных подзапросах, включая подзапросы в предложении [JOIN](https://clickhouse.com/docs/ru/sql-reference/statements/select/join) (в этом случае соответствующие итоговые значения объединяются). ## GROUP BY ALL[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#group-by-all "Прямая ссылка на GROUP BY ALL") `GROUP BY ALL` эквивалентен перечислению в предложении SELECT всех выражений, которые не являются агрегатными функциями. Например: ``` SELECT a * 2, b, count(c), FROM t GROUP BY ALL ``` то же самое, что ``` SELECT a * 2, b, count(c), FROM t GROUP BY a * 2, b ``` В особом случае, когда есть функция, в которой в качестве аргументов используются и агрегатные функции, и другие поля, ключи `GROUP BY` будут содержать максимально возможное число неагрегатных полей, которые можно из этой функции извлечь. Например: ``` SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY ALL ``` то же самое, что ``` SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY substring(a, 4, 2), substring(a, 1, 2) ``` ## Примеры[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#examples "Прямая ссылка на Примеры") Пример: ``` SELECT count(), median(FetchTiming > 60 ? 60 : FetchTiming), count() - sum(Refresh) FROM hits ``` В отличие от MySQL (и в соответствии со стандартом SQL), вы не можете получить значение столбца, не участвующего ни в ключе, ни в агрегатной функции (за исключением константных выражений). В качестве обходного решения можно использовать агрегатную функцию `any` (получить первое встретившееся значение) или `min/max`. Пример: ``` SELECT domainWithoutWWW(URL) AS domain, count(), any(Title) AS title -- getting the first occurred page header for each domain. FROM hits GROUP BY domain ``` Для каждого различного значения ключа оператор `GROUP BY` вычисляет набор значений агрегатных функций. ## Модификатор GROUPING SETS[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#grouping-sets-modifier "Прямая ссылка на Модификатор GROUPING SETS") Это самый общий модификатор. Он позволяет вручную задавать несколько наборов ключей агрегации (grouping sets). Агрегация выполняется отдельно для каждого grouping set, после чего все результаты объединяются. Если столбец не входит в grouping set, он заполняется значением по умолчанию. Другими словами, модификаторы, описанные выше, могут быть выражены с помощью `GROUPING SETS`. Несмотря на то, что запросы с модификаторами `ROLLUP`, `CUBE` и `GROUPING SETS` синтаксически эквивалентны, их производительность может отличаться. Когда `GROUPING SETS` старается выполнять все варианты агрегации параллельно, `ROLLUP` и `CUBE` выполняют финальное слияние агрегатов в одном потоке. В ситуации, когда исходные столбцы содержат значения по умолчанию, может быть сложно определить, является ли строка частью агрегации, в которой эти столбцы используются как ключи, или нет. Чтобы решить эту проблему, необходимо использовать функцию `GROUPING`. **Пример** Следующие два запроса эквивалентны. ``` -- Query 1 SELECT year, month, day, count(*) FROM t GROUP BY year, month, day WITH ROLLUP; -- Query 2 SELECT year, month, day, count(*) FROM t GROUP BY GROUPING SETS ( (year, month, day), (year, month), (year), () ); ``` **См. также** - настройку [group\_by\_use\_nulls](https://clickhouse.com/docs/ru/operations/settings/settings#group_by_use_nulls) для обеспечения совместимости со стандартом SQL. ## Подробности реализации[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#implementation-details "Прямая ссылка на Подробности реализации") Агрегация — одна из важнейших функций колоночной СУБД, и, следовательно, её реализация является одной из наиболее оптимизированных частей ClickHouse. По умолчанию агрегация выполняется в памяти с использованием хеш-таблицы. Для неё существует более 40 специализаций, которые выбираются автоматически в зависимости от типов данных «ключа группировки». ### Оптимизация GROUP BY в зависимости от сортировочного ключа таблицы[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#group-by-optimization-depending-on-table-sorting-key "Прямая ссылка на Оптимизация GROUP BY в зависимости от сортировочного ключа таблицы") Агрегацию можно выполнять более эффективно, если таблица отсортирована по некоторому ключу, а выражение `GROUP BY` содержит как минимум префикс сортировочного ключа или инъективные функции. В этом случае, когда из таблицы читается новый ключ, промежуточный результат агрегации может быть финализирован и отправлен клиенту. Такое поведение включается настройкой [optimize\_aggregation\_in\_order](https://clickhouse.com/docs/ru/operations/settings/settings#optimize_aggregation_in_order). Подобная оптимизация снижает потребление памяти во время агрегации, но в некоторых случаях может замедлить выполнение запроса. ### GROUP BY во внешней памяти[​](https://clickhouse.com/docs/ru/sql-reference/statements/select/group-by#group-by-in-external-memory "Прямая ссылка на GROUP BY во внешней памяти") Вы можете включить сброс временных данных на диск, чтобы ограничить использование памяти во время `GROUP BY`. Настройка [max\_bytes\_before\_external\_group\_by](https://clickhouse.com/docs/ru/operations/settings/settings#max_bytes_before_external_group_by) определяет порог потребления ОЗУ, при достижении которого временные данные `GROUP BY` начинают сбрасываться в файловую систему. Если установлено значение 0 (по умолчанию), механизм отключён. В качестве альтернативы вы можете задать [max\_bytes\_ratio\_before\_external\_group\_by](https://clickhouse.com/docs/ru/operations/settings/settings#max_bytes_ratio_before_external_group_by), что позволяет задействовать внешнюю память для `GROUP BY` только после того, как запрос достигнет определённого порога использованной памяти. При использовании `max_bytes_before_external_group_by` мы рекомендуем установить `max_memory_usage` примерно вдвое выше (или `max_bytes_ratio_before_external_group_by=0.5`). Это необходимо, потому что агрегация состоит из двух этапов: чтение данных и формирование промежуточных данных (1) и слияние промежуточных данных (2). Сброс данных в файловую систему может происходить только на этапе 1. Если временные данные не были сброшены, то на этапе 2 может потребоваться до такого же объёма памяти, как и на этапе 1. Например, если [max\_memory\_usage](https://clickhouse.com/docs/ru/operations/settings/settings#max_memory_usage) было установлено в 10000000000 и вы хотите использовать внешнюю агрегацию, имеет смысл задать `max_bytes_before_external_group_by` равным 10000000000, а `max_memory_usage` — 20000000000. Когда внешняя агрегация срабатывает (если был хотя бы один сброс временных данных), максимальное потребление ОЗУ лишь немного превышает `max_bytes_before_external_group_by`. При распределённой обработке запросов внешняя агрегация выполняется на удалённых серверах. Чтобы сервер, инициирующий запрос, использовал лишь небольшое количество ОЗУ, установите `distributed_aggregation_memory_efficient` в 1. При слиянии данных, сброшенных на диск, а также при слиянии результатов с удалённых серверов при включённой настройке `distributed_aggregation_memory_efficient`, используется до `1/256 * число_потоков` от общего объёма ОЗУ. Когда внешняя агрегация включена, если объём данных меньше `max_bytes_before_external_group_by` (то есть данные не были сброшены), запрос выполняется так же быстро, как и без внешней агрегации. Если какие-либо временные данные были сброшены, время выполнения будет в несколько раз больше (примерно в три раза). Если после `GROUP BY` используется [ORDER BY](https://clickhouse.com/docs/ru/sql-reference/statements/select/order-by) с [LIMIT](https://clickhouse.com/docs/ru/sql-reference/statements/select/limit), то объём используемой ОЗУ зависит от количества данных в `LIMIT`, а не во всей таблице. Но если у `ORDER BY` нет `LIMIT`, не забудьте включить внешнюю сортировку (`max_bytes_before_external_sort`).
Shard89 (laksa)
Root Hash12633450985039531489
Unparsed URLcom,clickhouse!/docs/ru/sql-reference/statements/select/group-by s443