当我在WHERE
子句中使用字符串文字时,我有一个非常快速(大约1秒)运行的简单查询,例如:
select *
from table
where theDate >= '6/5/2016'
然而,这个查询(没有实质性的不同)在2分钟内运行:
declare @thisDate as date
set @thisDate = '6/5/2016'
select *
from table
where theDate >= @thisDate
我尝试使用OPTION(RECOMPILE)
建议here,但它没有改善性能。列theDate
是日期时间,此数据库最近从SQL Server 2005迁移。
我的theDate
列上没有索引,该表的行数超过10亿。它是一个共享资源,我不想在没有保证它会有所帮助的情况下开始编制索引。
我发现使用逻辑而不是变量提供与字符串文字相同的性能:
select *
from table
where theDate >= dateadd(dd, -23, getdate())
但是,如果我用变量整数替换日期整数,性能再次受到阻碍。
如何包含变量并保持性能?
修改
请求包含的实际查询:
DECLARE @days INT
Set @days = 7
select c.DEBT_KEY
, c.new_value
, c.CHANGE_DATE
from changes c with (nolock)
where c.C_CODE = 3
and c.old_value = 4
and c.CHANGE_DATE >= dateadd(dd, -@days, getdate())
没有加入。
查询计划
使用变量(xml explain plan):
使用字符串文字(xml explain plan):
所以我可以看到区别在于变量调用聚簇索引扫描(聚集),而字符串文字调用密钥查找(聚集)...我需要引用谷歌,因为我真的不知道任何东西关于这些的表现利弊。
编辑编辑
这有效(xml explain plan):
DECLARE @days INT
Set @days = 7
select c.DEBT_KEY
, c.new_value
, c.CHANGE_DATE
from changes c with (nolock)
where c.CHANGE_CODE = 3
and c.old_value = 4
and c.CHANGE_DATE >= dateadd(dd, -@days, getdate())
OPTION(OPTIMIZE FOR (@days = 7))
......我不知道为什么。此外,我不喜欢这个解决方案,因为它否定了我使用变量的目的,即将所有变量放在proc的顶部,以减少在不可避免的维护期间在代码中徘徊的需要。
答案 0 :(得分:0)
快速版本执行群集密钥查找(可以直接到表中找到该值的部分)。
慢速版本执行非群集搜索,然后将其与聚集索引扫描合并(它必须扫描整个表格)。
我看到@thisDate
变量定义为Date
类型。该列是否可以定义为DateTime
?如果这是真的,@thisDate
中的任何值都不会与您的聚簇索引完全对齐,这意味着数据库将必须检查整个表,如我们在此处所示。另一方面,字面值将被解释为DateTime
值, 匹配您的表列类型,并将与索引一起使用。
如果这是正确的,你可以通过一个非常简单的改变来解决问题:
declare @thisDate as datetime
set @thisDate = '6/5/2016'
只有4个字符的差异。
您也可以与OPTION(RECOMPILE)
一起试用,也可以查看OPTIMIZE FOR UNKNOWN
。