Sql-Server

重新編譯不適用於 DELETE 語句

  • July 21, 2016

我想優化從我的表中刪除。

我有以下類型的 usp 的表變數輸入:

CREATE TYPE [AddressInfoParts] AS TABLE(
(
   [TcpInfoId]     [BIGINT] NULL INDEX IXTcpInfoId CLUSTERED,
   [EmailInfoId]   [BIGINT] NULL INDEX IXEmailInfoId NONCLUSTERED,
   [PhoneInfoId]   [BIGINT] NULL INDEX IXPhoneInfoId NONCLUSTERED
)

這裡我有一個刪除:

DELETE FROM [doc].[TcpInfo]
WHERE ID in (SELECT aip.TcpInfoId FROM @AddressInfoParts aip)
OPTION(RECOMPILE)

有以下計劃:

在此處輸入圖像描述

我的問題是:為什麼它需要 1 行(in Clustered index seek),當我指定重新編譯時(並期望它將重新編譯最後一個表變數大小的過程(在這種情況下為 2000))。

我總是有一個相同類型的表,但我不知道如何將它告訴 SQL 引擎。因為它選擇了非最優計劃:它使用循環,因為當我們有 N 行時只期望 1 行,變數和這 3 個表之間存在 1-1 關係。每列都有 X 個唯一值和 Y 個 NULL。但在實踐中,其中之一是 0(我們有所有空值或者我們有所有唯一的非空值)。

當我在 3 個唯一表上拆分錶時,統計資訊效果更好,但無論如何它只需要 1 行,當收到 N 時: 在此處輸入圖像描述

請指教。

當我指定重新編譯時,為什麼它需要 1 行(在聚集索引查找中)

沒事兒。

有點令人困惑的是,嵌套循環連接內部的估計行是每個運算符的執行。

對主鍵的搜尋確實會返回 1 行(如果該值根本不存在,則返回 0)。

在您的情況下,您有 2,000 次搜尋都返回 1 行,報告的實際行數為 2,000,因此每次執行的估計行數是正確的。您需要將估計的行數乘以估計的執行次數,並將其與實際行進行比較,以查看是否存在任何差異。

您的第一個計劃表明,內部的估計執行次數實際上會被低估(在 45 次而不是 2,000 次),因為它估計流聚合TcpInfoId將返回 45 個不同的值。這是因為沒有關於表變數的列統計資訊告訴它實際上這些值是唯一的。OPTION (RECOMPILE)只允許它考慮表變數中的行數,它不提供有關列密度的任何資訊。

TcpInfoId如果您要更改to [TcpInfoId] [BIGINT] NOT NULL PRIMARY KEYor的列定義[TcpInfoId] [BIGINT] NULL UNIQUE CLUSTERED(差異是第二個將允許單個NULL),那麼這將提供可以使用的唯一性資訊。

每列都有 X 個唯一值和 Y 個 NULL。但在實踐中,其中之一是 0(我們有所有空值或者我們有所有唯一的非空值)。

如果您在 2016 年,則可以使用唯一的過濾索引

CREATE TYPE [AddressInfoParts] AS TABLE
(
[TcpInfoId] [BIGINT] NULL INDEX IXTcpInfoId UNIQUE WHERE [TcpInfoId] IS NOT NULL,
[EmailInfoId] [BIGINT] NULL INDEX IXEmailInfoId NONCLUSTERED,
[PhoneInfoId] [BIGINT] NULL INDEX IXPhoneInfoId NONCLUSTERED
)

如果您使用的版本不支持表類型中的過濾索引,也許您可以使用#Temporary表來代替(因為它們可以創建列統計資訊)。

或者,您可以停止嘗試對這兩種截然不同的情況使用單一表類型。

如果我正確理解您的問題,這就是第二個計劃所代表的內容。您指出的問題實際上並不是本答案開頭所解釋的問題。

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