Sql-Server

在一個簡單的案例中,估計的與實際的行數

  • February 10, 2017

我正在優化我繼承的數據庫中的一些查詢。我不允許透露查詢,但我可以提供一個匿名版本的查詢計劃,它顯示出一些非常奇怪的行為(對我來說):

在此處輸入圖像描述 在此處輸入圖像描述

我的問題是關於圖像中 (1) 表示的“聚集索引掃描”。據我了解,以黃色突出顯示的“聚集索引掃描”沒有任何依賴關係。該操作沒有任何謂詞(儘管我在這裡沒有顯示),並且它在樹中的兄弟 (2) 執行的次數與返回的行數 (1) 的次數相同——我認為這是指(1) 首先執行,然後 (2) 逐行執行以進行連接(這是有道理的,因為連接是“嵌套循環”)。

這就是問題所在:(1) 的“估計行數”是 46。“實際行數”是 283972,這正是該表中的行數*……*這是有道理的,因為沒有什麼可以減少的。我知道查詢非常複雜(4 級嵌套視圖),但是 SQL Server 到底是怎麼弄錯的呢?為什麼在沒有謂詞的索引掃描中返回的行數的估計值不等於表中的行數?

我已經更新了所有相關的表統計資訊,但沒有成功。我還注意到降低查詢的嵌套級別會導致問題發生的頻率降低,儘管結果是“不穩定的”。有許多查詢引用了這個視圖,如果我部分地減少這個視圖的嵌套,一些查詢可能是固定的,但它可能會破壞更多。

重要的是要認識到聚集索引掃描並不總是意味著 SQL Server 期望讀取表中的所有行。對於某些查詢,SQL Server 能夠在找到所需的所有行後提前停止。您在計劃中看到的估計行數較少可能是由於行目標

讓我們來看一個簡單的例子。假設我創建了兩個沒有任何共享值的堆表:

CREATE TABLE X_HEAP_1 (ID INT NOT NULL);

INSERT INTO X_HEAP_1 WITH (TABLOCK)
SELECT N FROM dbo.GetNums(1000000)
WHERE N % 10 <> 5;

CREATE TABLE X_HEAP_2 (ID INT NOT NULL);

INSERT INTO X_HEAP_2 WITH (TABLOCK)
SELECT N FROM dbo.GetNums(1000000)
WHERE N % 10 = 5;

我知道以下查詢不會返回任何行:

SELECT TOP (10) H1.ID
FROM X_HEAP_1 h1
INNER JOIN X_HEAP_2 h2 ON h1.ID = h2.ID;

因為表上沒有索引,SQL Server 將被迫從兩個表中讀取所有行。但是,SQL Server 不知道查詢不會返回任何行。事實上,根據統計和建模假設,它預計查詢將返回完整的 10 行。它還期望不需要掃描兩個表中的每一行來達到 10 行。這是一個估計的計劃:

估計計劃

查詢優化器認為,在獲得 89 行之後X_HEAP_1,兩個表中總共會有 10 行匹配。但是,我們已經知道,在實際計劃中,它需要從以下位置掃描所有 900000 行X_HEAP_1

實際計劃

這是一個簡單的範例,說明行目標如何導致估計的行數減少 10000 倍。

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