Mar*_*man 5 sql-server-2005 sql-server functions cardinality-estimates
根据查询性能和多语句表值函数等文章,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;
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 中寻找影响计划的模糊差异,那么您可能会有更好的优化机会。