我正在通过存储过程让它们变得可靠,我注意到有关如何使用索引的意外情况。
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
答案 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'
,将返回所有记录。