SQL Server 的優化器如何估計連接表中的行數?
我在AdventureWorks2012數據庫中執行此查詢:
SELECT s.SalesOrderID, d.CarrierTrackingNumber, d.ProductID, d.OrderQty FROM Sales.SalesOrderHeader s JOIN Sales.SalesOrderDetail d ON s.SalesOrderID = d.SalesOrderID WHERE s.CustomerID = 11077
如果我查看估計的執行計劃,我會看到以下內容:
初始索引搜尋(右上角)使用 IX_SalesOrderHeader_CustomerID 索引並蒐索文字 11077。它估計有 2.6192 行。
如果我使用
DBCC SHOW_STATISTICS ('Sales.SalesOrderHeader', 'IX_SalesOrderHeader_CustomerID') WITH HISTOGRAM
,則表明值 11077 在兩個採樣鍵 11019 和 11091 之間。11019 和 11091 之間的平均不同行數為 2.619718,或四捨五入為 2.61972,這是為索引查找顯示的估計行的值。
我不明白的部分是聚集索引查找 SalesOrderDetail 表的估計行數。
如果我執行
DBCC SHOW_STATISTICS ('Sales.SalesOrderDetail', 'PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID')
:所以 SalesOrderID(我加入)的密度是 3.178134E-05。這意味著 1/3.178134E-05 (31465) 等於 SalesOrderDetail 表中唯一 SalesOrderID 值的數量。
如果 SalesOrderDetail 中有 31465 個唯一的 SalesOrderID,則在均勻分佈的情況下,每個 SalesOrderID 的平均行數為 121317(總行數)除以 31465。平均值為 3.85561
因此,如果估計要循環的行數是 2.61972,並且要在 3.85561 中返回平均值,我認為估計的行數將是 2.61972 * 3.85561 = 10.10062。
但估計的行數是 11.4867。
我認為我對第二個估計的理解是不正確的,不同的數字似乎表明了這一點。我錯過了什麼?
我認為我對第二個估計的理解是不正確的,不同的數字似乎表明了這一點。我錯過了什麼?
使用 SQL Server 2012 基數估計器,連接的選擇性驅動嵌套循環連接內側的估計行數,而不是相反。
11.4867 數字是通過將計算的連接輸出的估計基數 (30.0919) 除以迭代次數 (2.61972)*得出的(用於在 showplan 中顯示)。*使用單精度浮點運算的結果是11.4867。
它真的是那麼簡單。請注意,(邏輯)連接選擇性與物理連接運算符的選擇無關。無論最終是使用嵌套循環、雜湊還是合併連接物理運算符執行連接,都保持不變。
在 SQL Server 2012 及更早版本中,連接選擇性(作為一個整體)是使用每個表中的直方圖估計的
SalesOrderID
(針對每個直方圖步驟計算,在必要時使用線性插值在步驟邊界對齊之後)。SalesOrderID
與表格關聯的直方圖SalesOrderHeader
也針對獨立CustomerID
濾波器的縮放效果進行了調整。這並不是說問題中提出的替代計算存在任何根本“錯誤”;它只是做了一組不同的假設。對於給定的邏輯操作序列,總會有不同的方法來計算或組合估計。不能普遍保證應用於相同數據的不同統計方法會產生相同的答案,或者一種方法總是優於另一種方法。應用不同統計方法導致的不一致甚至會出現在單個最終執行計劃中,儘管它們很少被注意到。
作為旁注,SQL Server 2014 基數估計器採用不同的方法來組合獨立過濾器調整的直方圖資訊(“粗對齊” ),這會導致此查詢的最終估計為10.1006行:
Plan for computation: CSelCalcExpressionComparedToExpression (QCOL: [s].SalesOrderID x_cmpEq QCOL: [d].SalesOrderID) Loaded histogram for column QCOL: [s].SalesOrderID from stats with id 1 Loaded histogram for column QCOL: [d].SalesOrderID from stats with id 1 Stats collection generated: CStCollJoin(ID=4, **CARD=10.1006** x_jtInner) CStCollFilter(ID=3, CARD=2.61972) CStCollBaseTable(ID=1, CARD=31465 TBL: Sales.SalesOrderHeader AS TBL: s) CStCollBaseTable(ID=2, CARD=121317 TBL: Sales.SalesOrderDetail AS TBL: d)
這恰好與問題中的計算結果相同,儘管詳細推理不同(即它不是基於假設的嵌套循環實現)。