Grz*_*Łyp 5 sql-server execution-plan startup sql-server-2016
对于下面代码的最后两个语句,生成实际的执行计划。您可以看到启动谓词 on@Par1被放置在不同的位置,这完全改变了来自test_fn1函数的实际行数。我需要控制这种行为。
create or alter function dbo.test_fn1(@Par1 varchar(100), @Par2 varchar(1))
returns @t table(item varchar(100))
as
begin
insert into @t (item) select value from STRING_SPLIT(@Par1, @Par2);
return
end
GO
create or alter function dbo.test_fn(@Par1 varchar(100), @Par2 varchar(100))
returns table
as
return (
select s.*
from dbo.test_fn1(@Par2,';') x
inner join sys.objects s on s.name = x.item
where @Par1 = 'CASE1'
)
GO
create or alter function dbo.test_fnx(@Par1 varchar(100), @Par2
varchar(100))
returns table
as
return (
select s.*
from sys.objects s
inner join dbo.test_fn1(@Par2,';') x ON s.name = x.item
where @Par1 = 'CASE1'
)
GO
declare @Par1 varchar(100), @Par2 varchar(100)
select @Par1 = 'CASE2', @Par2 = 'test1;test2'
select * from dbo.test_fn(@Par1, @Par2)
select * from dbo.test_fnx(@Par1, @Par2)
Run Code Online (Sandbox Code Playgroud)
这是显示放置启动谓词的错误行为的计划。在这两种情况下,我们都从相同的函数开始,并且仅更改了 T-SQL 中的顺序。

在 SQL Server 2016 SP2 上测试。
是否有任何关于 SQL Server 如何放置启动谓词的白皮书或文档?
是否有任何关于 SQL Server 如何放置启动谓词的白皮书或文档?
不,不是我见过的。他们没有写那么多。有一次我写博客关于他们,我做了很多挠头。
现在,我有了一个答案——它不能保证总是有效。它在优化器上发挥了一些技巧,您可以通过观看Adam Machanic 的演讲Query Tuning Mastery: Clash of the Row了解更多信息。
有了这个,我们可以在一定程度上控制优化器决定使用 TOP 保留谓词的位置。
函数重写1:
在这个中,WHERE子句出现在CROSS APPLY.
CREATE OR ALTER FUNCTION dbo.test_erik ( @Par1 VARCHAR(100), @Par2 VARCHAR(100))
RETURNS TABLE
AS
RETURN ( SELECT s.*
FROM sys.objects AS s
CROSS APPLY
( SELECT TOP (2147483647) *
FROM dbo.test_fn1(@Par2, ';') AS x
WHERE s.name = x.item
AND @Par1 = 'CASE1' ) AS ca );
GO
Run Code Online (Sandbox Code Playgroud)
函数重写2:
在这一个中,该WHERE子句出现在CROSS APPLY.
CREATE OR ALTER FUNCTION dbo.test_erikx ( @Par1 VARCHAR(100), @Par2 VARCHAR(100))
RETURNS TABLE
AS
RETURN ( SELECT s.*
FROM sys.objects AS s
CROSS APPLY
( SELECT TOP (2147483647) *
FROM dbo.test_fn1(@Par2, ';') AS x
WHERE s.name = x.item ) AS ca
WHERE @Par1 = 'CASE1' );
GO
Run Code Online (Sandbox Code Playgroud)
在计划 1 中,启动表达式谓词出现在 TOP 内部:
在计划 2 中,它出现在外面。
如果您希望启动表达式谓词充当常量扫描,请尝试以下操作:
CREATE OR ALTER FUNCTION dbo.test_erik_filter ( @Par1 VARCHAR(100), @Par2 VARCHAR(100))
RETURNS TABLE
AS
RETURN (
SELECT ca.*
FROM (
SELECT TOP (1) 1 AS n
WHERE @Par1 = 'CASE1'
) AS x
CROSS APPLY
(
SELECT s.*
FROM sys.objects AS s
INNER JOIN dbo.test_fn1(@Par2, ';') AS x
ON s.name = x.item
) AS ca
);
GO
Run Code Online (Sandbox Code Playgroud)
如果我们运行两个不同的测试用例,计划会略有不同:
DECLARE @Par1 VARCHAR(100), @Par2 VARCHAR(100);
SELECT @Par1 = 'CASE2', @Par2 = 'test1;test2';
select * from dbo.test_erik_filter(@Par1, @Par2)
GO
DECLARE @Par1 VARCHAR(100), @Par2 VARCHAR(100);
SELECT @Par1 = 'CASE1', @Par2 = 'test1;test2';
select * from dbo.test_erik_filter(@Par1, @Par2)
GO
Run Code Online (Sandbox Code Playgroud)
查看实时查询计划(这里是常规查询计划),有几个早期的重要差异。
请记住,数据在查询计划中从右向左流动。将过滤器更靠近计划的左侧对于减少工作量没有任何好处。
Aaron Bertrand 在这里讨论了一个与常规过滤器类似的问题:
顺便说一句,如果您的实际代码不只是从系统表/视图中进行选择,您应该考虑向其中添加SCHEMABINDING属性,这有助于过滤器放置。
希望这可以帮助!
| 归档时间: |
|
| 查看次数: |
277 次 |
| 最近记录: |