使用OR @Parameter IS NULL和函数时出现奇怪的性能问题

时间:2014-10-30 19:38:56

标签: 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'

查询想要从具有非聚集索引的字段的表中提取所有数据。当我删除OR @Parameter IS NULL时,它会在一秒钟内运行,但是当我添加@Parameter IS NULL时需要40s +。

如果我用文字替换该函数,它会在一秒钟内运行。 实施例

SELECT *
FROM MyTable
WHERE 
(
    MyIndexedField IN (  '12345' )
    OR @Parameter ISNULL;
)
AND OtherCriteria = 'Something'

有什么想法,还有更好的方法可以重写这个查询吗?

这是在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'

1 个答案:

答案 0 :(得分:0)

如果没有看到执行计划并知道fn_Function函数实际上做了什么,很难给出确凿的建议,但是值得探讨的几个想法是:

1)如果你在语句的末尾添加OPTION(RECOMPILE),那么优化器将能够看到' @Parameter参数的值因此能够以' cost'来优化OR @Parameter IS NULL条件(针对此特定输入值)。每次调用此语句时都必须重新编译(而不是存储在执行计划缓存中)。根据呼叫频率/编译成本,这可能是一个可行的策略

2)取决于函数fn_Function的复杂性,您可以在线重新编写它。如果它是一个多语句或内联表值函数,我无法在不看函数的情况下知道,这与此相关。

希望这能给出一些关于要看的内容的指示。