如何使用大型复杂的where子句构造查询?

时间:2012-01-30 15:56:08

标签: sql sql-server sql-server-2005

我有一个SQL查询,它接受以下参数:

@SearchFor  nvarchar(200) = null 
,@SearchInLat Decimal(18,15) = null
,@SearchInLng Decimal(18,15) = null
,@SearchActivity int = null
,@SearchOffers bit = null
,@StartRow int
,@EndRow int

变量@SearchFor@SearchActivity@SearchOffers可以为null或非null。 @SearchInLat@SearchInLng必须都为null,或者两者都有值。

我不打算将整个查询发布为无聊且难以阅读,但WHERE子句的形状如下:

( -- filter by activity --
    (@SearchActivity IS NULL)
    OR (@SearchActivity = Activities.ActivityID)
)
AND ( -- filter by Location --
    (@SearchInLat is NULL AND @SearchInLng is NULL)
    OR ( ... )
)
AND ( -- filter by activity --
    @SearchActivity is NULL
    OR ( ... )
)
AND ( -- filter by has offers --
    @SearchOffers is NULL
    OR ( ... )
)
AND (
    ... -- more stuff
)

我已经读过,这是构建查询的一种不好的方法 - SqlServer在制定一个有效的执行计划方面遇到了麻烦,因为我正在寻找其他方法来实现它。

我看到两种方法:

  1. 在我的客户端应用程序中将查询构造为字符串,以便WHERE子句仅包含相关参数的过滤器。这个问题是它意味着不能通过存储过程访问数据库,就像其他所有东西一样。
  2. 更改存储过程,以便检查哪些参数为null,并根据传递的参数执行子过程。这里的问题是它会在procs的定义中重复自己,因此更难维护。
  3. 我该怎么办?或者我应该继续,因为我目前在做什么?我有OPTION (RECOMPILE)设置程序,但我听说这在Server 2005中不起作用。而且,我打算在这个proc中添加更多参数,所以我想确保我有什么解决方案是相当可扩展的。

3 个答案:

答案 0 :(得分:4)

答案是使用DynamicSQL(无论是在客户端,还是在使用sp_executesql的SP中),但原因很长,所以这里有一个链接......

Dynamic Search Conditions in T-SQL

非常短的版本是单一尺寸不适合所有。由于优化器为一个查询创建了一个计划,因此速度很慢。所以解决方案是继续使用参数化查询(用于执行计划缓存),但是对于可能发生的不同类型的搜索有很多查询。

答案 1 :(得分:1)

也许替代方案可能是执行几个单独的select语句?

e.g。

( -- filter by activity --
if @SearchActivity is not null
    insert into tmpTable (<columns>)
    select *
    from myTable
    where (@SearchActivity = Activities.ActivityID)
)

( -- filter by Location --
if @SearchInLat is not null and @SearchInLng is not null
    insert into tmpTable (<columns>)
    select *
    from myTable
    where (latCol = @SearchInLat AND lngCol = @SearchInLng)

等...

然后选择临时表以返回最终结果集。

我不确定这对于优化器和查询计划是如何工作的,但是每个单独的选择都非常简单,并且可以利用您在每列上创建的索引,这些索引应该非常快。

根据您的要求,在临时表上创建主键以允许您在每次选择时加入它(以避免重复)也是有意义的。

答案 2 :(得分:0)

首先看一下表演,就像其他人说的那样。

如果可能,您可以使用IF子句根据提供的参数简化查询。

如果您发现经常重复某些代码,也可以使用函数或视图来封装一些代码。