我有一个查询,该查询返回几千个记录,跨多个表。在WHERE子句中,日期被检查为不超过两个月。首先,查询将日期边界设置为变量,WHERE使用该日期边界。

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()分配给变量,而不是在WHERE中使用它:
Does SYSDATETIME() cost more than GETDATE()?

另外,在示例中仅使用了GETDATE:
TSQL datetimes functions in where clause

最佳答案

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)


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

如果这两个查询以不同的方式运行,我会感到惊讶。

理想情况下,您应该将它们强制转换为dateinquestion具有的类型。

您说过SYSDATETIME的变体占用大量CPU。如果dateinquestion的类型为datetime,则可能是这样。似乎在此变体中,dateinquestion列中的值在比较之前隐式转换为datetime2(7)类型。对于每一行。首先,它使用CPU。其次,它可能会阻止优化器在此列上使用索引(如果有索引)。

要查看实际发生的情况,而不是猜测,请比较两个变体的实际执行计划。

顺便说一下,带有变量的变量不等同于优化程序的内联变量。 Optimizer不知道变量的值,但是知道GETDATE()SYSDATETIME()的值,因此基数估计不同,这可能导致不同的计划和不同的性能。

关于sql-server - 请确认: SYSDATETIME() is slower than GETDATE() in WHERE clause,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29387398/

10-12 05:30