当OR @param = 1添加到WHERE子句

时间:2015-08-10 07:36:18

标签: sql-server indexing

我正在通过存储过程让它们变得可靠,我注意到有关如何使用索引的意外情况。

DateColumn上有非聚集索引,表上有聚簇索引(未在查询中直接引用)。

虽然以下内容对使用DateColumn作为索引列的非聚集索引使用索引搜索:

DECLARE @timestamp as datetime
SET @timestamp = '2014-01-01'

SELECT column1, column2 FROM Table WHERE DateColumn > @timestamp

但以下使用索引扫描:

DECLARE @timestamp as datetime
DECLARE @flag as bit
SET @timestamp = '2014-01-01'
SET @flag = 0

SELECT column1, column2 FROM Table WHERE (DateColumn > @timestamp) OR (@flag = 1)

我把括号放在以防万一,但当然没有区别。

因为@flag = 1与表无关,所以我期待在这两种情况下进行搜索。如果我将其更改为0 = 1,则无关紧要,它会再次使用索引搜索。 @flag值是一个过程的参数,告诉查询返回所有记录,所以我不能在现实中硬编码。

有没有办法让这个使用搜索而不是扫描?我能想到的唯一选择是以下,但实际上查询要复杂得多,因此这样的重复会损害可读性和可维护性:

DECLARE @timestamp as datetime
DECLARE @flag as bit
SET @timestamp = '2014-01-01'
SET @flag = 0

IF @flag = 1
BEGIN
    SELECT column1, column2 FROM Table 
END
ELSE
BEGIN
    SELECT column1, column2 FROM Table WHERE DateColumn > @timestamp
END

3 个答案:

答案 0 :(得分:2)

尝试使用这样的动态SQL。

DECLARE @flag  BIT,
        @query NVARCHAR(500)

SET @flag=0
SET @query='
SELECT <columnlist>
FROM   <tablename> 
WHERE  columnname = value
or 1=' + CONVERT(NVARCHAR(1), @flag)

EXEC Sp_executesql
  @query 

答案 1 :(得分:1)

你的动态解决方案实际上更好,因为当你第一次传入@ flag = 1时你不会被抓住,这就是你所有后续调用的结果。正如@RaduGheorghiu所说,在这些情况下,扫描比寻找更好。

如果是我,我将有2个程序,一个用于“获取所有内容”,一个用于“获取日期”。两个程序,两个用法,两个查询计划。如果重复困扰你,你可以介绍一个观点。

答案 2 :(得分:0)

为了完整起见,我将发布一个我刚刚意识到在我的具体情况下工作的选项。由于简单性,这可能是我要使用的,但是99.9%的情况可能不会起作用,所以我不认为它比动态SQL更好。

declare @flag as int
declare @date as datetime
set @flag = 1
set @date = '2015-08-11 09:12:08.553'

set @date = (select case @flag when 1 then '1753-01-01' else @date end)

select Column1, Column2
from Table_1
where DateColumn > @date 

上述方法有效,因为DateColumn存储了记录的修改日期(我返回的增量)。它的默认值为getdate(),并在更新时设置为getdate()。这意味着在这个特定情况下我知道,对于值@date = '1753-01-01',将返回所有记录。

相关问题