Verwirrt über UPDLOCK, HOLDLOCK

88

Bei der Untersuchung der Verwendung von Tabellenhinweisen bin ich auf diese beiden Fragen gestoßen:

Antworten auf beide Fragen besagen, dass (UPDLOCK, HOLDLOCK)andere Prozesse bei der Verwendung keine Daten in dieser Tabelle lesen können, aber ich habe dies nicht gesehen. Zum Testen habe ich eine Tabelle erstellt und zwei SSMS-Fenster gestartet. Im ersten Fenster habe ich eine Transaktion ausgeführt, die anhand verschiedener Tabellenhinweise aus der Tabelle ausgewählt wurde. Während die Transaktion ausgeführt wurde, habe ich im zweiten Fenster verschiedene Anweisungen ausgeführt, um zu sehen, welche blockiert werden würden.

Die Testtabelle:

CREATE TABLE [dbo].[Test](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Value] [nvarchar](50) NULL,
 CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Aus SSMS-Fenster 1:

BEGIN TRANSACTION

SELECT * FROM dbo.Test WITH (UPDLOCK, HOLDLOCK)
WAITFOR DELAY '00:00:10'

COMMIT TRANSACTION

Aus SSMS-Fenster 2 (führte eine der folgenden Aktionen aus):

SELECT * FROM dbo.Test
INSERT dbo.Test(Value) VALUES ('bar')
UPDATE dbo.Test SET Value = 'baz' WHERE Value = 'bar'
DELETE dbo.Test WHERE Value= 'baz'

Auswirkung verschiedener Tabellenhinweise auf Anweisungen in Fenster 2:

           (UPDLOCK)       (HOLDLOCK)    (UPDLOCK, HOLDLOCK)    (TABLOCKX)
---------------------------------------------------------------------------
SELECT    not blocked      not blocked       not blocked         blocked
INSERT    not blocked        blocked           blocked           blocked
UPDATE      blocked          blocked           blocked           blocked
DELETE      blocked          blocked           blocked           blocked

Habe ich die Antworten in diesen Fragen falsch verstanden oder bei meinen Tests einen Fehler gemacht? Wenn nicht, warum würden Sie (UPDLOCK, HOLDLOCK)vs. (HOLDLOCK)allein verwenden?


Weitere Erklärung dessen, was ich erreichen möchte:

Ich möchte Zeilen aus einer Tabelle auswählen und verhindern, dass die Daten in dieser Tabelle während der Verarbeitung geändert werden. Ich ändere diese Daten nicht und möchte, dass Lesevorgänge stattfinden.

Diese Antwort besagt eindeutig, dass (UPDLOCK, HOLDLOCK)Lesevorgänge blockiert werden (nicht das, was ich will). Die Kommentare zu dieser Antwort implizieren, HOLDLOCKdass dies das Lesen verhindert. Um zu versuchen, die Auswirkungen der Tabellenhinweise besser zu verstehen und zu sehen, ob UPDLOCKallein das tun würde, was ich wollte, habe ich das obige Experiment durchgeführt und Ergebnisse erhalten, die diesen Antworten widersprechen.

Derzeit glaube ich, dass (HOLDLOCK)ich das verwenden sollte, aber ich befürchte, dass ich einen Fehler gemacht oder etwas übersehen habe, das mich in Zukunft beißen wird, daher diese Frage.

Jeff Ogata
quelle

Antworten:

102

Warum sollte UPDLOCK Block auswählen? Die Sperr-Kompatibilitätsmatrix zeigt deutlich Nfür die S / U- und U / S-Konflikte, wie in No Conflict .

Was den HOLDLOCK- Hinweis betrifft, heißt es in der Dokumentation:

HOLDLOCK: Entspricht SERIALIZABLE. Weitere Informationen finden Sie unter SERIALIZABLE weiter unten in diesem Thema.

...

SERIALIZABLE: ... Der Scan wird mit derselben Semantik wie eine Transaktion ausgeführt, die auf der Isolationsstufe SERIALIZABLE ausgeführt wird ...

Im Thema Transaktionsisolationsstufe wird erläutert, was SERIALIZABLE bedeutet:

Keine anderen Transaktionen können Daten ändern, die von der aktuellen Transaktion gelesen wurden, bis die aktuelle Transaktion abgeschlossen ist.

Andere Transaktionen können keine neuen Zeilen mit Schlüsselwerten einfügen, die in den Bereich von Schlüsseln fallen würden, die von Anweisungen in der aktuellen Transaktion gelesen werden, bis die aktuelle Transaktion abgeschlossen ist.

Daher wird das angezeigte Verhalten in der Produktdokumentation perfekt erklärt:

  • UPDLOCK blockiert nicht gleichzeitig SELECT oder INSERT, sondern blockiert UPDATE oder DELETE der von T1 ausgewählten Zeilen
  • HOLDLOCK bedeutet SERALIZABLE und erlaubt daher SELECTS, blockiert jedoch UPDATE und DELETES der von T1 ausgewählten Zeilen sowie alle INSERT in dem von T1 ausgewählten Bereich ( dh die gesamte Tabelle, also alle Einfügung).
  • (UPDLOCK, HOLDLOCK): Ihr Experiment zeigt nicht, was zusätzlich zu dem obigen Fall blockieren würde, nämlich eine weitere Transaktion mit UPDLOCK in T2 :
    SELECT * FROM dbo.Test WITH (UPDLOCK) WHERE ...
  • TABLOCKX braucht keine Erklärungen

Die eigentliche Frage ist, was Sie erreichen wollen . Das Spielen mit Sperrhinweisen ohne ein absolut vollständiges 110% iges Verständnis der Sperrsemantik bittet um Ärger ...

Nach der OP-Bearbeitung:

Ich möchte Zeilen aus einer Tabelle auswählen und verhindern, dass die Daten in dieser Tabelle während der Verarbeitung geändert werden.

Sie sollten eine der höheren Transaktionsisolationsstufen verwenden. REPEATABLE READ verhindert, dass die von Ihnen gelesenen Daten geändert werden. SERIALIZABLE verhindert, dass die von Ihnen gelesenen Daten geändert und neue Daten eingefügt werden. Die Verwendung von Transaktionsisolationsstufen ist der richtige Ansatz im Gegensatz zur Verwendung von Abfragehinweisen. Kendra Little hat ein schönes Poster, das die Isolationsstufen erklärt .

Remus Rusanu
quelle
+1 und danke für die ausführliche Antwort. Ich werde meine Frage aktualisieren, um die Details meines Ziels hinzuzufügen.
Jeff Ogata
1
@Remus Rusanu Könnten Sie bitte erläutern, warum der richtige Ansatz Isolationsstufen anstelle von Abfragehinweisen verwendet? Ich habe eine Prozedur, bei der ich nur zwei Tabellen sperren muss, um geändert zu werden, und ich verwende TABLOCK, HOLDLOCK. Sollte ich wirklich zur Isolationsstufe wechseln und alle Tabellen in meiner Transaktion sperren?
Steve
Ich könnte eine Erklärung für TABLOCKX mögen :)
Niico
Hinweis: Der Link für den Blogeintrag für Kendra Little gibt eine 404 zurück. Ich kann keinen Eintrag vom 2. Februar 2011 finden, wie der Link andeutet.
Bacon Bits
21

UPDLOCK wird verwendet, wenn Sie eine oder mehrere Zeilen während einer select-Anweisung für eine zukünftige Update-Anweisung sperren möchten. Das zukünftige Update könnte die nächste Anweisung in der Transaktion sein.

Andere Sitzungen können die Daten weiterhin sehen. Sie können einfach keine Sperren erhalten, die mit UPDLOCK und / oder HOLDLOCK nicht kompatibel sind.

Sie verwenden UPDLOCK, wenn Sie möchten, dass andere Sitzungen die gesperrten Zeilen nicht ändern. Es schränkt ihre Fähigkeit ein, gesperrte Zeilen zu aktualisieren oder zu löschen.

Sie verwenden HOLDLOCK, wenn Sie verhindern möchten, dass andere Sitzungen die angezeigten Daten ändern. Dies schränkt die Möglichkeit ein, die gesperrten Zeilen einzufügen, zu aktualisieren oder zu löschen. Auf diese Weise können Sie die Abfrage erneut ausführen und dieselben Ergebnisse anzeigen.

Scott Bruns
quelle
1
Vielen Dank, aber ich glaube nicht, dass Sie meine Frage wirklich beantwortet haben: Waren die Antworten auf diese Fragen falsch, als Sie sagten, dass der (UPDLOCK,HOLDLOCK)Block lautet, und gibt es einen Grund, (UPDLOCK,HOLDLOCK)statt nur zu verwenden (HOLDLOCK)?
Jeff Ogata
Meine zweite Aussage beantwortet Ihre Frage, sie sind falsch. Andere Sitzungen können die Daten weiterhin lesen.
Scott Bruns
Updlock, Holdlock ist nicht dasselbe wie Holdlock. Updlock, Holdlock sperrt die Zeilen für die Aktualisierung und serialisiert Ihre Transaktion. Holdlock selbst serialisiert nur Ihre Transaktion. Die ausgewählten Zeilen werden nicht für den weiteren Zugriff gesperrt.
Scott Bruns
"UPDLOCK wird verwendet, wenn Sie eine oder mehrere Zeilen während einer select-Anweisung für eine zukünftige Update-Anweisung sperren möchten." Ich liebe das, da XLOCK möglicherweise irgendwann nicht mehr funktioniert
Yiping