Sql 为什么通过使用子查询调用UDF来提高查询性能?

Sql 为什么通过使用子查询调用UDF来提高查询性能?,sql,sql-server,performance,tsql,user-defined-functions,Sql,Sql Server,Performance,Tsql,User Defined Functions,我最近意识到,在子查询中调用UDF要比直接调用UDF好得多,为什么会发生这种情况 例如: CREATE FUNCTION [CurrentYearStart]() RETURNS DATETIME AS BEGIN DECLARE @Date DATETIME; SELECT top 1 @Date = StartPeriod FROM SystemPeriods WITH (NOLOCK); RETURN @Date; END ProviderServiceA

我最近意识到,在子查询中调用UDF要比直接调用UDF好得多,为什么会发生这种情况

例如:

CREATE FUNCTION [CurrentYearStart]()
RETURNS DATETIME
AS
BEGIN
    DECLARE @Date DATETIME;
    SELECT top 1 @Date = StartPeriod
    FROM SystemPeriods WITH (NOLOCK);
    RETURN @Date;
END
ProviderServiceArea有412585行

下面的查询大约在50秒后返回

SELECT   PayGroup, SystemType, MAX(EffDt) AS MaxEffDt
FROM     CAT.ProviderServiceAreas
WHERE    EffDt > CurrentYearStart() 
GROUP BY Paygroup, SystemType 
执行计划:

下面的查询大约1s后返回

SELECT   PayGroup, SystemType, MAX(EffDt) AS MaxEffDt
FROM     CAT.ProviderServiceAreas
WHERE    EffDt > (SELECT CurrentYearStart()) 
GROUP BY Paygroup, SystemType 
执行计划:

我会选择:

SELECT PayGroup, SystemType, MAX(EffDt) AS MaxEffDt
FROM ServiceAreas CROSS JOIN
     (SELECT StartPeriod() as sp) sp
WHERE EffDt > sp.sp
GROUP BY Paygroup, SystemType ;

显然,性能差异在于调用函数的次数。如果您将函数调用放在
FROM
子句中,您将有更多的控制权。

可能查询缓存类似于这两种缓存的执行计划是什么?
我注意到,通过在子查询中调用函数,它们只会执行函数一次
=>缓存:)无论如何,您的函数是非常危险的(没有ORDER by+NOLOCK的前1)不管怎样,我都会去掉这个函数。标量函数的性能是出了名的差。要么将其转换为内联表值函数,要么只执行子查询。这不是真正的缓存。这意味着函数被多次执行并重放缓存的结果。我会想象一个不同的树形,它对函数求值一次,然后将结果用作相关参数。显然不是,我测试过,得到了一个与最坏情况非常相似的执行计划,大约在同一时间50秒..@IsraelGarcia。真奇怪。函数本身会不会有性能问题,有时需要很长时间,有时不会?Gordon函数是对包含1条记录的表的一个非常简单的调用,问题是因为我放置子查询时的执行计划与直接调用函数完全不同。检查我在问题文本中添加的执行计划。