Sicherstellung einzelner Hinzufügen in SQL-Tabelle

Ich habe eine DocumentJob-Tabelle, die Aufträge enthält, die gegen ein bestimmtes Dokument durchgeführt werden sollen. Jede Zeile in der Tabelle hat jobId, documentId und jobstatus.

Mehrere Threads / processe würden versuchen, diese Tabelle zu einem beliebigen timepunkt hinzuzufügen (unter Verwendung des unten angegebenen Codes)

begin tran if exists ( select 1 from DocumentJob where DocumentId = @inDocumentId and Status in ('Running', 'New') ) throw 50001, 'New or Active Job for Document is already present', 1 insert into DocumentJob (DocumentId, Status) values(DocumentId, 'New') select @JobId = scope_identity(); commit; 

Für ein gegebenes Dokument Id – Ich möchte einen neuen Job nur hinzufügen, wenn es keinen anderen Job für das Dokument gibt, das entweder läuft oder neu ist. Gibt es das folgende Code-Snippet, das sich um die obige Anforderung kümmert oder gibt es einige Bedingungen, bei denen die obige Bedingung verletzt werden kann?

Mein Ziel ist es zu verstehen, ob der Tisch ordnungsgemäß verriegelt wäre usw. Wenn der oben genannte Proc gleichzeitig aufgerufen wird.

[1] Das erste, was ich tun würde, ist, einen einzigartigen gefilterten Index zu erstellen, also:

 CREATE UNIQUE NONCLUSTERED INDEX IUF_DocumentJob_DocumentId ON dbo.DocumentJob (DocumentId) --INCLUDE (...) WHERE Status in ('Running', 'New') 

Dieser eindeutige Index garantiert, dass dbo.DocumentJob Tisch eine eindeutige DocumentId s hat, die einen folgenden Status hat: 'Running' oder 'New' .

Dies ist genug, um doppelte dbo.DocumentJob s zu verhindern, wenn der Status 'Running' oder 'New' .

[2] Nach [1] könnte der Quellcode, der in der aktuellen Frage enthalten ist, durch einen einfachen ersetzt werden

 INSERT INTO dbo.DocumentJob (DocumentId, Status) VALUES (@DocumentId, 'New') 

Für jeden { @DocumentId Wert und Running oder New Status} wird nur die erste INSERT (oder UPDATE ) Ausführung erfolgreich und die nächsten Ausführungen fehlschlagen.

Anmerkung: Ich würde diesen Code innerhalb der Transaktion einkapseln (siehe SET XACT_ABORT ON ) und auch innerhalb TRY ... CATCH Block (dieses Thema wird in dieser Antwort nicht dargestellt).

[3] Um zu testing, würde ich ostress.exe Tool von Microsoft ( http://sqlmag.com/t-sql/2-tools-keep-sql-server-tuned ) und / oder folgenden Ansatz verwenden

[3.1] Innerhalb von SSMS öffnen Sie eine neue Abfrage ([Neue Abfrage]) windows und führen Sie den folgenden Code aus

 BEGIN TRAN -- Replace 1234 with a new DocumentId INSERT INTO dbo.DocumentJob (DocumentId, Status) VALUES (1234, 'New') -- COMMIT 

[3.2] Innerhalb von SSMS öffnen Sie eine andere Abfrage ([Neue Abfrage]) windows und führen Sie den folgenden Code aus

 BEGIN TRAN -- Use the same DocumentId INSERT INTO dbo.DocumentJob (DocumentId, Status) VALUES (1234, 'New') COMMIT 

[3.3] Erstes INSERT wird erfolgreich und das zweite wird scheitern.

Hinweis: Wenn Sie Fragen haben (bezüglich dieser Antwort), bitte fragen Sie bitte. Anmerkung 2: Vergessen Sie nicht, COMMIT (oder ROLLBACK first Tx) zu vergessen.