请确认:SYSDATETIME()比WHERE子句中的GETDATE()慢

时间:2015-04-01 09:39:10

标签: sql-server datetime sql-server-2012

我有一个返回数千条记录的查询,它们连接在几个表中。在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

3 个答案:

答案 0 :(得分:8)

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()的值,因此基数估计不同,这可能导致不同的计划和不同的性能。

答案 1 :(得分:3)

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

  

当一个运算符组合了两个不同数据类型的表达式时,   数据类型优先级的规则指定具有的数据类型   较低的优先级转换为具有较高的数据类型   优先级。

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

答案 2 :(得分:2)

Microsoft的定义:

  • datetime2(7)会返回 GETDATE
  • datetime会返回 dateinquestion

如果您的字段datetime的类型为datetime,则每行中datetime2module TicTacToe open FsUnit open NUnit.Framework [<Test>] let ``player has connected row`` () = let grid = Map.empty .Add(0, true).Add(1, true).Add(2, true) .Add(3, true).Add(4, false).Add(5, true) .Add(6, true).Add(7, true).Add(8, true) let firstRowIsStreak = grid |> Seq.take 3 |> Seq.forall (fun x -> x.Value = true) let secondRowIsStreak = grid |> Seq.skip 3 |> Seq.take 3 |> Seq.forall (fun x -> x.Value = true) let thirdRowIsStreak = grid |> Seq.skip 6 |> Seq.take 3 |> Seq.forall (fun x -> x.Value = true) firstRowIsStreak |> should equal true secondRowIsStreak |> should equal false thirdRowIsStreak |> should equal true 之间会有一个广告(因为每行都需要进行比较)因此,执行速度较慢。另外,正如在其他答案中已经说明的那样,由于演员表,可能无法使用索引。