Sql server 将可选参数最优地传递到查询中
我有一个带有可选参数的参数化查询。 多个表被联接。 WHERE子句的一部分如下所示:Sql server 将可选参数最优地传递到查询中,sql-server,sql-server-2008-r2,Sql Server,Sql Server 2008 R2,我有一个带有可选参数的参数化查询。 多个表被联接。 WHERE子句的一部分如下所示: and ((x.a = @arg1) OR (@arg1 IS NULL)) and ((y.b = @arg2) OR (@arg2 IS NULL)) and ((z.c = @arg3) OR (@arg3 IS NULL)) 因此,其思想是:一个参数可以用于应用过滤器,或者,如果该参数为NULL,则不会应用任何过滤 然而,我发现执行计划并不适合这段代码。 当实际设置了一个参数时,编写 and x.a
and ((x.a = @arg1) OR (@arg1 IS NULL))
and ((y.b = @arg2) OR (@arg2 IS NULL))
and ((z.c = @arg3) OR (@arg3 IS NULL))
因此,其思想是:一个参数可以用于应用过滤器,或者,如果该参数为NULL,则不会应用任何过滤
然而,我发现执行计划并不适合这段代码。
当实际设置了一个参数时,编写
and x.a = @arg1
而不是
and ((x.a= @arg1) OR (@arg1 IS NULL))
事实上,我总共有8个表连接在一起。在这两条语句中,所有8个表都被联接,并且在所有这些表上应用了相同的索引查找/扫描。但是,连接顺序不同,因此导致不同的执行速度
有没有办法重写上面的语句,使执行计划能够最佳工作?可能有一些查询提示
还是说没有办法编写动态SQL?我想避免后者,因为
- 动态SQL很难阅读
- SSMS不显示依赖项
- 将参数传递到动态SQL非常糟糕
合并(@arg1,x.a)
而不是((x.a=@arg1)或(@arg1为空))
不幸的是,乐观主义者倾向于坚持任何适合第一次调用的计划。最好的选择是为每个组合(或至少主要组合)编写一个存储过程,或者尝试
OPTION(RECOMPILE)
,这将花费时间来评估实际参数,但要付出一定的代价
要回答您关于“是否有方法重写上述语句,以使执行计划能够最佳工作?”的问题,答案可能不是。有太多的变化,不可能想出一个单一的计划,有这么多可能不会发生的事情(你的空变量) 好主意,但结果是一样的:(那么我猜,
x.a=CASE当@arg1为NULL时,那么x.a ELSE@arg1 END
也不会有帮助,但值得一试。你能发布执行计划吗?不管你做什么,动态sql都应该被视为最后的手段。是的,CASE当
时,结果是一样的。实际语句连接了8个表,因此执行计划是big.将尝试以某种方式发布。在这两种情况下,所有8个表都被联接,并且在所有这些表上应用了完全相同的索引查找/扫描。但是,联接顺序不同,因此导致执行速度不同。很难优化您一无所知的查询。是的,选项(重新编译)
很好!与合并
变体[@ZoharPeled]结合使用,它会产生与手写变体相同的执行计划。这是一个缺点,仅重新编译时间会花费大约70毫秒的额外时间。因此,我将在这里坚持所有答案的组合。从性能角度来看,动态SQL是此任务的最佳解决方案。尽管您对依赖关系的看法是正确的,但不难理解阅读是否遵循了良好的编码实践。我不确定我是否理解传递参数的困难。传递到DynSQL的参数并不是很难,我只是不喜欢通过为每个“外部”创建一个“内部”参数将每个参数“隧道”到DynSQL的方式参数,然后将整个过程传递到exec函数中。但是很好。;)您可以在传递给sp_executesql的声明字符串中声明所有内部
参数,并无条件映射内部/外部
参数值。性能的关键是有条件地构建WHERE子句,以便只指定搜索实际需要的谓词。
and x.a = COALESCE(@arg1, x.a)
and y.b = COALESCE(@arg2, xyb)
and z.c = COALESCE(@arg3, z.c)