性能調優8:分組聚合 - group by
聚合實際上對數據做分組統計,SQL Server使用兩種操作符來實現聚合,流聚合(Stream Aggregation)和哈希聚合(Hash aggration)。流聚合是非阻塞性的,具有流的特性,流聚合操作符;邊處理數據,邊輸出聚合的結果。而哈希聚合是阻塞性的,只要處理完所有的數據,才會輸出聚合的結果。
一,流聚合
流聚合要求輸入的數據集在group by 即分組列上是有序的,也就是說,流聚合需要排序。分組列的位置和順序不會影響聚合的結果,因此分組列的排序是任意的。對於索引上的流聚合,由於數據是已經排序的,使用流聚合算法沒有排序操作的開銷。
流聚合算法是:第一個被讀取的數據會創建第一個分組,後續讀入的數據都會先和當前的分組匹配,如果匹配,把該行放入到當前的分組中;如果不匹配,創建新的分組,直到所有數據行都處理完成為止,最終對各個分組計算聚合值。
二,哈希聚合
在執行計劃中,哈希聚合使用的物理操作符是:Hash Match(Aggregate),實際上,Hash Join也是使用Hash Match作為物理操作符。哈希聚合不需要排序,但是需要授予內存來創建Hash表。優化器傾向於使用哈希聚合來對無序的大表進行聚合操作,哈希聚合的算法:
- 對於每一個輸入行,在group by列上計算哈希值,
- 檢查該行是否映射到hash表中,如果不存在於現有的哈希表,那麽把該行插入到哈希表中,創建新的分組;如果存在於現有的哈希表中,把該行插入到現有的分組中。
- 計算哈希表中的數據,作為最終的結果輸出。
哈希聚合使用Hash表來存儲各個分組的數據,最後並行計算各個分組中的數據。由於數據是無序的,任何數據行都有可能屬於任意一個分組,因此,哈希聚合直到處理完所有的數據行才會輸出結果。
Hash聚合在創建哈希表時,需要向系統申請授予內存,當授予內存不足時,需要把哈希表的一部分哈希桶溢出到硬盤的workfiles中。這和Hash Join的內存使用和溢出相同。
三,列存儲索引
列存儲索引適合於數據倉庫中,主要執行大容量數據加載和只讀查詢,與傳統面向行的存儲方式相比,使用列存儲索引存儲可最多提高 10 倍查詢性能 ,與使用非壓縮數據大小相比,可提供多達 7 倍數據壓縮率 。列存儲索引使用用“批處理執行模式”的模式,這與行存儲使用的逐行數據讀取模式對比,性能大幅提升。
列存儲索引主要在下面三個特性上提升查詢的性能:
- 行存儲使用逐行處理模式,每次只處理一行數據;而列存儲索引使用批處理模式,每次處理一批數據行。
- 行存儲是逐行存儲(Row Store),每一個Page存儲多行數據,而列存儲(Column Store)把數據表中的每一列單獨存儲在Page集合中,這意味著,Page集合中存儲的是某一列的數據,而不是一行中所有列的數據。在讀取數據時,行存儲把一行的所有列都加載到內存,即使有些列根本不會用到;而列存儲只把需要的列加載到內存中,不需要的列不會被加載到內存中。
- 列存儲索引自動對數據進行壓縮處理,由於同一行的數據具有很高的相似性,壓縮率很高,數據讀取更快速。
一般情況下,數據倉庫的查詢語句只會查詢少數幾個列的數據,其他列的數據不需要加載到內存中,這就使得列存儲特別適合用於數據倉庫中對星型連接(Star- Join)進行聚合查詢,所謂星型連接(Star-Join)的聚合查詢是指對一個大表(Large Table)和多個小表(Little Table)進行連接,並對Large Table 進行聚合查詢。在數據庫倉庫中,是指事實表和維度表的連接。在大表上創建列存儲索引,SQL Server 引擎將充分使用批處理模式(Batch processing mode)來執行星型查詢,獲取更高的查詢性能。
參考文檔:
性能調優8:分組聚合 - group by