替代在where子句中使用局部变量

时间:2011-03-08 18:22:58

标签: sql sql-server-2008

我有一个查询,其中有一个使用多个局部变量构建的where子句,但这很慢。下面是一个粗略的例子,因为我目前无法访问查询:

declare @a varchar(50), @b varchar(50), @c varchar(50)
set @a = '%'
set @b = 'foo'
set @c = '%bar'

我的where子句类似于

where a = @a and b = @b and c =@c

这需要大约1分钟才能运行。但是,如果我直接引用where子句中的值,例如:

where a = '%' and b = 'foo' and '%bar'

大约需要5秒钟。

所以我的问题是,有没有更好的方法来构建我的where子句?需要注意的一件重要事情。 where子句中使用了大约10个局部变量,但大多数都设置为默认值%

提前致谢

4 个答案:

答案 0 :(得分:6)

在WHERE过滤器中使用局部变量会导致FULL TABLE SCAN。因为SS在编译时不知道局部变量的值。因此,它创建了一个可用于该列的最大规模的执行计划。

为了防止性能问题,SS必须在编译时知道变量的值。定义SP,将这些局部变量作为参数传递是问题的解决方案之一。另一个解决方案是,使用 sp_executesql 并再次将这些局部变量作为参数传递...

或者您可以在sql语句的末尾添加 OPTION(RECOMPILE),以便编译本地变量。这将解决性能问题。

答案 1 :(得分:4)

没有

对于常量,优化器可以根据给定值的统计数据计算出最佳计划。

当您使用变量时,您正在强制参数化,并且该计划将被设计为可以重复使用各种值。

在这种情况下,您可以尝试OPTIMISE FOR UNKNOWN,这可能会提供更好的结果。或者不要像这样过滤:对不同的排列使用不同的查询。你是否也喜欢领先的通配符?

答案 2 :(得分:0)

它变得混乱并且可能导致一组新的问题,但您可能想要评估将其转换为动态SQL。基本上,您在运行时根据哪些参数实际具有(非通配符)值来构造您的where子句。

这是我发现的最好的动态SQL写作之一: http://www.sommarskog.se/dynamic_sql.html

这是另一个他专门处理动态where子句的地方: http://www.sommarskog.se/dyn-search-2005.html

答案 3 :(得分:0)

gbn提供的{p> Optimise for unknown可能在某些情况下起作用,但在其他情况下,OPTION RECOMPILE可能是更好的选择。

对于在极值之间变化的数据集的简单查询,OPTION RECOMPILE为每个案例提供最佳计划,因为它实际上使用静态值计划每个查询(每次执行的计划成本),但是OPTIMISE FOR UNKNOWN导致通用计划在任何情况下都不是最好的,对所有情况都是平均的(缓存计划)。

样本用法

select top 10 * from master..spt_values
OPTION (RECOMPILE)

SQL Server 2005中有一些OPTION RECOMPILE的边缘案例错误,但它在2008年运行良好。