进行以下查询:
DECLARE @X VARCHAR(200) = '1,2,3,4'
SELECT
*,
dbo.aUserDefinedScalarFunction(4) AS ScalarValue
FROM
MyTable T
INNER JOIN dbo.aUserDefineTableFunction(@X) A ON T.SomeID=A.SomeID
WHERE
(T.ID1 IS NULL OR T.ID1 IN (SELECT [value] FROM STRING_SPLIT(@X,',')))
AND
(T.ID2 IS NULL OR T.ID2 IN (SELECT Value FROM dbo.MySplitterFunction(@X))
我通常为上述条件创建索引#tempTables WHERE
,我发现它在大型数据集上表现更好。但是,我仍然无法找到以下问题的明确答案:
查询分析器会将 aUserDefinedScalarFunction(4) 优化为 ScalarValue 还是针对每条记录进行评估?
INNER JOIN dbo.aUserDefineTableFunction(@X) 会在临时表中实现一次,还是会为每条记录执行?该函数返回表(不是表变量)。
SELECT [value] FROM STRING_SPLIT(@X,',') 的结果是否得到优化,还是针对每次比较进行评估?
SELECT Value FROM dbo.MySplitterFunction(@X) 的结果是否得到优化或在每次比较期间进行评估?
这取决于功能。对于使用schemabinding指定的确定性函数,优化器通常只能评估其结果一次,并缓存答案。
有关详细信息,请参阅:
内联表值函数在优化之前扩展为调用查询文本,因此没有特殊机会进行早期评估和缓存。这并不意味着执行计划不会包含任何缓存和重用优化。在适用的情况下,优化器将考虑那些(例如假脱机),就像它对没有内联函数的查询一样。
通常,优化器将能够判断
SPLIT_STRING
在恒定输入上返回确定性结果。该计划可能只评估一次拆分,但这确实取决于计划的形状。假设 splitter 函数是一个多语句表值函数,那么结果很可能只求值一次。有关详细信息,以及如何判断执行计划中是否发生缓存,请参阅:
综上所述,你对这一切保持谨慎是对的。优化器将经常能够评估表达式一次并重用结果,但这并不能保证,并且通常需要专家分析来确定。
使用临时表强制实现通常是最强大的解决方案,因为它保证了特定的评估顺序和数量。
每一行都会评估 where 子句中的函数。研究 SARGABLE 查询。 https://www.sqlshack.com/how-to-use-sargable-expressions-in-t-sql-queries-performance-advantages-and-examples/