第六章——根據執行計劃優化性能(1)——理解哈希、合併、嵌套循環連接策略

前言:

本系列文章包括:

1、 理解Hash、Merge、Nested Loop關聯策略。

2、 在執行計劃中發現並解決表/索引掃描。

3、 介紹並在執行計劃中發現鍵查找並解決它們。

 

對於性能優化,需要集中處理以下的問題:

1、 爲你的環境創建性能基線。

2、 監控現在的性能並發現瓶頸。

3、 解決瓶頸以便得到更好的性能。

 

一個預估執行計劃是描述查詢將會如何執行的一個藍圖,而一個實際執行計劃就是一個查詢執行時實際發生的鏡像。通過對比兩個執行計劃,可以發現查詢是否真的按照預估執行計劃來執行。

在執行計劃中,有一些非常重要的操作符需要清楚:

1、           Join策略:SQLServer有3種策略——哈希、合併、嵌套循環。每種策略都有其優缺點,本章將講述這部分。

2、           掃描和查找是SQLServer用於讀取數據的兩種方式,這兩種方式在性能優化中是核心概念。將會在下一篇中講述。

3、           鍵查找有時候會成爲主要的性能問題。因爲存儲引起必須從非聚集索引中跳到聚集索引,一邊找到非聚集索引中的非鍵值列的值。這樣的行爲通常很耗時間。

 

理解哈希、合併、嵌套循環連接策略

SQLServer提供了3中JOIN的策略,它們沒有絕對的好和壞之分。

 

1、 哈希(Hash Join):SQLServer選擇哈希關聯作爲物理操作符,一邊對於大容量數據,且未排序或者沒有索引時進行查詢。兩個進程關聯起來進行哈希關聯,它們 爲【建立】和【探測】,在【建立】進程中,會從建立輸入(即join的左表中,但是可能這個左表會在優化過程中交換位置,使得不一定就是實際上的左表。) 讀取所有行,然後在內存中創建一個符合關聯條件的哈希表。在【探測】進程中,會從探測表(輸入的右表)中讀取所有的行,並根據關聯條件,與之前創建的內存 哈希表匹配。

2、 合併(Merge Join):如果關聯表中已經排序,SQLServer會選擇合併關聯。合併關聯要求關聯條件中最少有一個是已經被排序了的。如果數據量不大的時候,這比哈希關聯更加有效,它並不是重負荷關聯的方式。

3、 嵌套循環(Nested Loop):在最少兩個結果集中,使用嵌套循環會比較有效,這兩個結果集中,作爲外部表的集合要小,而內部循環結果集具有有效的索引。這種方式不適用於大結果集。

準備工作:

下面將創建兩個表,然後看看各種關聯方式的執行計劃:

[sql] view plaincopyprint?

  1. USE AdventureWorks  

  2. GO  

  3. IF OBJECT_ID('SalesOrdHeaderDemo'IS NOT NULL   

  4.     BEGIN  

  5.         DROP TABLE SalesOrdHeaderDemo  

  6.     END  

  7. GO  

  8.   

  9. IF OBJECT_ID('SalesOrdDetailDemo'IS NOT NULL   

  10.     BEGIN  

  11.         DROP TABLE SalesOrdDetailDemo  

  12.     END  

  13. GO  

  14.   

  15. SELECT  *  

  16. INTO    SalesOrdHeaderDemo  

  17. FROM    Sales.SalesOrderHeader  

  18. GO  

  19.   

  20. SELECT  *  

  21. INTO    SalesOrdDetailDemo  

  22. FROM    Sales.SalesOrderDetail  

  23. GO  



步驟:

1、 執行一下查詢,並開啓執行計劃(Ctrl+M):

[sql] view plaincopyprint?

  1. SELECT  sh.*  

  2. FROM    SalesOrdDetailDemo AS sd  

  3.         INNER JOIN SalesOrdHeaderDemo AS sh ON sh.salesorderID = sd.salesorderid  

  4. GO  



2、 然後從執行計劃截圖中可以看到使用了哈希連接:


3、 現在先創建唯一的聚集索引在兩個表中:

[sql] view plaincopyprint?

  1. CREATE UNIQUE CLUSTERED INDEX idx_salesorderheaderdemo_SalesOrderID ON salesordheaderdemo(SalesOrderID)  

  2.   

  3. GO  

  4.   

  5. CREATE UNIQUE CLUSTERED INDEX idx_SalesDetail_SalesOrderID ON SalesOrdDetailDemo(SalesOrderID,SalesOrderDetailID)  

  6.   

  7. GO  



4、 再次執行步驟1的語句:

5、 截圖是第二次執行的執行計劃,可以發現變成了合併連接,並且表掃描變成了聚集索引掃描:


6、 現在來看看嵌套循環關聯,在上面的查詢中添加where條件來限定查詢的結果集:

[sql] view plaincopyprint?

  1. SELECT  sh.*  

  2. FROM    SalesOrdDetailDemo AS sd  

  3.         INNER JOIN SalesOrdHeaderDemo AS sh ON sh.salesorderID = sd.salesorderid  

  4. WHERE   sh.salesorderid = 43659  

  5. GO  




7、 從執行結果中看到現在關聯變成了嵌套循環: 

 

分析:

        前面已經提到,哈希關聯工作在大數據量且關聯字段沒有排序的關聯中。所以在步驟1中,由於沒有索引或者預先排序,數據的關聯會使用哈希關聯。

        在步驟3中,創建了一個唯一的聚集索引,所以表已經通過聚集索引排序了,此時優化器會選擇合併關聯。

        在步驟6中,由於使用了where條件限制數據集的大小,同時由於已經排序,所以使用了嵌套循環關聯。

        每一種關聯方法都有其優缺點,視乎如何優化而已。有時候哈希關聯有其非常重要的作用,但是如果可以,強烈建議每個表都應該有一個唯一的聚集索引,一邊使用 合併關聯,如果不可以,千萬別嘗試使用OPTION提示符來把關聯改成合並或者嵌套循環,這可能會降低性能。而嵌套循環僅在小結果集的時候運行的最好。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章