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设置为
,然后执行您想要的文本计划语句。虽然这只是生成计划,而不是执行计划