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

时间:2012-08-22 17:14:15

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

更好的是,我的意思是它会以一些非边际数量来提高绩效吗?

也就是说,每次拨打GETDATE()时,服务器会做多少工作来返回该值?

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

declare @transDate datetime = GETDATE()

基准测试数据非常棒。

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

5 个答案:

答案 0 :(得分:20)

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

根据微软的此次交流,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);

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

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

答案 1 :(得分:17)

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

除非您仅使用Date的{​​{1}}部分,否则您将确保始终使用相同的值。

答案 2 :(得分:1)

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

我自己将300GB的数据迁移到了几个表中。

答案 3 :(得分:1)

我正在使用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()

..... 然后根据需要使用参数,你会看到好的结果

欢迎任何意见或建议。

答案 4 :(得分:0)

我用过

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