【发布时间】:2016-06-29 21:59:33
【问题描述】:
当我在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
我尝试按照here 的建议使用OPTION(RECOMPILE),但它对提高性能没有任何帮助。 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 的顶部,以减少在不可避免的维护期间在代码中四处寻找的需要。
【问题讨论】:
-
超过 10 亿行且没有索引 - 哇!搜索这批文字也需要很长时间......我假设还有某种缓存结果......你比较了执行计划吗? * 我不想在没有确定会有所帮助的情况下开始编制索引* 好吧,我可以向您保证,索引会有所帮助:-)
-
嗯,有一个索引,但在
theDate上没有,我想我可以更清楚一点:P -
有这么多的行,你应该在你想在排序、过滤或连接操作中使用的所有列上使用索引... 索引 - 简单地说 - 该列值的排序列表。在这个列表中找到一个给定的值是一个非常快的过程(分成两半,看看是大是小,啊,它是更大的!划分上半部分等等......)一旦找到,所有的值都坐在一起堵塞。现在想象一个未排序的堆。您的查询必须逐行扫描整个表格。
-
您的第一站应该是实际的查询计划。 mssqltips.com/sqlservertutorial/2252/…。任何其他分析都会使缓存问题变得模糊。因此,获取快速和慢速查询的实际/估计查询计划并进行比较。顺便说一句,“我不想在没有保证它会有所帮助的情况下开始索引”的态度是一种 优秀 方法 - 除非您了解问题并捕捉到一些问题,否则不要只是将索引扔给它测量前后
-
Google 的“参数嗅探”
标签: sql sql-server performance sql-server-2014