Sql-Server

SQL Server 的優化器如何估計連接表中的行數?

  • January 5, 2019

我在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)

這恰好與問題中的計算結果相同,儘管詳細推理不同(即它不是基於假設的嵌套循環實現)。

引用自:https://dba.stackexchange.com/questions/96913