动态生成where子句的最佳方法是什么?

JSW*_*ork 3 sql performance sql-server-2008

我正在编写一个使用重型select语句的存储过程.存储过程接受大约15个参数作为过滤器,所有这些参数都是NULLable.

参数通常有两件事 - 检查x是否在高和低之间或检查列值是否在y中.

我主要担心的是我如何编写where子句.

示例:动态SQL非常慢,因此我不想编写where子句,然后将其传递给exec.

我不想这样做,if High = null then High = max因为那时我仍然会有一个占用处理能力但没有用处的声明.

我不想这样做,(if High = null or X <= High)因为仍然会为每一行处理空检查,并且我听到传言会混淆索引.

简而言之,我正在寻找考虑性能的最佳实践的指导.

Jus*_*tin 7

动态SQL过去很慢,因为没有缓存动态生成的SQL的执行计划.这不再是这种情况,只要查询文本相同,动态SQL查询的执行计划就会被缓存.这意味着你应该:

  • 使用参数可以避免参数值更改查询文本
  • 尝试对where子句进行排序,使它们以相同的顺序出现

只要你这样做,那么你的查询计划应该被缓存(每个可能的查询变体一个),动态SQL不会比任何普通查询慢.


您应该避免使用其他建议(将各种参数设置为NULL),并且实际上可能执行得非常糟糕 - 语句只能有一个缓存的查询计划,但最佳查询计划将取决于参数,并且根据值可能会有很大差异提供.

例如,一组参数可能导致返回大部分表,在这种情况下,表扫描可能是最佳的.另一组参数可能导致返回单行,在这种情况下,行查找可能是最佳的.SQL Server必须选择缓存这两个计划中的一个(可能是基于第一次运行查询时提供的参数的最佳计划),但无论选择哪个计划,查询都可能在相反的情况下执行得很糟糕.(这是一种过度简化,但我已经看到了这种情况的变化,它可能会产生非常显着的性能影响).

最终这将意味着:

  • 大多数情况下,选择的查询计划可能不是最优的,或者
  • 您可以强制SQL Server为每次执行生成新计划,这始终会产生合理的执行计划,但会消除计划缓存的优势

替代aproaches的另一个缺点是它会导致更复杂的查询,这会使查询优化器难以正确优化查询.

出于这些原因,我会说动态SQL绝对是更好的选择.