Sql-Server

為什麼子查詢將行估計減少到 1?

  • November 28, 2019

考慮以下人為但簡單的查詢:

SELECT 
 ID
, CASE
   WHEN ID <> 0 
   THEN (SELECT TOP 1 ID FROM X_OTHER_TABLE) 
   ELSE (SELECT TOP 1 ID FROM X_OTHER_TABLE_2) 
 END AS ID2
FROM X_HEAP;

我希望此查詢的最終行估計等於X_HEAP表中的行數。無論我在子查詢中做什麼,對行估計都無關緊要,因為它無法過濾掉任何行。但是,在 SQL Server 2016 上,由於子查詢,我看到行估計減少到 1:

錯誤查詢

為什麼會這樣?我能做些什麼呢?

使用正確的語法很容易重現此問題。這是一組可以執行此操作的表定義:

CREATE TABLE dbo.X_HEAP (ID INT NOT NULL)
CREATE TABLE dbo.X_OTHER_TABLE (ID INT NOT NULL);
CREATE TABLE dbo.X_OTHER_TABLE_2 (ID INT NOT NULL);

INSERT INTO dbo.X_HEAP WITH (TABLOCK)
SELECT TOP (1000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values;

CREATE STATISTICS X_HEAP__ID ON X_HEAP (ID) WITH FULLSCAN;

db小提琴連結

在以下情況下,此基數估計 (CE) 問題會出現:

  1. 連接是帶有傳遞謂詞的外連接
  2. 直通謂詞的選擇性估計****正好是 1

注意:用於確定選擇性的特定計算器並不重要。


細節

CE 將外連接的選擇性計算為以下各項和:

  • 具有相同謂詞的內連接選擇性
  • 具有相同謂詞的反連接選擇性

外連接和內連接之間的唯一區別是外連接還返回與連接謂詞不匹配的行。反連接恰好提供了這種差異。內連接和反連接的基數估計比直接外連接更容易。

連接選擇性估計過程非常簡單:

  • 首先,評估傳遞謂詞

的選擇性。SPT

  • 這是使用適合具體情況的任何計算器來完成的。
  • 謂詞是整個事物,包括任何否定IsFalseOrNull成分。
  • 內部連接選擇性:=1 - SPT
  • 反連接選擇性:=SPT

反連接表示將“通過”連接的行。內連接表示不會“通過”的行。請注意,“通過”表示流過連接的行,根本不執行內側。強調一下:連接將返回所有行,區別在於在出現之前執行連接內側的行和不執行的行。

顯然,添加到應始終提供 1 的總選擇性,這意味著所有行都由連接返回,正如預期的那樣。1 - SPT****SPT

實際上,上述計算的工作原理與對除 1 之外的所有值的描述完全相同。SPT

當= 1 時,內連接和反連接選擇性都估計為零,從而產生一行的基數估計(對於整個連接)。據我所知,這是無意的,應該報告為錯誤。SPT


一個相關的問題

由於單獨的 CE 限制,此錯誤比人們想像的更可能出現。當CASE表達式使用EXISTS子句時會出現這種情況(這很常見)。例如,問題中的以下修改查詢不會遇到意外的基數估計:

-- This is fine
SELECT 
   CASE
       WHEN XH.ID = 1
       THEN (SELECT TOP (1) XOT.ID FROM dbo.X_OTHER_TABLE AS XOT) 
   END
FROM dbo.X_HEAP AS XH;

引入一個小EXISTS問題確實會導致問題浮出水面:

-- This is not fine
SELECT 
   CASE
       WHEN EXISTS (SELECT 1 WHERE XH.ID = 1)
       THEN (SELECT TOP (1) XOT.ID FROM dbo.X_OTHER_TABLE AS XOT) 
   END
FROM dbo.X_HEAP AS XH;

UsingEXISTS在執行計劃中引入了一個半連接(突出顯示):

半加盟計劃

半連接的估計很好。問題是 CE 將關聯的探針列視為一個簡單的投影,固定選擇性為 1:

Semijoin with probe column treated as a Project.

Selectivity of probe column = 1

無論條款的內容如何,這都會自動滿足此 CE 問題出現所需的條件之一EXISTS


有關重要的背景資訊,請參閱Craig Freedman的表達式中的子查詢。CASE

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