【问题标题】:Please confirm: SYSDATETIME() is slower than GETDATE() in WHERE clause请确认:SYSDATETIME() 在 WHERE 子句中比 GETDATE() 慢
【发布时间】:2015-06-05 21:35:38
【问题描述】:

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

【问题讨论】:

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


    【解决方案1】:

    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。其次,它可能会阻止优化器在该列上使用索引(如果有索引)。

    要了解实际情况,而不是猜测,比较两个变体的实际执行计划。

    顺便说一句,带有变量的变体并不等同于优化器的内联变体。优化器不知道变量的值,但是知道GETDATE()SYSDATETIME()的值,所以基数估计不同,会导致不同的计划和不同的性能。

    【讨论】:

      【解决方案2】:

      微软定义:

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

      如果您的字段dateinquestion 的类型为datetime,那么每一行中都会有datetimedatetime2 之间的转换(因为每一行都需要比较),因此执行速度较慢.此外,正如其他答案中已经说明的那样,由于演员阵容,可能无法使用索引。

      【讨论】:

        【解决方案3】:

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

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

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

        【讨论】:

        • 转换速度慢并不是唯一的原因。由于转换,数据库不能再使用datetime字段上的索引,需要进行慢表扫描。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-11
        • 2015-06-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多