【问题标题】:When using GETDATE() in many places, is it better to use a variable?在很多地方使用 GETDATE() 时,使用变量更好吗?
【发布时间】:2012-08-18 04:13:58
【问题描述】:

更好,我的意思是它会以非边际量提高性能吗?

也就是说,我每次调用GETDATE(),服务器要返回那个值,服务器做了多少work

如果我在存储过程的许多地方使用GETDATE(),我是否应该创建一个变量来存储交易日期?

declare @transDate datetime = GETDATE()

基准数据会很棒。

编辑我想澄清一下:我主要感兴趣的是这两种可能性之间的实际性能差异,以及它是否重要。

【问题讨论】:

  • 性能差异将非常微不足道或不存在。如果在重新评估的上下文中使用 GETDATE(),我会担心结果的准确性。
  • 感谢您为我解决这个问题。正如我所提到的,我主要对性能感兴趣。当准确性至关重要时,使用变量显然是最佳选择。
  • 准确性何时不重要?
  • @aaron:查询多行时性能差异很大,请参阅下面接受的答案,它也准确地反映了我们的观察结果。
  • 好的,我就到此为止。这不是要证明我是否可以复制任何东西,而是要帮助 OP。陈述了我对这个问题的经验,并且下面有足够好的 cmets。我有比在这里的 cmets 进行火焰战更好的事情要做。

标签: sql sql-server performance sql-server-2008 tsql


【解决方案1】:

[注意:如果您要否决这个答案,请留下评论解释原因。它已经被否决了很多次,最后 ypercube(谢谢)至少解释了一个原因。我无法删除答案,因为它已被接受,因此您不妨帮助改进它。]

根据此在 Microsoft 上的交流,GETDATE() switched from being constant within a query to non-deterministic in SQL Server 2005。回想起来,我认为这并不准确。我认为它在 SQL Server 2005 之前是完全非确定性的,然后在 SQL Server 2005 之后侵入了一种称为“非确定性运行时常量”的东西。后面的短语似乎真的意味着“查询中的常量”。

(And GETDATE() is defined as unambiguously and proudly non-deterministic, with no qualifiers.)

唉,在 SQL Server 中,非确定性并不意味着对每一行都评估一个函数。 SQL Server 确实使这变得不必要的复杂和模棱两可,几乎没有关于该主题的文档。

实际上,函数调用是在查询运行时评估的,而不是在编译查询时评估一次,每次调用时它的值都会改变。在实践中,GETDATE() 对于每个使用它的表达式只计算一次——在执行时而不是编译时。但是,Microsoft 将rand()getdate() 归入一个特殊类别,称为非确定性运行时常量函数。相比之下,Postgres 不会跳过这样的循环,它只是调用在“稳定”执行时具有恒定值的函数。

尽管有 Martin Smith 的评论,但 SQL Server 文档对这个问题并没有明确说明——GETDATE() 被描述为“非确定性”和“非确定性运行时常量”,但该术语并没有得到真正的解释。 The one place I have found the term ,例如,文档中的下一行说不要在子查询中使用非确定性函数。对于“非确定性运行时常量”,这将是愚蠢的建议。

我建议即使在查询中也使用带有常量的变量,这样您就有了一致的值。这也让意图非常明确: 您需要查询中的单个值。在单个查询中,您可以执行以下操作:

select . . . 
from (select getdate() as now) params cross join
     . . . 

实际上,这是一个建议,应该在查询中只计算一次,但可能会有例外。出现混淆是因为getdate() 在所有不同的行上返回相同的值——但它可以在不同的列中返回不同的值。每个带有getdate() 的表达式都是独立评估的。 如果你运行,这很明显:

select rand(), rand()
from (values (1), (2), (3)) v(x);

在存储过程中,您可能希望变量中有一个值。如果存储过程在午夜过去时运行,并且日期发生变化,会发生什么情况?这对结果有什么影响?

至于性能,我的猜测是日期/时间查找是最小的,并且当查询开始运行时,每个表达式都会发生一次查询。这不应该是真正的性能问题,而更多的是代码一致性问题。

【讨论】:

  • @Shmiddty 无法运行一些性能测试来查看差异如何影响您的工作负载?事实上,我会说你比我们任何人都更能做到这一点。虽然我不明白为什么基准测试很重要——如果不安全的方法快 0.1 毫秒,你会改用它吗?
  • GETDATE() 从来都不是确定性的。确定性意味着当传递相同的参数时它总是返回相同的结果。请参阅list of deterministic functions in 2000GETDATERuntime Constant Function。无论查询执行的长度如何,单个 GETDATE() 调用都不会在每行返回不同的结果,尽管您可以包装在 UDF 中以获得此效果。
  • 同一查询中不同的GETDATE()引用会返回不同的结果WHILE DATEDIFF(ms, GETDATE() , GETDATE()) = 0 PRINT 'This will not run in an infinite loop'在2000/2005/2008年不会无限循环运行。
  • 令我担心的是,这个被接受且高度支持的答案似乎是错误的,而 comment by Marthin Smith 似乎是正确的。
【解决方案2】:

我的建议是使用变量,主要是因为如果您有一个长时间运行的进程,GetDate() 值可能在调用之间有所不同。

除非您只使用GetDate()Date 部分,否则您将确保始终使用相同的值。

【讨论】:

  • 我还建议尽可能使用 UTC(通过GETUTCDATE())。它稍微快一点,并且可以帮助您避免很多与时间相关的问题。
  • 我不认为您也可以依赖获取日期部分,因为您可以在晚上 11:59 开始查询,这可能会持续 10 分钟,然后在第二天凌晨 12:01 获得另一个日期。
  • 但是,如果GetDate() 的每个实例返回完全相同的值并不重要,那么使用变量还有其他好处吗?
  • @Kash 这也是非常正确的,在这种情况下我总是会使用变量。比打多个电话要好得多。
  • @Shmiddty 我个人的建议是使用一个变量,然后如果您需要更改所有查询的值,您只需在一个地方而不是多个地方进行。
【解决方案3】:

使用带有getdate() 的变量或suser_sname() 之类的函数的一个原因是,如果您正在插入行,或者您正在执行GROUP BY,则性能差异巨大。如果您插入大量行,您会注意到这一点。

我自己将 300GB 数据迁移到多个表时遇到了这种情况。

【讨论】:

    【解决方案4】:

    我正在测试几个使用 GETDATE() 函数作为 SP 中的变量的存储过程,由于查询优化器不知道要操作的值是什么,我的 IO 读取和执行时间增加了阅读此 Stored Procedure Execution with Parameters, Variables, and Literals ,也就是说您可以在 SP 的每个部分中使用 GETDATE() 函数,因为 @Gordon Linoff 提到它的值在执行期间不会改变,或者为了避免/消除认为值可能会改变的想法我确实以这种方式创建了一个参数:

    CREATE PROC TestGetdate
    (
    @CurrentDate DATETIME = NULL
    )
    AS
    SET CurrentDate  = GETDATE()
    

    ..... 然后使用你认为合适的参数,你会看到很好的结果

    欢迎任何cmets或建议。

    【讨论】:

      【解决方案5】:

      我用过

      WHERE ActualDateShipped+30 > dbo.Today()
      

      结合下面的功能。将我的查询时间从 13 秒缩短到 2 秒。这篇文章中没有任何先前的答案可以解决 SQL 2008/R2 中的这个问题。

      CREATE FUNCTION [dbo].[Today]()
      
          RETURNS date
          AS
          BEGIN
      
              DECLARE @today date = getdate()
      
              RETURN @today
          End
      

      【讨论】:

        猜你喜欢
        • 2014-04-04
        • 2011-02-14
        • 1970-01-01
        • 2018-11-23
        • 2022-01-18
        • 1970-01-01
        • 2018-10-22
        • 1970-01-01
        • 2012-06-03
        相关资源
        最近更新 更多