SQL 当约束被硬编码时,服务器在 WHERE 子句中的不同性能

SQL Server different performance in a WHERE clause when constraint is hardcoded

我在 SQL Server 2014 上遇到了一个非常奇怪的性能问题。我尝试 select 一些基于约束特定日期记录的 where 子句的值。当我对日期进行硬编码时,查询很快(3 秒),而当我尝试参数化查询时,它很慢。

为了以防万一,时间戳上有一个索引。您将在下面找到不同的查询及其性能。

SELECT *
FROM [DB].[schema].[table]
WHERE [Timestamp]>='2016-07-25' AND [Timestamp]<'2016-07-26'
--execution time 3 seconds!

SELECT *
FROM [DB].[schema].[table]
WHERE [Timestamp] BETWEEN '2016-07-25' AND '2016-07-26'
--execution time 3 seconds!

DECLARE @StartDate DATETIME
SET @StartDate = '2016-07-25'

DECLARE @StartDateString VARCHAR(10)
SET @StartDateString =CAST(FORMAT(@StartDate,'yyyy-MM-dd HH:mm:ss.fff') AS VARCHAR(10))

DECLARE @EndDateString VARCHAR(10)
SET @EndDateString =CAST(FORMAT(DATEADD(day,1,@StartDate),'yyyy-MM-dd HH:mm:ss.fff') AS VARCHAR(10))

SELECT *
FROM [DB].[schema].[table]
WHERE [Timestamp] BETWEEN @StartDateString AND @EndDateString
--execution time 30 minutes!

DECLARE @StartDate DATETIME
SET @StartDate = '2016-07-25'

DECLARE @EndDate DATETIME
SET @EndDate =DATEADD(day,1,@StartDate)

SELECT *
FROM [DB].[schema].[table]
WHERE [Timestamp] BETWEEN @StartDate AND @EndDate
--execution time 30 minutes!

请参阅下面 TT 的回答,了解除了构建查询之外的替代解决方案

DECLARE @StartDate DATETIME
SET @StartDate = '2016-07-25'

DECLARE @EndDate DATETIME
SET @EndDate =DATEADD(day,1,@StartDate)

SELECT *
FROM [DB].[schema].[table]
WHERE [Timestamp] BETWEEN @StartDate AND @EndDate
OPTION(RECOMPILE)
--execution time 3 sec

我找到了解决方法。我构建了查询并执行了它。不过,如果您知道性能不同的原因,请告诉我。

DECLARE @StartDate DATETIME
SET @StartDate = '2016-07-25'
DECLARE @StartDateString VARCHAR(10)
SET @StartDateString =CAST(FORMAT(@StartDate,'yyyy-MM-dd HH:mm:ss.fff') AS VARCHAR(10))
DECLARE @EndDateString VARCHAR(10)
SET @EndDateString =CAST(FORMAT(DATEADD(day,1,@StartDate),'yyyy-MM-dd HH:mm:ss.fff') AS VARCHAR(10))


 DECLARE @Query NVARCHAR(4000)
 SET @Query =
 '
 SELECT *
 FROM [DB].[schema].[table]
 WHERE [Timestamp]>='''+@StartDateString+''' AND [Timestamp]<'''+@EndDateString+'''
 '
 EXECUTE sp_executesql @Query

首先,我会为您的参数使用 DATETIME 类型。

其次,您很有可能 运行正在研究参数嗅探。使用 Query Hints:

回避此问题的两种方法
  • 向查询添加查询提示OPTION(RECOMPILE)
  • 向查询添加查询提示OPTION(OPTIMIZE FOR UNKNOWN)

第一个选项仅适用于不经常 运行 的查询(>> 1/秒),而第二个选项在很多情况下更受欢迎。