在许多地方使用GETDATE()时,使用变量是否更好?

Shm*_*dty 37 sql t-sql sql-server performance sql-server-2008

更好的是,我的意思是它是否以一些非边际数量提高了性能?

也就是说,每次调用时GETDATE(),服务器返回该值的工作量是多少?

如果我GETDATE()在存储过程中的许多地方使用,我应该创建一个变量来存储事务的日期吗?

declare @transDate datetime = GETDATE()
Run Code Online (Sandbox Code Playgroud)

基准测试数据非常棒.

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

Gor*_*off 20

[注意:如果你打算回答这个问题,请发表评论解释原因.它已被多次下调,最后ypercube(谢谢)解释了至少一个原因.我无法删除答案,因为它被接受了,所以你不妨帮助改进它.]

根据微软的这种交流,GETDATE()从查询中的常量切换到SQL Server 2005中的非确定性.回想起来,我认为这不准确.我认为它在SQL Server 2005之前是完全不确定的,然后在SQL Server 2005之后被黑客入侵了一个名为"非确定性运行时常量"的东西.后面的短语实际上似乎意味着"在查询中不变".

(并且GETDATE()被定义为明确且自豪地非确定性,没有限定词.)

唉,在SQL Server中,非确定性并不意味着为每一行计算一个函数.SQL Server确实使这个问题变得非常复杂和模糊,只有非常少的文档.

实际上,在查询运行时评估函数调用,而不是在编译查询时评估函数调用,并且每次调用查询时其值都会更改.实际上,GETDATE()只对每个使用它的表达式计算一次 - 在执行时而不是编译时.但是,Microsoft将rand()getdate()置于一个特殊类别,称为非确定性运行时常量函数.相比之下,Postgres没有跳过这样的箍,只是在执行"稳定"时调用具有常量值的函数.

尽管马丁史密斯的评论,SQL Server文档在这个问题上根本不明确 - GETDATE()被描述为"非确定性"和"非确定性运行时常量",但该术语并未真正解释. 我找到这个术语的地方,例如,文档中的下一行说不要在子查询中使用非确定性函数.这对于"非确定性运行时常量"来说是愚蠢的建议.

我建议甚至在查询中使用带常量的变量,这样你就有了一致的值.这也使得意图非常明确:您希望查询中包含单个值.在单个查询中,您可以执行以下操作:

select . . . 
from (select getdate() as now) params cross join
     . . . 
Run Code Online (Sandbox Code Playgroud)

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

select rand(), rand()
from (values (1), (2), (3)) v(x);
Run Code Online (Sandbox Code Playgroud)

在存储过程中,您可能希望在变量中包含单个值.如果存储过程在午夜过程中运行,并且日期发生变化,会发生什么?这会对结果产生什么影响?

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

  • `GETDATE()`从来都不是确定性的.确定性意味着它在传递相同参数时将始终返回相同的结果.请参阅[2000年的确定性函数列表](http://msdn.microsoft.com/en-us/library/aa214775(v = sql.80).aspx).`GETDATE`是[运行时常量函数](http://blogs.msdn.com/b/conor_cunningham_msft/archive/2010/04/23/conor-vs-runtime-constant-functions.aspx).无论查询执行的长度如何,单个`GETDATE()`调用都不会返回每行不同的结果,尽管您可以在UDF中包装以获得此效果. (16认同)
  • 同一查询中不同的`GETDATE()`引用可以返回不同的结果`WHILE DATEDIFF(ms,GETDATE(),GETDATE())= 0 PRINT'这不会在无限循环中运行'不会在无限循环中运行在2000/2005/2008. (5认同)
  • 我担心这个被接受且高度赞成的答案似乎是错误的,而[Marthin Smith的评论](http://stackoverflow.com/questions/12078202/when-using-getdate-in-many-places-is-它 - 更好地使用变量#comment16223903_12078717)似乎是正确的. (5认同)
  • @Shmiddty不能*你*运行一些性能测试,看看差异会如何影响你的工作量?事实上,我会说你做得比我们任何人都要好得多.虽然我不明白为什么基准测试很重要 - 如果不安全的方法快了0.1毫秒,你打算用它吗? (3认同)
  • @GordonLinoff http://dba.stackexchange.com/questions/18459/does-sql-server-evaluate-functions-once-for-every-row (3认同)
  • 以防你没有听说过他:[Conor Cunningham简介](https://sqlbits.com/Speakers/Conor_Cunn​​ingham) (3认同)
  • 此外,Conor Cunningham博客文章:[RAND()和其他运行时常量函数,redux](http://www.sqlskills.com/blogs/conor/rand-and-other-runtime-constant-functions-redux/) (2认同)
  • @ypercubeᵀᴹ...我觉得这篇博文很模糊.确切的陈述是:"想到的是getdate() - 它是非确定性的,你可能不希望在长时间运行的查询中改变结果." 那究竟是如何实现的呢?这类信息确实应该在文档中非常明确,而不是埋藏在博客文章中.我应该强调,"GETDATE()"自豪地是文档另一部分中的原型非确定性函数 - 引用在修订后的答案中. (2认同)
  • 我当然同意你的看法,目前还不清楚文件.有几个人**推断** - 使用各种方法(调试,执行计划,时间安排,与MS开发人员的讨论) - 它充当运行时常量.我的结论是,它是这样做的,因为至少有6个最近的SQL Server版本 - 但它不是旧版本,2000或更早版本(与答案中的声明相反)并且文档尚未更新. (2认同)
  • 至于非弱智,当然.它永远不会 - 也可能不是 - 确定性的. (2认同)

Tar*_*ryn 18

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

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

  • 我不认为你可以依赖于获取日期部分,因为你可以在晚上11:59开始查询,这可能会持续10分钟,并在第二天上午12:01再次获得日期. (8认同)