2015-04-01 63 views
4

我有一个查询返回数千个记录,并跨几个表连接。在WHERE子句中,过去检查日期不超过两个月。起初,查询将此日期边界设置为变量,WHERE使用该边界。请确认:SYSDATETIME()比WHERE子句中的GETDATE()慢

DECLARE @startdate as DATE = DATEADD(MONTH, -2, SYSDATETIME()) 

select [....] 
where dateinquestion >= @startdate 

这将运行得很好(返回4秒预期的结果),但我想摆脱变量声明和分配移动到WHERE子句本身:

select [....] 
where dateinquestion >= DATEADD(MONTH, -2, SYSDATETIME()) 

这运行一分钟以上并吃掉所有的CPU。我杀了查询停止推送服务器,没有给出结果。更改为GETDATE()(我不需要从SYSDATETIME(精度)反正)加快东西:

select [....] 
where dateinquestion >= DATEADD(MONTH, -2, GETDATE()) 

测试结果类似于方案1.

我相信这是因为SYSDATETIME评价上因为处理一行需要几个纳秒,这对SYSDATETIME很重要。但GETDATE具有更高的更改阈值,不受影响(或受影响较小),并且不会更改 - 或需要重新评估 - 以每行为基础。

您能确认吗?我对这种行为的假设是否正确?

我搜索了这一点,但无法找到除了这个,什么都仅关注分配SYSDATETIME()给一个变量,在哪里都不使用它:仅 Does SYSDATETIME() cost more than GETDATE()?

而且这一点,但GETDATE在此示例中使用: TSQL datetimes functions in where clause

回答

7

GETDATESYSDATETIME之间最重要的区别是返回值的类型。 SYSDATETIME不针对每一行进行评估,与GETDATE相同,不针对每一行进行评估。它们是Runtime Constant Functions另请参阅https://dba.stackexchange.com/questions/18459/does-sql-server-evaluate-functions-once-for-every-row

dateinquestion是什么类型的列?

当您使用@startdate变量时,您将SYSDATETIME的结果转换为date。当您不使用变量时,DATEADD的结果在您的示例中具有不同的类型。

为了使这两个查询与GETDATESYSDATETIME相当于你可以同时投射到date明确:

比较

select [....] 
where dateinquestion >= CAST(DATEADD(MONTH, -2, SYSDATETIME()) AS date) 

VS

select [....] 
where dateinquestion >= CAST(DATEADD(MONTH, -2, GETDATE()) as date) 

我会感到惊讶,如果这两个查询跑不同。

理想情况下,您应该将它们投射到与dateinquestion相同的类型。

你说SYSDATETIME的变种使用了大量的CPU。如果dateinquestion的类型为datetime,那么可能的解释可能是这样的。看起来在该变体中,来自dateinquestion列的值在比较之前隐式转换为datetime2(7)类型。对于每一行。首先,它使用CPU。其次,它可能会阻止优化器在此列上使用索引(如果有索引)。

为了看看真正发生的是什么,而不是猜测,比较两种变体的实际执行计划。

顺便说一下,带变量的变体与优化程序的内联变体不同。优化器不知道变量的值,但它知道GETDATE()SYSDATETIME()的值,所以基数估计是不同的,这可能导致不同的计划和不同的性能。

2

定义由微软:

  • SYSDATETIME返回datetime2(7)
  • GETDATE返回datetime

如果你的领域dateinquestiondatetime型的,那么就会有一个演员阵容在之间和datetime2(因为每行都需要比较),因此执行速度较慢。此外,正如其他答案中已经指出的那样,由于演员阵容,索引可能无法使用。

3

没有人提到过类型优先。但这实际上是你的问题的答案。事实上,SYSDATETIME返回类型datetime2(7)GETDATE返回类型datetime。如果您查看类型优先顺序表(https://msdn.microsoft.com/en-us/library/ms190309.aspx),您会看到datetime2(7)优先于datetime。这意味着:

当操作者结合不同的数据类型的两个表达式,对于数据类型的优先级的 规则指定与 低优先级的数据类型被转换为具有较高 优先级的数据类型。

所以实际上表中的每一行都被转换为datetime2(7)。这就是为什么它很慢。如果优先顺序相反,您的变量将被转换,而不是表中的每一行。

+2

该转换不是缓慢的唯一原因。由于转换,数据库不能再使用'datetime'字段的索引,而需要执行缓慢的表扫描。 – 2015-11-11 12:27:09