为什么在使用变量的where子句中获取Select时速度较慢?

时间:2015-06-22 18:19:08

标签: sql variables select sql-server-2008-r2 where-clause

我有以下查询,大约需要2分钟才能返回输出。

DECLARE @today DATETIME 
SET @today = GETDATE() 

SELECT con.* 
FROM GAS_consumptions con 
WHERE con.createdDate >= @today 

我注意到如果我使用它,则需要不到一秒的时间

SELECT con.* 
FROM GAS_consumptions con 
WHERE con.createdDate >= '2015-06-22' 

为什么会这样?我需要第一个查询,因为日期可能每天都有所不同。

2 个答案:

答案 0 :(得分:1)

在查询中使用文字值时,SQL Server将生成针对该特定值进行优化的查询计划。

例如,如果您在createdDate上有非聚集索引,则查询优化器可以使用createdDate >= '2015-06-22'获得对行数的良好估计。如果表中的一小部分行,最佳查询将在createdDate索引中找到匹配的记录,然后从表中查找匹配行的其余所选列。

在WHERE子句中使用变量时,SQL Server会生成一个查询计划,该计划将用于@today的所有可能值。生成的计划最适合@today的任意值,但单个计划只能对选定的特定行数最佳。

假设所选平均行数的估计值是表中行数的一半,在这种情况下,估计扫描整个表以过滤记录而不是过滤createdDate索引然后更高效必须在表上进行大量查找才能获得剩余的所选列。

问题是SQL Server对可能具有完全不同的行计数的查询使用单个查询计划。单个查询计划用于@today的所有值的原因通常是编译最佳查询比仅运行次优查询更昂贵。在你的例子中,显然情况并非如此。

有一些方法可以改变这种行为:

1)您也可以让Sql Server生成单个计划,但要根据预定的@today值进行优化

DECLARE @today DATETIME 
SET @today = GETDATE() 

SELECT con.* 
FROM GAS_consumptions con 
WHERE con.createdDate >= @today
OPTION (OPTIMIZE FOR (@today = '2015-06-22')) 

这应该产生与使用con.createdDate >= '2015-06-22'谓词相同的查询,并且如果您的应用程序总是在预定日期之后查询记录,则可以提供一个很好的解决方案。

2)指定重新编译选项将导致每次运行时生成新的查询计划,这允许针对特定的@today值优化查询。

DECLARE @today DATETIME 
SET @today = GETDATE() 

SELECT con.* 
FROM GAS_consumptions con 
WHERE con.createdDate >= @today
OPTION (RECOMPILE) 

这应该产生与使用con.createdDate >= '2015-06-22'谓词相同的查询。

警告:重新构建查询也可能会变慢。使用RECOMPILE选项可以降低性能。使用最后的度假村。 ETC。

答案 1 :(得分:0)

这只是一种解决方法。应用此commnad:

UPDATE STATISTICS GAS_consumptions WITH FULLSCAN, NORECOMPUTE

做几分钟的查询 再次陷入困境。

请记住,, NORECOMPUTE将定期执行此命令,因为它会停止sqlserver将来生成统计信息的方式。

在我得到的类似案例中,这是“解决方案”。我不知道为什么会发生