Sql-Server

多語句 TVF 上的 WITH SCHEMABINDING 是否會改善基數估計?

  • August 15, 2021

根據查詢性能和多語句表值函式等文章,SQL Server 假設多行表值函式返回一行。如果呼叫語句實際上返回許多行,這會導致為呼叫語句選擇一個糟糕的執行計劃。

添加SCHEMABINDING到函式是否會導致函式返回值集的基數估計更正確?

如果我們假設我們將一個UserId傳遞給這個函式並返回一個允許使用者訪問的RecordId值表,並且一些使用者只被允許看到一些記錄,而一些使用者被允許看到很多甚至所有記錄,函式或呼叫語句(或包含它們的過程)是否會從使用中受益RECOMPILE?函式中的使用會SCHEMABINDING改變這個答案嗎?

我意識到我可以通過實驗來解決這個問題,但我希望有人已經找到了答案。指向有據可查的地方的指針會很有幫助。

在我的測試中,不,添加WITH SCHEMABINDING不會改善基數估計。我創建了一個簡單的表:

CREATE TABLE dbo.myobjects(id INT PRIMARY KEY);

INSERT dbo.myobjects SELECT [object_id] FROM sys.all_objects;

然後是兩個函式:

CREATE FUNCTION dbo.noschemabinding(@UserID INT)
RETURNS @x TABLE (id INT)
AS
BEGIN
 INSERT @x SELECT id FROM dbo.myobjects;

 RETURN;
END
GO

CREATE FUNCTION dbo.withschemabinding(@UserID INT)
RETURNS @x TABLE (id INT)
WITH SCHEMABINDING
AS
BEGIN
 INSERT @x SELECT id FROM dbo.myobjects;

 RETURN;
END
GO

比較實際計劃,兩者都顯示估計行 = 1,實際行 = 2112(後一個數字可能在您的系統上有所不同,具體取決於版本/SP 等)。

速度對比:

SET NOCOUNT ON;
GO
SELECT SYSDATETIME();
GO
SELECT id INTO #x FROM dbo.noschemabinding(1);
DROP TABLE #x;
GO 1000
GO
SELECT SYSDATETIME();
GO
SELECT id INTO #x FROM dbo.withschemabinding(1);
DROP TABLE #x;
GO 1000
SELECT SYSDATETIME();

結果:

                   run 1               run 2
----------------    ------------------  ------------------
No schemabinding    14632 milliseconds  14079 milliseconds
Schemabinding       14251 milliseconds  13979 milliseconds

那麼,這很重要嗎?沒有。

SCHEMABINDING在這種情況下,用於更重要的目標:底層架構穩定性。如果您追求將您的函式轉換為內聯 TVF,那麼您可能會有更好的優化機會,而不是在多語句 TVF 中尋找影響計劃的模糊差異。

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