Будет ли оператор `merge` гарантировать одинаковое значение столбца` default_timestamp` по умолчанию для всех вставленных строк? - PullRequest
1 голос
/ 02 мая 2019

Я полагаю, что даже внутри транзакции, группа вставки в таблицу со столбцом default current_timestamp может иметь разные значения в зависимости от времени создания строки, но я не уверен, как atomic merge заявление:

Является ли MERGE атомарным оператором в SQL2008?

Вот мой тестовый скрипт:

  • Код

    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 все равно сделает все вставленные строки с одинаковым временем создания?

Ответы [ 2 ]

1 голос
/ 03 мая 2019

Время, введенное по умолчанию, будет одинаковым для всех строк, независимо от того, сколько времени потребуется для 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*/
0 голосов
/ 03 мая 2019

Current_timestamp не гарантирует, что все строки, вставленные в длительный оператор слияния, имеют одинаковую метку времени. Если вы хотите, чтобы все строки имели одинаковую отметку времени, я бы предложил сохранить отметку времени в переменной непосредственно перед объединением. Затем вы можете использовать переменную timestamp как часть оператора вставки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...