TABLOCK vs TABLOCKX

75

Was ist der Unterschied zwischen TABLOCKund TABLOCKX http://msdn.microsoft.com/en-us/library/ms187373.aspx besagt, dass TABLOCKes sich um eine gemeinsam genutzte Sperre handelt, während TABLOCKXes sich um eine exklusive Sperre handelt. Ist die erste vielleicht nur eine Art Indexsperre? Und was ist das Konzept, ein Schloss zu teilen?

Carlo V. Dango
quelle
8
Es TABLOCKhandelt sich um eine gemeinsam genutzte Sperre, mit der mehrere Clients gleichzeitig Daten in die Tabelle laden können. Eine exklusive Sperre nicht.
Lieven Keersmaekers
@Lieven Bei Tablocks wird die gegenseitige Ausschließlichkeit von der Sperre ausgeschlossen, in der die Datentabelle in einem reservierten Seitenspeicherzyklus gespeichert wird.
Roel

Antworten:

103

Großer Unterschied, TABLOCKwird versuchen, "gemeinsame" Sperren und TABLOCKXexklusive Sperren zu greifen .

Wenn Sie sich in einer Transaktion befinden und eine exklusive Sperre für einen Tisch erhalten, z.

SELECT 1 FROM TABLE WITH (TABLOCKX)

Keine andere Prozesse werden in der Lage zu greifen alle Sperren auf dem Tisch, was bedeutet , alle Anfragen versuchen , auf den Tisch zu reden , bis die Transaktion Commits blockiert werden.

TABLOCKgreift nur nach einer gemeinsam genutzten Sperre, freigegebene Sperren werden freigegeben, nachdem eine Anweisung ausgeführt wurde, wenn Ihre Transaktionsisolation READ COMMITTED(Standard) ist. Wenn Ihre Isolationsstufe höher ist , zum Beispiel: SERIALIZABLEwerden gemeinsam genutzte Sperren bis zum Ende einer Transaktion gehalten.


Geteilte Schlösser werden geteilt, hmmm. Das bedeutet, dass 2 Transaktionen beide gleichzeitig Daten aus der Tabelle lesen können, wenn beide eine S- oder IS-Sperre für die Tabelle haben (via TABLOCK). Wenn jedoch transaction Aeine gemeinsam genutzte Sperre für eine Tabelle vorhanden ist, transaction Bkann erst dann eine exklusive Sperre aktiviert werden, wenn alle gemeinsam genutzten Sperren freigegeben wurden. Lesen Sie bei msdn, welche Sperren mit welchen kompatibel sind .


Beide Hinweise führen dazu, dass die Datenbank detailliertere Sperren umgeht (z. B. Sperren auf Zeilen- oder Seitenebene). Im Prinzip ermöglichen detailliertere Sperren eine bessere Parallelität. So könnte beispielsweise eine Transaktion Zeile 100 in Ihrer Tabelle und eine weitere Zeile 1000 gleichzeitig aus zwei Transaktionen aktualisieren (bei Seitensperren wird es schwierig, aber lassen Sie uns das überspringen).

Im Allgemeinen möchten Sie granulare Sperren, aber manchmal möchten Sie möglicherweise die DB-Parallelität reduzieren, um die Leistung eines bestimmten Vorgangs zu steigern und die Möglichkeit von Deadlocks auszuschließen.

Im Allgemeinen würden Sie es nicht verwenden TABLOCKoder es TABLOCKXsei denn, Sie benötigen es unbedingt für einen Randfall.

Sam Safran
quelle
8
Einer dieser Randfälle ist beispielsweise eine Situation, in der Sie die Tabelle zunächst erstellen und beispielsweise mit Daten füllen INSERT INTO. In solchen Situationen kann eine exklusive Sperre einen großen Leistungsgewinn bringen.
Abel
1
Dies bedeutet, dass alle Abfragen, die versuchen, mit der Tabelle zu kommunizieren, blockiert werden, bis die Transaktion festgeschrieben wird. Das ist nicht wahr. Sie können immer noch mit dem NOLOCK oder TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
Po-ta-toe
Dies scheint auf SQL Server 2016 nicht zu funktionieren?
Frederik Gheysels
5

Ein ganz alter Artikel über mssqlcity versucht, die Arten von Sperren zu erklären:

Freigegebene Sperren werden für Vorgänge verwendet, bei denen Daten nicht geändert oder aktualisiert werden, z. B. eine SELECT-Anweisung.

Aktualisierungssperren werden verwendet, wenn SQL Server beabsichtigt, eine Seite zu ändern, und später die Aktualisierung der Seitensperre auf eine exklusive Seitensperre hochstufen, bevor die Änderungen tatsächlich vorgenommen werden.

Exklusive Sperren werden für Datenänderungsvorgänge wie UPDATE, INSERT oder DELETE verwendet.

Was nicht besprochen wird, ist Absicht (was im Grunde ein Modifikator für diese Sperrtypen ist). Absichtsschlösser (gemeinsam genutzt / exklusiv) sind Schlösser, die auf einer höheren Ebene als das eigentliche Schloss gehalten werden. Wenn Ihre Transaktion beispielsweise eine X-Sperre für eine Zeile hat, verfügt sie auch über eine IX-Sperre auf Tabellenebene (wodurch verhindert wird, dass andere Transaktionen versuchen, eine inkompatible Sperre auf einer höheren Ebene der Tabelle zu erhalten (z. B. ein Schema) Änderungssperre), bis Ihre Transaktion abgeschlossen ist oder zurückgesetzt wird).


Das Konzept der "Freigabe" einer Sperre ist recht einfach: Mehrere Transaktionen können eine gemeinsame Sperre für dieselbe Ressource haben, während nur eine einzelne Transaktion eine exklusive Sperre haben kann und eine exklusive Sperre jede Transaktion daran hindert, eine gemeinsame Sperre zu erhalten oder zu halten.

Damien_The_Unbeliever
quelle
Gibt es einen Unterschied, wie lange die Schlösser gehalten werden? TABLOCK wird bis zum Ende der Anweisung gehalten. Wenn auch HOLDLOCK angegeben ist, wird die gemeinsame Tabellensperre bis zum Ende der Transaktion beibehalten. Aber was ist mit TABLOCKX
Carlo V. Dango
@Carlo - Exklusive Sperren werden immer bis zum Ende der Transaktion gehalten.
Damien_The_Unbeliever
1
@Carlo, alle gemeinsam genutzten Sperren werden am Ende einer Anweisung in einer Transaktion mit festgeschriebenem Lesevorgang freigegeben. Wenn Sie die Sperren halten möchten, benötigen Sie Hinweise oder eine höhere Isolationsstufe. tablockxwird ein X-Schloss greifen.
Sam Saffron
3

Dies ist eher ein Beispiel, bei dem TABLOCK bei mir und TABLOCKX nicht funktioniert hat.

Ich habe 2 Sitzungen, die beide die Standardisolationsstufe (READ COMMITTED) verwenden:

Sitzung 1 ist eine explizite Transaktion, die Daten von einem Verbindungsserver in eine Reihe von Tabellen in einer Datenbank kopiert und deren Ausführung einige Sekunden dauert. [Beispiel, es löscht Fragen] Sitzung 2 ist eine Einfügeanweisung, die einfach Zeilen in eine Tabelle einfügt, an der Sitzung 1 keine Änderungen vornimmt. [Beispiel, es fügt Antworten ein].

(In der Praxis werden mehrere Sitzungen gleichzeitig in die Tabelle eingefügt, während Sitzung 1 die Transaktion ausführt.)

Sitzung 1 muss die Tabelle abfragen, in die Sitzung 2 eingefügt wird, da keine Datensätze gelöscht werden können, die von Einträgen abhängen, die von Sitzung 2 hinzugefügt wurden. [Beispiel: Löschen von Fragen, die nicht beantwortet wurden].

Während also Sitzung 1 ausgeführt wird und Sitzung 2 versucht einzufügen, verliert Sitzung 2 jedes Mal einen Deadlock.

Eine Löschanweisung in Sitzung 1 könnte also ungefähr so ​​aussehen: DELETE tblA FROM tblQ LEFT JOIN tblX on ... LEFT JOIN tblA a ON tblQ.Qid = tblA.Qid WHERE ... a.QId IS NULL und ...

Der Deadlock scheint durch einen Konflikt zwischen der Abfrage von tblA verursacht zu werden, während Sitzung 2, [3, 4, 5, ..., n] versuchen, in tblA einzufügen.

In meinem Fall könnte ich die Isolationsstufe der Transaktion von Sitzung 1 so ändern, dass sie SERIALISIERBAR ist. Als ich dies tat: Der Transaktionsmanager hat die Unterstützung für Remote- / Netzwerktransaktionen deaktiviert.

Ich könnte also den Anweisungen in der akzeptierten Antwort hier folgen, um das Problem zu umgehen: Der Transaktionsmanager hat die Unterstützung für Remote- / Netzwerktransaktionen deaktiviert

Aber a) ich war überhaupt nicht damit zufrieden, die Isolationsstufe auf SERIALIZABLE zu ändern - angeblich verschlechtert dies die Leistung und kann andere Konsequenzen haben, die ich nicht berücksichtigt habe. B) Ich habe nicht verstanden, warum dies plötzlich zu einer Transaktion geführt hat ein Problem, das auf Verbindungsservern funktioniert, und c) ich weiß nicht, welche möglichen Lücken ich durch die Aktivierung des Netzwerkzugriffs öffnen könnte.

Es schien nur 6 Abfragen innerhalb einer sehr großen Transaktion zu geben, die die Probleme verursachen.

Also habe ich über TABLOCK und TabLOCKX gelesen.

Ich war mir der Unterschiede nicht ganz sicher und wusste nicht, ob beides funktionieren würde. Aber es schien so. Zuerst habe ich TABLOCK ausprobiert und es schien keinen Unterschied zu machen. Die konkurrierenden Sitzungen erzeugten die gleichen Deadlocks. Dann habe ich TABLOCKX ausprobiert und keine Deadlocks mehr.

An sechs Stellen musste ich also nur ein WITH (TABLOCKX) hinzufügen.

Eine Löschanweisung in Sitzung 1 könnte also ungefähr so ​​aussehen: LÖSCHEN von tblA VON tblQ q LINKS VERBINDEN tblX x on ... LINKS VERBINDEN tblA a WITH (TABLOCKX) ON tblQ.Qid = tblA.Qid WHERE ... a.QId IST NULL und ...

John
quelle
2
Willkommen bei stackoverflow! Vielen Dank für Ihre erste Antwort. Ich denke, diese Antwort wäre für andere nützlicher, wenn Sie die persönlichen Referenzen entfernen und sich an die grundlegenden Fakten halten würden. Mach weiter so!
Caltor