内联表值函数与内联 sql

Ben*_*hul 5 sql-server sql-server-2008-r2

我在尝试调整内联表值函数时看到了一些奇怪的行为。具体来说,如果我使用函数的胆量,并使用与我调用函数时相同的参数,我会看到大约 3 倍的性能提升。所以像这样(大大简化):

create function dbo.FooToDate(@ToDate date)
returns table
as
return (

select f.a, f.b, b.c
    from dbo.[Foo] as f
    left join dbo.Bar as b
       on f.fId = b.fId
    where f.ToDate >= @ToDate

)
go
declare @ToDate date = '2012-12-21'

--runs in about 4 seconds
select f.a, f.b, b.c
from dbo.[Foo] as f
left join dbo.Bar as b
   on f.fId = b.fId
where f.ToDate >= @ToDate

--runs in about 12 seconds
select a, b, c from dbo.FooToDate(@ToDate)
Run Code Online (Sandbox Code Playgroud)

当我查看针对我的实际情况的查询计划时,整体形状大不相同。我对内联 TVF 的理解是优化器能够展开函数,所以这种行为对我来说有些奇怪。是否有一个简单(或不那么简单)的解释?

Seb*_*ine 2

在 SQL Server 2000 及更早版本中,我们都习惯于使用逻辑等效查询的交替形式作为查询调优的手段。

从那时起,优化器已经有了很大的改进,如果两个不同但逻辑上等效的查询导致不同的执行计划,我们会感到惊讶。

然而,即使对于中等复杂的查询,给定查询的所有可能执行计划的搜索空间也很大,因此优化器不可能查看所有这些计划。优化器使用启发式和规则以及有关数据的信息的组合来确定在找到第一个合适的计划后下一步要查看的位置。如果查询足够复杂,即使像这样的微小更改也可以将优化器设置在完全不同的路径上,最终导致运行时间如此大的差异。(查看我关于连接提示的帖子,了解对此的更详细讨论:http://sqlity.net/en/1443/a-join-a-day-join-hints/

通常,我们可以通过确保优化器决策所依据的信息尽可能准确来解决这种情况。这意味着,您应该确保您的表已适当索引并且所有统计信息都是最新的。您还可以考虑向所涉及的表添加额外的(可能是过滤的)统计信息。