2010-06-23 130 views
0

我想用存储过程编写一个查询并使用多个过滤器,但我想避免动态SQL。Sql Server查询优化

说我的参数可以为空(@ filter1,@ filter2,@ filter3 ...)。我可能会解决这个问题的一种方法是:

SELECT col1, col2, col3 
FROM table 
WHERE col1 = ISNULL(@filter1, col1) 
AND col2 = ISNULL(@filter2, col2) 
AND col3 = ISNULL(@filter3, col3) 

如果不是null,则会通过适当的过滤器进行过滤。问题是: 1)这是一种很好的做法吗? 2)优化器会优化col1 = col1 out还是会影响查询性能?

+3

性能会很糟糕,因为有很多可能的组合,查询计划不可能被缓存。动态SQL是一个更好的选择。 – 2010-06-23 20:09:49

回答

3

Erland Sommarskog将这种类型的问题放在一起an excellent article。我强烈建议通读它。

0

ISNULL可能会伤害索引使用,所以我不会说这是理想的,但如果您需要上述功能,我不确定是否有解决方法。

你可以看看你的执行计划,看看你期望使用的索引是否被使用?

+0

这个构造通常工作正常。 COALESCE可以成为杀手,因为它如何对待数据类型 – gbn 2010-06-23 20:14:55

+0

有趣的是,ISNULL vs COALESCE的任何推荐读物? – 2010-06-23 20:21:06

0

1)这是一种很好的做法吗? 2)优化器会优化col1 = col1 out还是会影响查询性能?

是的,这是一个很好的做法。

有些RDBMS会优化它,有些不会。如果您将其称为准备好的声明,则不会。

不要过早地优化;对于大多数情况来说,成本差异可以忽略不计,或者如果不是,可以忽略适当的指数。

专注于编写明确表达你正在做的事情的代码。在我看来,这个成语很清晰简洁。

+1

我很大的支持者并没有试图过早地进行优化,但是在这种情况下,性能影响往往很大,而且索引不太可能提供帮助,因为查询可能每次都会做出不同的事情。这种类型的功能通常是系统范围的(即你需要在许多不同的表上进行动态搜索),因此在编写50个SP之前必须知道你的一般方法,然后你必须重写。 – 2010-06-23 20:17:59

+1

这并不是过早的优化,它应该在每个数据库上进行性能优化。当技术之间的表现存在差异时,应从一开始就选择表现最好的一种。 Databasea是非常难以重构的。表现已成问题为时已晚。过早优化并不意味着没有优化。 – HLGEM 2010-06-23 20:35:55

0

如果您希望这个表将增长到任何实质性的规模,这是不是一个好主意,因为查询优化器将不缓存执行计划和优化,在吸用的情况下处理这样的,因为它不能轻易告诉在编译时执行路径将是什么。

只要在客户端使用where子句中的正确过滤器生成查询,而不是尝试写入单个全部捕获查询,那将会好得多。

0

根据我的经验(运行大表上一些基准)以下:

(col1 = @filter or @filter IS NULL) 

比快得多:

col1 = ISNULL(@filter1, col1) 
1

关于优化的条件:你必须知道的是,一个编制计划必须满足任何变量值。因此,当生成计划时,SQL Server 必须创建一个访问计划,该计划在@ filter1为NULL时起作用,并且在@ filter1不为NULL时也起作用。结果几乎总是一个扫描。

汤姆H.链接的文章详细介绍了这一点。