In che modo IDENTITY_INSERT influisce sulla concorrenza?


11

Sto cercando di aiutare un cliente con un componente aggiuntivo SAP di terze parti che presenta un problema tecnico relativo alla pubblicazione e non è più supportato.

In determinate circostanze, archivia e post incompleto dalla tabella delle code di invio alla tabella degli archivi di invio. Devo spostare questi risultati archiviati nella coda.

L'ID coda è una colonna di identità e vorrei mantenerlo lo stesso.

La domanda è: se inserisco identity_insert / insert / identity_insert off, cosa posso aspettarmi rispetto alla concorrenza con i processi che creano le voci della coda e mi aspetto che la colonna identità venga generata automaticamente?

Anche qualsiasi suggerimento sul modo migliore per dimostrare tale comportamento sarebbe molto apprezzato.

Risposte:


8

L'impostazione IDENTITY_INSERT ONda sola non elimina la concorrenza - questo non pone alcun blocco esclusivo sulla tabella, ma solo un breve blocco di stabilità dello schema (Sch-S).

Quindi cosa potrebbe teoricamente accadere, in base al comportamento predefinito, è che potresti farlo nella sessione 1:

BEGIN TRANSACTION;

-- 1
SET IDENTITY_INSERT dbo.tablename ON;

-- 2
INSERT dbo.tablename(id, etc) VALUES(100, 'foo'); -- next identity is now 101

-- 3
INSERT dbo.tablename(id, etc) VALUES(101, 'foo'); -- next identity is now 102

-- 4
SET IDENTITY_INSERT dbo.tablename OFF;

COMMIT TRANSACTION;

In un'altra sessione, è possibile inserire righe nella tabella ai punti 1, 2, 3 o 4. Questo può sembrare una buona cosa, tranne ciò che accade per qualsiasi inserimento che si verifica tra 2 e 3, è che il valore generato automaticamente attivato da un'altra sessione si basa sui risultati dell'istruzione 2 - quindi genererà un 101 e quindi l'istruzione 3 avrà esito negativo con una violazione della chiave primaria. Questo è abbastanza semplice da configurare e testare te stesso con alcuni WAITFORs:

-- session 1
-- DROP TABLE dbo.what;
CREATE TABLE dbo.what(id INT IDENTITY PRIMARY KEY);
GO
BEGIN TRANSACTION;

SET IDENTITY_INSERT dbo.what ON;

INSERT dbo.what(id) VALUES(32);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(33);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(34);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(35);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(36);

SET IDENTITY_INSERT dbo.what OFF;

COMMIT TRANSACTION;

Una volta avviato quel batch, avvia questo batch in un'altra finestra:

-- session 2
INSERT dbo.what DEFAULT VALUES;
WAITFOR DELAY '00:00:01';
GO 20

La sessione 2 dovrebbe sempre inserire valori compresi tra 1 e 20, giusto? Tranne che poiché l'identità sottostante è stata aggiornata dal manuale inserisce la sessione 1, ad un certo punto la sessione 2 riprenderà da dove era stata interrotta la sessione 1, e inserirà 32, o 33, o 34 ecc. Sarà permesso farlo, ma quindi la sessione 1 fallirà al successivo inserto con una violazione di PK (che si vince potrebbe essere solo una questione di tempistica).

Un modo per ovviare a questo è quello di invocare a TABLOCKsul primo inserto:

INSERT dbo.what WITH (TABLOCK) (id) VALUES(32);

Questo bloccherà tutti gli altri utenti che provano a inserire (o fare qualsiasi cosa, in realtà) con questa tabella fino a quando non hai finito di spostare indietro quelle righe archiviate. Ciò limita la concorrenza, certo, ma è così che vuoi che funzioni il blocco. E spero che questo non sia qualcosa che sta accadendo a un ritmo così frequente in cui blocchi continuamente altre persone.

Un paio di altre soluzioni alternative:

  • smetti di preoccuparti del IDENTITYvalore generato. Che importa? Utilizzare un UNIQUEIDENTIFIER(forse generato in una tabella separata con un IDENTITYsurrogato) se il valore originale è molto importante.
  • modifica il processo di archiviazione per utilizzare un "soft delete" in cui qualcosa è contrassegnato inizialmente come archiviato e l'archiviazione non è resa permanente fino a qualche data successiva. Quindi qualunque processo tenti di spostarli indietro può semplicemente eseguire un aggiornamento diretto e correggere il flag di eliminazione graduale.

Grazie per la tua spiegazione. Sto scrivendo un'utilità autonoma per aiutare con un prodotto fuori supporto che crea questi campi di identità. Non ho controllo su come funziona.
Metafora,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.