Когда использовать 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
для предоставления ответа (а затем обработать эту дополнительную строку, проходящую в отчете).