Когда использовать GROUPING SETS, CUBE и ROLLUP

Недавно я узнал о GROUPING SETS, CUBE и ROLLUP для определения множества наборов группировок на сервере sql.

Что я спрашиваю, при каких обстоятельствах мы используем эти функции? Каковы преимущества и преимущества их использования?

SELECT shipperid, YEAR(shippeddate) AS shipyear, COUNT(*) AS numorders
FROM Sales.Orders
GROUP BY GROUPING SETS ( ( shipperid, YEAR(shippeddate) ), ( shipperid ), ( YEAR(shippeddate) ), ( ) );


SELECT shipperid, YEAR(shippeddate) AS shipyear, COUNT(*) AS numorders
FROM Sales.Orders
GROUP BY CUBE( shipperid, YEAR(shippeddate) );


SELECT shipcountry, shipregion, shipcity, COUNT(*) AS numorders
FROM Sales.Orders
GROUP BY ROLLUP( shipcountry, shipregion, shipcity );

Ответы

Ответ 1

Во-первых, для тех, кто еще не прочитал эту тему:

При этом не думайте об этих вариантах группировки как о способах получения набора результатов. Это инструменты производительности.

Возьмем ROLLUP как простой пример.

Я могу использовать следующий запрос, чтобы получить количество записей для каждого значения GrpCol.

SELECT   GrpCol, count(*) AS cnt
FROM     dbo.MyTable
GROUP BY GrpCol

И я могу использовать следующий запрос для суммирования "свертывания" количества ВСЕХ записей.

SELECT   NULL, count(*) AS cnt
FROM     dbo.MyTable

И я мог бы UNION ALL выполнить указанные выше два запроса, чтобы получить те же самые результаты, которые я мог бы получить, если бы я написал первый запрос с предложением ROLLUP (поэтому я поставил там NULL).

Мне может быть удобнее выполнять это как два разных запроса, потому что тогда у меня есть сгруппированные результаты отдельно от моих итогов. Почему я хочу, чтобы мой окончательный итог смешивался с остальными результатами? Ответ заключается в том, что совместная работа с использованием предложения ROLLUP является более эффективной. SQL Server будет использовать план выполнения, который вычисляет все агрегаты за один проход. Сравните это с примером UNION ALL, который предоставит точные результаты, но использует менее эффективный план выполнения (два сканирования таблицы вместо одного).

Представьте себе крайний пример, в котором вы работаете над набором данных настолько большим, что каждое сканирование данных занимает один час. Вы должны предоставлять итоговые данные в основном для каждого возможного измерения (способ среза) этих данных каждый день. Ага! Бьюсь об заклад, один из этих вариантов группировки - именно то, что вам нужно. Если вы сохраните результаты этого сканирования в специальном макете схемы, вы сможете запускать отчеты в течение оставшейся части дня с сохраненных результатов.

Поэтому я в основном говорю, что вы работаете над проектом хранилища данных. Для остальных из нас это в основном относится к категории "опрятная вещь, чтобы знать".

Ответ 2

CUBE совпадает с GROUPING SETS со всеми возможными комбинациями.

Итак, это (используя CUBE)

GROUP BY CUBE (C1, C2, C3, ..., Cn-2, Cn-1, Cn)

то же самое (используя GROUPING SETS)

GROUP BY GROUPING SETS (
     (C1, C2, C3, ..., Cn-2, Cn-1, Cn) -- All dimensions are included.
    ,( , C2, C3, ..., Cn-2, Cn-1, Cn) -- n-1 dimensions are included.
    ,(C1, C3, ..., Cn-2, Cn-1, Cn)
    …
    ,(C1, C2, C3, ..., Cn-2, Cn-1,)
    ,(C3, ..., Cn-2, Cn-1, Cn) -- n-2 dimensions included
    ,(C1  ..., Cn-2, Cn-1, Cn)
    …
    ,(C1, C2) -- 2 dimensions are included.
    ,…
    ,(C1, Cn)
    ,…
    ,(Cn-1, Cn)
    ,…
    ,(C1) -- 1 dimension included
    ,(C2)
    ,…
    ,(Cn-1)
    ,(Cn)
    ,() ) -- Grand total, 0 dimension is included.

Затем, если вам действительно не нужны все комбинации, вы должны использовать GROUPING SETS, а не CUBE

Операторы ROLLUP и CUBE генерируют некоторые из тех же наборов результатов и выполнить те же вычисления, что и приложения OLAP. Куб оператор генерирует результирующий набор, который может использоваться для перекрестной табуляции отчеты. Операция ROLLUP может вычислять эквивалент OLAP размерности или иерархии.

Посмотрите здесь, чтобы увидеть эквиваленты наборов группировок


UPDATE

Я думаю, что пример поможет здесь. Предположим, у вас есть таблица количества наблюдений НЛО по странам и жанрам, например, ниже:

╔═════════╦═══════╦═════════╗
║ COUNTRY ║ GENRE ║ #SIGHTS ║
╠═════════╬═══════╬═════════╣
║ USA     ║ F     ║     450 ║
║ USA     ║ M     ║    1500 ║
║ ITALY   ║ F     ║     704 ║
║ ITALY   ║ M     ║     720 ║
║ SWEDEN  ║ F     ║     317 ║
║ SWEDEN  ║ M     ║     310 ║
║ BRAZIL  ║ F     ║     144 ║
║ BRAZIL  ║ M     ║     159 ║
╚═════════╩═══════╩═════════╝

Затем, если вы хотите узнать итоговые значения для каждой страны, только по жанру и только по общей сумме, вы должны использовать GROUPING SETS

 select Country, Genre, sum(Number_Of_Sights)
 from Table1
 group by GROUPING SETS((Country), (Genre), ())
 order by Country, Genre

SQL Fiddle

Чтобы получить тот же результат с помощью GROUP BY, вы должны использовать UNION ALL как:

select Country, NULL Genre, sum(Number_Of_Sights)
from Table1
GROUP BY Country
UNION ALL
select NULL Country, Genre, sum(Number_Of_Sights)
from Table1
GROUP BY GENRE
UNION ALL
SELECT NULL Country, NULL Genre, sum(Number_Of_Sights)
FROM TABLE1
ORDER BY COUNTRY, GENRE

SQL Fiddle

Но невозможно получить тот же результат с CUBE, так как он вернет все возможности.

Теперь, если вы хотите знать все возможные комбинации, вы должны использовать CUBE

Ответ 3

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

Например, если вы делаете что-то с COUNT(DISTINCT...), тогда результат в большей группе не обязательно совпадает с суммой частей. Например, в течение двух отдельных дней у вас может быть 1500 посетителей и 2000 посетителей, но общая сумма может быть где угодно между 2000 и 3500 годами, в зависимости от перекрытия. Это приятно сделать в клиенте, но поскольку клиент не может определить, что такое перекрытие, вы можете использовать GROUPING SETS для предоставления ответа (а затем обработать эту дополнительную строку, проходящую в отчете).