Tsql 对函数使用OR@参数为NULL时出现奇怪的性能问题

Tsql 对函数使用OR@参数为NULL时出现奇怪的性能问题,tsql,Tsql,我正在研究遗留代码,因为它的性能非常差。 我把这个问题追查到 DECLARE @Parameter AS VARCHAR(50) = '12345' SELECT * FROM MyTable WHERE ( MyIndexedField IN ( SELECT Value from fn_Function(@Parameter) ) OR @Parameter ISNULL; ) AND OtherCriteria = 'Something' 查询希望从具有非聚集索引的字段

我正在研究遗留代码,因为它的性能非常差。 我把这个问题追查到

DECLARE @Parameter AS VARCHAR(50) = '12345'
SELECT *
FROM MyTable
WHERE 
(
    MyIndexedField IN ( SELECT Value from fn_Function(@Parameter) )
    OR @Parameter ISNULL;
)
AND OtherCriteria = 'Something'
查询希望从具有非聚集索引的字段上的表中提取所有数据。当我删除或@Parameter为NULL时,它会在一秒钟内运行,但当我添加@Parameter为NULL时,它需要40s+

如果我用一个文本替换函数,它将在一秒钟内运行。 范例

知道发生了什么吗?还有更好的方法重写这个查询吗

这是在SQL 2008上运行的

谢谢


编辑

我能够绕过这个问题,但解决方法很奇怪,见下文。 不要认为这是最好的解决方案,如果您有任何建议,我们将不胜感激

DECLARE @Parameter AS VARCHAR(50) = '12345'
SELECT DISTINCT MyIndexedField
INTO #T
FROM MyTable WHERE @Parameter IS NULL

UNION ALL

SELECT Value FROM fn_Function(@Parameter)

SELECT *
FROM MyTable AS X
JOIN #T      AS T ON T.MyIndexedField = X.MyIndexedField
WHERE OtherCriteria = 'Something'

在没有看到执行计划和了解fn_功能实际作用的情况下,很难给出结论性建议,但值得探讨的两个想法是:

1) 如果在语句末尾添加选项(重新编译),那么优化器将能够“看到”@Parameter参数的值,因此将能够优化掉@Parameter为NULL的条件(对于此特定输入值),而每次调用该语句时都必须重新编译该条件(而不是存储在执行计划缓存中)。根据调用频率/编译成本,这可能是一种可行的策略

2) 根据函数fn_函数的复杂性,您可以在线重新编写它。如果没有看到函数,我就无法知道它是一个多语句函数还是一个内联表值函数,这在这里是相关的

希望这能给我们提供一些参考

DECLARE @Parameter AS VARCHAR(50) = '12345'
SELECT DISTINCT MyIndexedField
INTO #T
FROM MyTable WHERE @Parameter IS NULL

UNION ALL

SELECT Value FROM fn_Function(@Parameter)

SELECT *
FROM MyTable AS X
JOIN #T      AS T ON T.MyIndexedField = X.MyIndexedField
WHERE OtherCriteria = 'Something'