第六章——根據執行計劃優化效能(1)——理解雜湊、合併、巢狀迴圈連線策略...
前言:
本系列文章包括:
1、理解Hash、Merge、Nested Loop關聯策略。
對於效能優化,需要集中處理以下的問題:
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?
USEAdventureWorks
GO
IFOBJECT_ID('SalesOrdHeaderDemo'
BEGIN
DROPTABLESalesOrdHeaderDemo
END
GO
IFOBJECT_ID('SalesOrdDetailDemo')ISNOTNULL
BEGIN
DROPTABLESalesOrdDetailDemo
END
GO
SELECT*
INTOSalesOrdHeaderDemo
FROMSales.SalesOrderHeader
GO
SELECT*
INTOSalesOrdDetailDemo
FROMSales.SalesOrderDetail
GO
步驟:
1、執行一下查詢,並開啟執行計劃(Ctrl+M):
[sql] view plaincopyprint?
SELECTsh.*
FROMSalesOrdDetailDemoASsd
INNERJOINSalesOrdHeaderDemoASshONsh.salesorderID=sd.salesorderid
GO
2、然後從執行計劃截圖中可以看到使用了雜湊連線:
3、現在先建立唯一的聚集索引在兩個表中:
[sql] view plaincopyprint?
CREATEUNIQUECLUSTEREDINDEXidx_salesorderheaderdemo_SalesOrderIDONsalesordheaderdemo(SalesOrderID)
GO
CREATEUNIQUECLUSTEREDINDEXidx_SalesDetail_SalesOrderIDONSalesOrdDetailDemo(SalesOrderID,SalesOrderDetailID)
GO
4、再次執行步驟1的語句:
5、截圖是第二次執行的執行計劃,可以發現變成了合併連線,並且表掃描變成了聚集索引掃描:
6、現在來看看巢狀迴圈關聯,在上面的查詢中新增where條件來限定查詢的結果集:
[sql] view plaincopyprint?
SELECTsh.*
FROMSalesOrdDetailDemoASsd
INNERJOINSalesOrdHeaderDemoASshONsh.salesorderID=sd.salesorderid
WHEREsh.salesorderid=43659
GO
7、從執行結果中看到現在關聯變成了巢狀迴圈:
分析:
前面已經提到,雜湊關聯工作在大資料量且關聯欄位沒有排序的關聯中。所以在步驟1中,由於沒有索引或者預先排序,資料的關聯會使用雜湊關聯。
在步驟3中,建立了一個唯一的聚集索引,所以表已經通過聚集索引排序了,此時優化器會選擇合併關聯。
在步驟6中,由於使用了where條件限制資料集的大小,同時由於已經排序,所以使用了巢狀迴圈關聯。
每一種關聯方法都有其優缺點,視乎如何優化而已。有時候雜湊關聯有其非常重要的作用,但是如果可以,強烈建議每個表都應該有一個唯一的聚集索引,一邊使用 合併關聯,如果不可以,千萬別嘗試使用OPTION提示符來把關聯改成合並或者巢狀迴圈,這可能會降低效能。而巢狀迴圈僅在小結果集的時候執行的最好。
轉載於:https://blog.51cto.com/rmlifejun/1678101