多语句 TVF 上的 WITH SCHEMABINDING 是否会改进基数估计?

Mar*_*man 5 sql-server-2005 sql-server functions cardinality-estimates

根据查询性能和多语句表值函数等文章,SQL Server 假设多行表值函数返回一行。如果它实际上返回许多行,这会导致为调用语句选择一个糟糕的执行计划。

添加SCHEMABINDING到函数是否会导致函数返回值集的基数估计更正确?

如果我们假设我们将一个UserId传递给这个函数并返回一个RecordId值的表,该表允许用户访问,并且一些用户只被允许查看一些记录,而一些用户被允许查看很多甚至所有记录,函数或调用语句(或包含它们的过程)是否会从使用中受益RECOMPILESCHEMABINDING函数中的使用会改变这个答案吗?

我意识到我可以通过实验来解决这个问题,但我希望有人已经找到了答案。指向有详细记录的地方的指针会有所帮助。

Aar*_*and 5

在我的测试中,不,添加WITH SCHEMABINDING不会改善基数估计。我创建了一个简单的表:

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

INSERT dbo.myobjects SELECT [object_id] FROM sys.all_objects;
Run Code Online (Sandbox Code Playgroud)

然后是两个函数:

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
Run Code Online (Sandbox Code Playgroud)

比较实际计划,两者都显示估计行数 = 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 Code Online (Sandbox Code Playgroud)

结果:

                    run 1               run 2
----------------    ------------------  ------------------
No schemabinding    14632 milliseconds  14079 milliseconds
Schemabinding       14251 milliseconds  13979 milliseconds
Run Code Online (Sandbox Code Playgroud)

那么,重要吗?不。

SCHEMABINDING在这种情况下,用于更重要的目标:底层架构稳定性。如果您将函数转换为内联 TVF,而不是在多语句 TVF 中寻找影响计划的模糊差异,那么您可能会有更好的优化机会。