在SQL Server里,你有沒有想進行跨越多個列/緯度的聚集操作,不使用SSAS許可(SQL Server分析服務)。我不是說在生產里使用開發版,也不是說安裝盜版SQL Server。
不可能的任務?未必,因為通過SQL Server里所謂的Grouping Sets就可以。在這篇文章里我會給你概括介紹下Grouping Sets,使用它們可以實現哪類查詢,什么是它們的性能優勢。
使用Grouping Sets的聚合假設你有個訂單表,你想進行跨多個分組的T-SQL聚集查詢。在AdventureWorks2012數據庫的Sales.SalesOrderHeader表的環境里,這些分組可以類似如下:
當你想用傳統T-SQL查詢進行這些各自分組時,你需要多個語句,對各個記錄集進行UNION ALL。我們來看這樣的查詢:
1 SELECT * FROM 2 ( 3 -- 1st Grouping Set 4 SELECT 5 NULL AS 'CustomerID', 6 NULL AS 'SalesPersonID', 7 NULL AS 'OrderYear', 8 SUM(TotalDue) AS 'TotalDue' 9 FROM Sales.SalesOrderHeader10 WHERE SalesPersonID IS NOT NULL11 12 UNION ALL13 14 -- 2nd Grouping Set15 SELECT16 NULL AS 'CustomerID',17 SalesPersonID, 18 YEAR(OrderDate) AS 'OrderYear', 19 SUM(TotalDue) AS 'TotalDue' 20 FROM Sales.SalesOrderHeader21 WHERE SalesPersonID IS NOT NULL22 GROUP BY SalesPersonID, YEAR(OrderDate)23 24 UNION ALL25 26 -- 3rd Grouping Set27 SELECT28 CustomerID,29 NULL AS 'SalesPersonID', 30 YEAR(OrderDate) AS 'OrderYear', 31 SUM(TotalDue) AS 'TotalDue' 32 FROM Sales.SalesOrderHeader33 WHERE SalesPersonID IS NOT NULL34 GROUP BY CustomerID, YEAR(OrderDate)35 36 UNION ALL37 38 -- 4th Grouping Set39 SELECT40 CustomerID,41 SalesPersonID,42 YEAR(OrderDate) AS 'OrderYear', 43 SUM(TotalDue) AS 'TotalDue' 44 FROM Sales.SalesOrderHeader45 WHERE SalesPersonID IS NOT NULL46 GROUP BY CustomerID, SalesPersonID, YEAR(OrderDate)47 ) AS t48 ORDER BY CustomerID, SalesPersonID, OrderYear49 GO
用這個T-SQL語句方法有多個缺點:
如果你使用自SQL Server 2008以后引入的grouping sets功能,就可以大大簡化你需要的T-SQL代碼。下面代碼展示你同樣的查詢,但這次用grouping sets實現。
1 SELECT 2 CustomerID, 3 SalesPersonID, 4 YEAR(OrderDate) AS 'OrderYear', 5 SUM(TotalDue) AS 'TotalDue' 6 FROM Sales.SalesOrderHeader 7 WHERE SalesPersonID IS NOT NULL 8 GROUP BY GROUPING SETS 9 (10 -- Our 4 different grouping sets11 (CustomerID, SalesPersonID, YEAR(OrderDate)),12 (CustomerID, YEAR(OrderDate)),13 (SalesPersonID, YEAR(OrderDate)),14 ()15 )16 GO
從代碼本身可以看到,你只在GROUP BY GROUPING SETS子句里指定需要的分組集——其它的一切都由SQL Server搞定。指定的空括號是所謂的Empty Grouping Set,是跨整個表的聚集。當你看STATISTICS IO輸出時,你會發現Sales.SalesOrderHeader只被訪問了1次!這是和剛才手工實現的巨大區別。
在執行計劃里,SQL Server使用了Table Spool運算符,它把獲得的數據臨時存儲在TempDb里。來自臨時表里創建的Worktable的數據在執行計劃的第2個分支被使用。因此對來自表的每個分組數據沒有重新掃描,這就給整個執行計劃的帶來了更好的性能。
我們再來看下執行計劃,你會發現查詢計劃包含了3個Stream Aggregate運算符(紅色,藍色,綠色高亮顯示)。這3個運算符計算各個分組集:
2個連續的Stream Aggregate運算符的背后想法是計算所謂的Super Aggregates——聚集的聚集。
小結在今天的文章里我給你介紹了grouping sets,在SQL Server 2008后引入的增強T-SQL。如你所見grouping sets有2個大優點:簡化你的代碼,只訪問一次數據提高查詢性能。
我希望現在你已經能夠很好理解grouping sets,如果你能在你的數據庫里使用這個功能可以在此留言,非常感謝!
感謝關注!
新聞熱點
疑難解答