Sql server “merge”语句能否保证所有插入行的“defaultcurrent\u timestamp”列的值相同?

Sql server “merge”语句能否保证所有插入行的“defaultcurrent\u timestamp”列的值相同?,sql-server,merge,Sql Server,Merge,我相信,即使在一个事务中,对带有默认当前时间戳列的表的一系列插入,根据行创建时间可能有不同的值,但我不确定合并语句的原子性: 以下是我的测试脚本: 代码 if type_id(N'ValuableRow') is not null drop type ValuableRow create type ValuableRow as table ( JustAValue nvarchar(max) ) drop table if exists TestTable

我相信,即使在一个事务中,对带有
默认当前时间戳
列的表的一系列插入,根据行创建时间可能有不同的值,但我不确定
合并
语句的原子性:

以下是我的测试脚本:

  • 代码

    if type_id(N'ValuableRow') is not null 
        drop type ValuableRow
    
    create type ValuableRow as table (
        JustAValue nvarchar(max)
    )
    
    drop table if exists 
        TestTable
    
    create table TestTable(
        JustAValue nvarchar(max) 
        , Birth datetime2 default current_timestamp
    ) 
    
    go
    
    --// delete TestTable
    
    insert TestTable(JustAValue)
        values ('1234'), ('5678')
    
    declare 
        @rows ValuableRow, @alsoRows ValuableRow
    
    insert @rows(JustAValue)
        values ('abcd'), ('1234'), ('5678'), ('wxyz')
    
    merge 
        TestTable y
    using
        @rows x
    on (y.JustAValue=x.JustAValue)  
    when not matched then  
    insert (JustAValue) 
        values (JustAValue)
    output 
        inserted.JustAValue
    into 
        @alsoRows
    ;
    
    select 
        *
    from 
        @alsoRows
    
    select 
        *
    from 
        TestTable
    
结果表明:


显然,如果操作需要更长的执行时间,还不足以说明会发生什么情况,我想知道
merge
是否仍会使所有插入的行具有相同的创建时间?

Current\u timestamp不能保证长时间运行的merge语句中插入的所有行都具有相同的时间戳。如果希望所有行具有相同的时间戳,我建议在合并之前在变量中存储一个时间戳。然后可以将timestamp变量用作insert语句的一部分

对于所有行,作为默认值输入的时间将是相同的,无论
合并需要多长时间

这与
MERGE
的原子性无关

CURRENT\u 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*/

我想知道的是这样做的必要性;我不知道megre是否已经在发动机罩下做了这件事。答案是错的。只有两个基本答案。时间保证是相同的,或者时间不保证是相同的,这选择了错误的一个。这也是我所想的,但当我们仍然使用sql 2008(如问题中所述)时,我们遇到了一个问题,在午夜前后一个接口进行了一次巨大的合并(请不要告诉我为什么他们这样编码). 不管怎样,有些记录以第二天的时间戳结束,并导致人们认为接口失败。不管怎么说,底线是,如果这不再是一个问题,那么我很乐意纠正。当所有记录都获得一个常量值非常重要时,我可能仍然会使用一个变量,但这可能只是我目前的妄想:)我还想知道如何生成执行计划的文本版本。@KenKin-
将SHOWPLAN\u text设置为
,然后执行您想要的文本计划语句。虽然这只是生成计划,而不是执行计划