Wie wirkt sich IDENTITY_INSERT auf die Parallelität aus?

11

Ich versuche, einem Kunden mit einem SAP-Add-On eines Drittanbieters zu helfen, das einen Posting-Fehler aufweist und keinen Support mehr bietet.

Unter bestimmten Umständen archiviert und unvollständige Beiträge aus der Buchungswarteschlangentabelle in die Buchungsarchivtabelle. Ich muss diese archivierten Ergebnisse wieder in die Warteschlange verschieben.

Die Warteschlangen-ID ist eine Identitätsspalte und ich möchte sie beibehalten.

Die Frage ist, was kann ich in Bezug auf die Parallelität mit Prozessen erwarten, die die Warteschlangeneinträge erstellen und erwarten, dass die Identitätsspalte automatisch generiert wird, wenn ich identity_insert on / insert / identity_insert off ausführe?

Hinweise, wie ein solches Verhalten am besten demonstriert werden kann, sind ebenfalls sehr willkommen.

Metapher
quelle

Antworten:

8

Durch das Festlegen IDENTITY_INSERT ONallein wird die Parallelität nicht beseitigt. Dadurch werden keine exklusiven Sperren für die Tabelle platziert, sondern nur eine kurze Sch-S-Sperre (Schemas).

Was also theoretisch unter dem Standardverhalten passieren könnte, ist, dass Sie dies in Sitzung 1 tun könnten:

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 einer anderen Sitzung können Sie an den Punkten 1, 2, 3 oder 4 Zeilen in die Tabelle einfügen. Dies scheint eine gute Sache zu sein, außer dass bei jeder Einfügung zwischen 2 und 3 der automatisch generierte Wert ausgelöst wird Eine andere Sitzung basiert auf den Ergebnissen von Anweisung 2 - es wird also eine 101 generiert, und dann schlägt Anweisung 3 mit einer Primärschlüsselverletzung fehl. Dies ist ziemlich einfach einzurichten und mit einigen WAITFORs zu testen :

-- 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;

Sobald dieser Stapel gestartet wurde, starten Sie diesen Stapel in einem anderen Fenster:

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

Sitzung 2 sollte immer nur Werte von 1-20 einfügen, oder? Abgesehen davon, dass die zugrunde liegende Identität durch das manuelle Einfügen von Sitzung 1 aktualisiert wurde, wird Sitzung 2 irgendwann dort fortgesetzt, wo Sitzung 1 aufgehört hat, und 32, 33 oder 34 usw. eingefügt. Dies ist jedoch zulässig dann schlägt Sitzung 1 beim nächsten Einfügen mit einer PK-Verletzung fehl (die man gewinnt, kann nur eine Frage des Timings sein).

Eine Möglichkeit, dies zu umgehen, besteht darin, TABLOCKbeim ersten Einfügen ein aufzurufen :

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

Dadurch werden alle anderen Benutzer blockiert, die versuchen, diese Tabelle einzufügen (oder wirklich etwas zu tun), bis Sie mit dem Zurückschieben dieser archivierten Zeilen fertig sind. Dies drosselt Gleichzeitigkeit, sicher, aber das ist so , wie Sie wollen , um Arbeit zu blockieren. Und hoffentlich passiert das nicht so häufig, wenn Sie ständig andere Leute blockieren.

Einige andere Problemumgehungen:

  • Hör auf, dich um den IDENTITYgenerierten Wert zu kümmern . Wen interessiert das? Verwenden Sie a UNIQUEIDENTIFIER(möglicherweise in einer separaten Tabelle mit einem IDENTITYals Ersatz generiert ), wenn der ursprüngliche Wert sehr wichtig ist.
  • Ändern Sie den Archivierungsprozess so, dass ein "Soft Delete" verwendet wird, bei dem etwas anfänglich als archiviert markiert ist und die Archivierung erst zu einem späteren Zeitpunkt dauerhaft wird. Dann kann jeder Prozess, der versucht, sie zurückzuschieben, einfach eine direkte Aktualisierung durchführen und das Soft-Delete-Flag korrigieren.
Aaron Bertrand
quelle
Ich danke Ihnen für Ihre Erklärung. Ich schreibe ein eigenständiges Dienstprogramm, um mit einem Produkt ohne Support zu helfen, das diese Identitätsfelder erstellt. Ich habe keine Kontrolle darüber, wie es funktioniert.
Metapher