首页 > 解决方案 > `merge` 语句会保证所有插入行的 `default current_timestamp` 列的值相同吗?

问题描述

我相信即使在事务中,一堆插入到带有default current_timestamp列的表中,可能会根据行创建时间具有不同的值,但我不确定该语句的原子性如何:merge

MERGE 是 SQL2008 中的原子语句吗?

这是我的测试脚本:

结果显示:

显然,如果操作需要更长的执行时间是不够的,我想知道merge仍然会使所有插入的行具有相同的创建时间吗?

标签: sql-servermerge

解决方案


无论MERGE.

这与 的原子性无关MERGE

CURRENT_TIMESTAMP结束调用GETDATE()函数。GETDATE()是一个运行时常量。保证计划中的每个单独引用在整个语句持续时间内具有相同的值(尽管如果计划有多个引用GETDATE()这些将是两个不同的运行时常量,并且可以在不同的时间进行评估)。

这里的执行计划只有一个对该函数的引用。它计算一次并给出表达式标签Expr1010

StmtText
  |--Table Insert(OBJECT:(@alsoRows), SET:([JustAValue] = [tempdb].[dbo].[TestTable].[JustAValue] as [y].[JustAValue]))
       |--Table Merge(OBJECT:([tempdb].[dbo].[TestTable] AS [y]), SET:([tempdb].[dbo].[TestTable].[JustAValue] as [y].[JustAValue] = @rows.[JustAValue] as [x].[JustAValue],[tempdb].[dbo].[TestTable].[Birth] as [y].[Birth] = [Expr1010]) ACTION:([Action1009]))
            |--Compute Scalar(DEFINE:([Expr1010]=CONVERT_IMPLICIT(datetime2(7),getdate(),0)))
                 |--Table Spool
                      |--Filter(WHERE:([Action1009] IS NOT NULL))
                           |--Compute Scalar(DEFINE:([Action1009]=ForceOrder(CASE WHEN [TrgPrb1007] IS NOT NULL THEN NULL ELSE (4) END)))
                                |--Nested Loops(Left Outer Join, OUTER REFERENCES:([x].[JustAValue]))
                                     |--Table Scan(OBJECT:(@rows AS [x]))
                                     |--Compute Scalar(DEFINE:([TrgPrb1007]=(1)))
                                          |--Filter(WHERE:([tempdb].[dbo].[TestTable].[JustAValue] as [y].[JustAValue]=@rows.[JustAValue] as [x].[JustAValue]))
                                               |--Table Scan(OBJECT:([tempdb].[dbo].[TestTable] AS [y]))

RAND()也是一个运行时常量,并且在实践中更容易看到这种行为,因为它不依赖于设计一个长时间运行的语句。

DECLARE @T TABLE(X FLOAT DEFAULT RAND());

MERGE INTO @T 
USING sys.objects o ON o.object_id = X
WHEN NOT MATCHED THEN INSERT DEFAULT VALUES;

SELECT *
FROM @T; /*All rows will have the same value*/

推荐阅读