Ошибка обновления темпоральной таблицы MS SQL

Я не могу найти ничего, чтобы объяснить, почему при вызове SP, который выполняет вставку или обновление в зависимости от того, существует ли запись во временной таблице, я получаю

Не удалось изменить данные в таблице с системным управлением версиями MYDB.dbo.TemporalExample, поскольку время транзакции было раньше, чем время начала периода для затронутых записей.

какая доза это значит? Это только иногда случается, интересно, потому что я запускаю многопоточный код, а azure sql просто не любит взаимные подключения к одной и той же таблице, когда это временная? Я иду через entity framework (последняя версия), но я сомневаюсь, что проблема

мой sp только это


create PROCEDURE mysp 
    @ID bigint,
    @a FLOAT,
    @b NVARCHAR(10),
    @c  DECIMAL(19, 4)
AS
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED    

    SET NOCOUNT ON    

    BEGIN TRY

        IF EXISTS ( SELECT TOP 1 
                        Id 
                    FROM 
                        my_Temporal_Table WITH (NOLOCK) 
                    WHERE 
                        id = @ID 
                        AND a = @a
                        AND b = @b)
            BEGIN

                UPDATE 
                    my_Temporal_Table
                SET
                    Id = @ID,
                    a = @a,
                    b = @b
                    c = @c
                    DateModified =  GETUTCDATE()
                WHERE 
                    Id = @Id

            END
        ELSE    
            BEGIN

                INSERT INTO 
                    my_Temporal_Table
                        (Id, a, b, c, DateModified)
                VALUES 
                        (@ID, @a, @b, @c , GETUTCDATE())        
            END

    END TRY
    BEGIN CATCH
        DECLARE @ErrorMessage   NVARCHAR(4000),
                @ErrorSeverity  INT,
                @ErrorState     INT

        SELECT 
                @ErrorMessage = ERROR_MESSAGE(),        
                @ErrorSeverity = ERROR_SEVERITY(),
                @ErrorState = ERROR_STATE()

        -- Use RAISERROR inside the CATCH block to return error
        -- information about the original error that caused
        -- execution to jump to the CATCH block.
        RAISERROR (@ErrorMessage, -- Message text.
                   @ErrorSeverity, -- Severity.
                   @ErrorState -- State.
                   )

    END CATCH

Обновите мой скрипт создания темпоральной таблицы:


    CREATE TABLE [Temporal](
    [TemporalId] [bigint] IDENTITY(1,1) NOT NULL,
    [Payment] [decimal](19, 4) NOT NULL,
    [DateModified] [datetime2](7) NOT NULL,
    [SysStartTime] [datetime2](7) GENERATED ALWAYS AS ROW START NOT NULL,
    [SysEndTime] [datetime2](7) GENERATED ALWAYS AS ROW END NOT NULL,
    CONSTRAINT [TemporalId] PRIMARY KEY CLUSTERED ([TemporalId] ASC)
        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON),
    PERIOD FOR SYSTEM_TIME ([SysStartTime], [SysEndTime])
    )WITH(
    SYSTEM_VERSIONING = ON ( HISTORY_TABLE = [Car2].[TemporalHistory] )
    )

может кто-нибудь объяснить, почему я могу увидеть эту проблему, что это означает и, что более важно, как я могу ее исправить?

Благодарность


person Rawdon Hume    schedule 18.11.2016    source источник
comment
почему вы обновляете темпоральные таблицы   -  person TheGameiswar    schedule 18.11.2016
comment
Я не уверен, почему мне не обновить его? В конце концов, это обычная таблица, я не обновляю таблицу истории, это в соответствии с документами MS ссылка по-прежнему обычный метод обновления, который вы используете, когда вам нужно обновить данные в таблице.   -  person Rawdon Hume    schedule 18.11.2016
comment
о, хорошо, понял, я думал, это таблица истории   -  person TheGameiswar    schedule 18.11.2016
comment
Разве вы не используете partitiong?   -  person Deadsheep39    schedule 18.11.2016
comment
Я добавил сценарий создания для своей темпоральной таблицы, нет, я не использую разделение для обновления, так как я не хочу ограничивать обновление установленным периодом времени, согласно документам MS, которые я должен был сделать?   -  person Rawdon Hume    schedule 18.11.2016
comment
Просто примечание. Если вы используете SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED в своем SP, вам не нужно использовать WITH (NOLOCK) для запросов ниже.   -  person Ross Bush    schedule 18.11.2016
comment
yer я действительно удалил это мышление, что установка этого была плохой идеей при выполнении обновления / вставки части SP, но спасибо, что указали на это :)   -  person Rawdon Hume    schedule 18.11.2016


Ответы (2)


Итак, я решил это ... похоже, что темпоральные таблицы не очень хорошо работают с логикой потоковой передачи. Я подозреваю, что потому, что я выполняю несколько одновременных обновлений таблицы параллельно; связанная таблица истории отстает в обновлении настолько, что временная привязка вызывает сбой. Сделав мой код однопоточным, проблема была решена. Кажется странным, что темпоральная таблица может быть подвержена тому, что кажется почти состоянием гонки? Я знаю, что это не мой код, так как тот же код отлично работает для других таблиц. Так что, думаю, мне придется придерживаться однопоточной логики, пока MS не исправит ее.

person Rawdon Hume    schedule 18.11.2016
comment
Вы вызываете (через структуру сущности) процедуру с явной транзакцией? - person Deadsheep39; 18.11.2016
comment
я вызываю, используя платформу сущностей azure, которая поддерживает политику повторных попыток и поддерживает асинхронные методы ссылка - person Rawdon Hume; 18.11.2016
comment
Вы действительно имеете в виду переход от многопоточности к однопоточной, например, при последовательной вставке, а не одновременно? Или вы имеете в виду переход от шаблона async / await к обычным методам синхронизации? Я понимаю, что шаблон async / await связан с потоками, но просто хочу прояснить, что именно вы имеете в виду, делая свой код однопоточным. - person uygar.raf; 24.02.2017
comment
Я перешел с параллельной задачи async / await на вызов метода синхронизации sp - person Rawdon Hume; 06.03.2017

Это хакерский обходной путь, который в большинстве случаев не идеален, однако, если вы хотите сериализовать доступ к критическому разделу при работе с sql-сервером, вы можете использовать встроенный механизм блокировки, чтобы предоставить доступ к этому критическому разделу через SP_GETAPPLOCK, однако , вы просто можете переместить узкое место в другое место в зависимости от ситуации.

CREATE PROC MyCriticalWork(@MyParam INT)      
AS
    DECLARE @LockRequestResult INT=0    
    DECLARE @MyTimeoutMiliseconds INT=5000--Wait only five seconds max then timeouit

    BEGIN TRAN

    EXEC @LockRequestResult=SP_GETAPPLOCK 'MyCriticalWork','Exclusive','Transaction',@MyTimeoutMiliseconds
    IF(@LockRequestResult>=0)BEGIN

            /*
            DO YOUR CRITICAL READS AND WRITES HERE
            */

        COMMIT TRAN--Releases the lock
    END ELSE
        ROLLBACK TRAN--Releases the lock  
person Ross Bush    schedule 18.11.2016
comment
Ваша проблема в том, что вся суть заключалась в поддержке асинхронного метода, который поставляется с инфраструктурой сущностей Azure. Я всегда могу использовать однопоточную логику, но в идеале можно представить, что временные таблицы будут работать с асинхронной логикой. Сказав, что я заметил, что вы не можете вызвать truncate для временных таблиц, что, по моему мнению, было странным, поэтому, возможно, они не поддерживают другие функции, такие как потоки ... но спасибо за предложение :) - person Rawdon Hume; 18.11.2016