之前系列中在查詢計劃中一直出現Stream Aggregate,當時也隻是做了基本了解,對于查詢計劃中出現的操作,我們都需要去詳細研究下,隻有這樣才能對查詢計劃執行的每一步操作都了如指掌,是以才有了本文的出現,簡短的内容,深入的了解,Always to review the basics。
Stream Aggregate通過單列或者多列來對行進行分組并且對指定的查詢來計算聚合表達式。最常見的聚合類型如SUM、COUNT、SUM、AVG、MIN、MAX,當我們執行這些聚合函數時在查詢計劃中就會出現Stream Aggregate,Stream Aggregate是非常快的,因為它需要在輸入時通過在GROUP BY中指定的列進行排序。如果聚合中的資料沒有進行排序此時會通過Sort進行預排序或者使用索引查找或者索引掃描來提前預排序資料。之前我們讨論過出現Stream Aggregate有三種方式分别為:聚合函數聚合,分組聚合,DISTINCT聚合,實際上隻有兩種,DISTINCT内部就用到了分組,這裡我們将Stream Aggregate分為兩種類型,一種是标量聚合,另外一種則是分組聚合。我們舉一個标量聚合的例子,也就是傳回單值聚合。

下面我們再來分組聚合的例子
上述就是Stream Aggregate兩種類型的例子,關于标量聚合比較簡單直接利用聚合函數就行,下面我們主要詳細講解這兩種類型中的分組聚合。
我們來結合SQL Server 2012基礎教程來看一個簡單的例子
上述查詢計劃比較簡單我們來解釋下,首先通過預設主鍵建立的聚集索引來讀取表中行資料,接着通過GROUP BY上指定的列custid來進行排序,我們看到其排序操作具體資訊就知道,如下。接着周遊所有custid,所有行被讀取,開始一行行讀取并計算其聚合表達式的值。重複處理直到完成為止。
對于通過流聚合對custid進行分組的示意圖大概如下:
上述由于未對custid建立索引導緻是以會通過Sort來進行排序,毫無疑問導緻查詢緩慢,這裡我們對custid建立非聚集索引再來看看情況
此時查詢将會充分利用索引,它會通過使用索引排序來進行聚合計算,是以就不會再利用Sort來排序導緻性能低下,通過上述我們知道,在進行Stream Aggregate之前事實上在指定的分組列上建立索引來預先排序會提高查詢性能,而不需要再去利用Sort進行排序而耗費不必要的時間。上述我們已經說過在進行排序要麼在GROUP BY上指定的列通過建立索引查找或者索引排序,如果GROUP BY中的列沒有建立索引此時利用Sort來進行顯示排序,如下顯示指定ORDER BY custid來排序和沒有指定的話結果依然都是使用Sort來排序,此時Stream Aggregate,其實這種說法不太準确,因為在SQL Server中有兩種聚合方式,一種是Stream Aggregate,另外一種則是Hash Match Aggregate。
自從SQL Server 7之後就出現了Stream Aggregate和Hash Aggregate兩種聚合方式,也就是說上述我們稍作修改查詢計劃就變成了Hash Aggregate的形式。
上述GbAggToStrm是什麼鬼,其實如果查詢計劃中走的Stream Aggregate操作的話,也就說它走的是GbAggToStrm規則(GROUP BY Aggregate To Stream ),但是這裡我們關閉了查詢計劃本該走的Stream Aggregate操作即GbAggToStrm規則,是以此時它将隻能走Hash Aggregate。是以到這裡說明在排序時即使指定了ORDER BY操作有可能是多餘的,但是如果我們不指定的話,要是我們希望傳回的結果集是排序的,此時要是走的Hash Aggregate,結果傳回的結果集将是無序的,導緻我們得不到想要的結果集,是以還是希望在排序時指定ORDER BY操作,這樣能夠避免不必要的情況發生。
當查詢中用到了DISTINCT關鍵字時,此時查詢計劃有可能走Stream Aggregate,也有可能走的是Hash Match Aggregate。是以在這裡我們分析下什麼時候會用Hash Match Aggregate,什麼時候又會用到Stream Aggregate。說到底DISTINCT關鍵字時用來去重的,在SQL Server中利用DISTINCT關鍵字來去重其查詢計劃走的方式分為兩種,一種是在哈希表中建立唯一值,另外一種則是将行進行排序配置設定到組中然後隻傳回組中的一個值即可。是以在SQL Server中使用Hash Match Aggregate來實作哈希表,使用Stream Aggregate或者DISTINCT Sort來對資料進行排序去重。
當我們如下直接利用DISTINCT來查詢時就是利用的DISTINCT Sort來排序去重。
雖然很明确走的Sort,但是這是經過SQL查詢引擎優化過後才有的,最原始的情況是先進行Sort接着進行Stream Aggregate,下面我們關閉Sort的規則看看。
當未在列SomeColumn建立索引時我們進行如下查詢
接下來我們在列上建立索引
在建立索引時此時查詢計劃走的卻是Stream Aggregate,也就是說當利用DISTINCT關鍵字查詢時且列已經進行了排序,此時查詢計劃走Stream Aggregate。那什麼時候用Hash Match Aggregate呢,上述對列未建立索引時走的是Hash Match Aggregate因為資料量比較大此時還利用了并行計算,換句話說當對列未建立索引時且資料量非常大同時分組比較少時,查詢計劃更加更傾向于走Hash Match Aggregate,輸入大量的資料通過Hash Match Aggregate結合并行計算效率也非常高,當然分組較少更好,此時不會太占用哈希表。接下來我們限制查詢結果集的條數。
此時查詢計劃不再是Hash Match Aggregate代替的是Hash Match(Flow Distinct)我們看下msdn關于Flow Distinct的解釋:Flow Distinct邏輯運算符用于通過掃描輸入來删除重複項。雖然Distinct 運算符在生成任何輸入前消耗所有的輸入,但FlowDistinct 運算符在從輸入獲得行時傳回每行(除非該行是一個重複項,若是這樣則删除該行)
也就是說DISTINCT直接就過濾了重複行,而Flow Distict則獲得每行時并傳回每一行,這就是Flow Distinct,它的出現依賴于在查詢計劃中估計唯一值的數量,當我們将TOP的數量設定為接近100萬或者比100萬還少一點時此時走的是Hash Match Aggregate。到此我們關于Hash Match Aggregate和Stream Aggregate的分析算是結束了,我們下個基本結論:
Hash Match Aggregate和Stream Aggregate分析結論:
(1)查詢中有DISTINCT關鍵字時:當在查詢列上建立索引時即列進行了排序時此時走Stream Aggregate,當資料量非常大時且未建立索引時此時一般走的是Hash Match Aggregate并結合并行計算,其餘情況則是走的Distinct Sort。
(2)查詢中沒有DISTINCT關鍵字時,對于标量聚合和分組聚合走的是Stream Aggregate。
好了本節關于Hash Match Aggregate和Stream Aggregate的介紹就到此為止,基本算是了解,太複雜的也沒去過多探讨,這是DBA的事情了,下一節我們穿插講講關于計算列持久化系列文章,簡短的内容,深入的了解,我們下節再會。
本文轉自Jeffcky部落格園部落格,原文連結:http://www.cnblogs.com/CreateMyself/p/6170565.html,如需轉載請自行聯系原作者