Grundlegendes zu SQL Server LOCKS bei SELECT-Abfragen


79

Ich frage mich, welchen Nutzen es SELECT WITH (NOLOCK)für eine Tabelle hat, wenn die einzigen anderen Abfragen, die diese Tabelle betreffen, SELECTAbfragen sind.

Wie geht das mit SQL Server um? Würde eine SELECTAbfrage eine andere SELECTAbfrage blockieren ?

Ich verwende SQL Server 2012 und ein Linq-to-SQL DataContext.

(BEARBEITEN)

Über die Leistung:

  • Würde ein 2. SELECTwarten müssen, bis ein 1. SELECTfertig ist, wenn er ein Schloss verwendet SELECT?
  • Versus a SELECT WITH (NOLOCK)?

Antworten:


178

Ein SELECTin SQL Server platziert eine gemeinsame Sperre für eine Tabellenzeile - und eine zweite SELECTwürde auch eine gemeinsame Sperre erfordern, und diese sind miteinander kompatibel.

Also nein - einer SELECTkann keinen anderen blockieren SELECT.

Der WITH (NOLOCK)Abfragehinweis wird verwendet, um Daten lesen zu können, die gerade eingefügt werden (durch eine andere Verbindung) und die noch nicht festgeschrieben wurden.

Ohne diesen Abfragehinweis SELECTkann das Lesen einer Tabelle durch eine fortlaufende INSERT(oder UPDATE) Anweisung blockiert werden, die Zeilen (oder möglicherweise eine ganze Tabelle) exklusiv sperrt, bis die Transaktion dieser Operation festgeschrieben (oder zurückgesetzt) ​​wurde.

Das Problem des WITH (NOLOCK)Hinweises ist: Möglicherweise lesen Sie am Ende Datenzeilen, die überhaupt nicht eingefügt werden (wenn die INSERTTransaktion zurückgesetzt wird). In Ihrem z. B. Bericht werden möglicherweise Daten angezeigt, die nie wirklich in die Datenbank übernommen wurden .

Es gibt einen weiteren Abfragehinweis, der nützlich sein könnte - WITH (READPAST). Dies weist den SELECTBefehl an, nur alle Zeilen zu überspringen, die er zu lesen versucht und die ausschließlich gesperrt sind. Das SELECTwird nicht blockiert und es werden keine "schmutzigen" nicht festgeschriebenen Daten gelesen - es werden jedoch möglicherweise einige Zeilen übersprungen, z. B. werden nicht alle Zeilen in der Tabelle angezeigt.


1
Schöne Antwort, vielen Dank! Würde es Auswirkungen (auf Hunderte von SELECTAbfragen) geben, die WITH (NOLOCK)ohne Grund verwendet werden könnten?
Francis P

3
Wir verwenden mit Nolock in 99,5% unserer Auswahl, kein Scherz. Wenn ein Administrator einen Benutzerdatensatz aktualisiert, soll der Bericht nicht dort abgelegt werden und auf den Abschluss der gesamten verteilten Transaktion warten. Ihre alten Daten werden also im Bericht angezeigt. Wen interessiert das? Wenn der Bericht eine Sekunde zuvor ausgeführt worden wäre, wären dies dieselben Daten, die mit Rowlock vorhanden gewesen wären. Der einzige Ort, um den es geht, sind Daten, die noch nicht festgeschrieben sind. Wenn Sie "Bestellungen in der letzten Stunde" anzeigen, könnte dies möglicherweise ein Problem sein, aber ein winziges Problem im Vergleich zu Geschwindigkeits- / Parallelitätsgewinnen.
Brian White

5
Da "Bericht" als Beispiel verworfen wurde, beziehen sich Berichte normalerweise auf einen Zeitraum, der nicht die letzten 5 Minuten beträgt. Berichterstattung über Daten aus dem letzten Monat mit nolock - nun, es ist nicht so, dass die Daten einen Monat später zurückgesetzt werden.
Brian White

2
@FrancisP: Nicht, wenn Sie eine kleine Anzahl von Zeilen einfügen. In diesem Fall werden nur die neu eingefügten Zeilen gesperrt. Wenn Sie mehr als ungefähr 5000 Zeilen gleichzeitig einfügen, tritt eine Sperreskalation auf und die gesamte Tabelle wird ausschließlich gesperrt.
Marc_s

1
Sehr schöne Antwort. Es fühlte sich an wie ein All-in-One-Tutorial für SQL-Sperren! Ich bin froh, dass ich hier reingekommen bin!
digitally_inspired

32

Bei der Leistung konzentrieren Sie sich weiterhin auf die Auswahl.
Shared blockiert keine Lesevorgänge.
Aktualisierung der freigegebenen Sperrblöcke.
Wenn Sie Hunderte von gemeinsam genutzten Sperren haben, dauert es eine Weile, bis eine exklusive Sperre vorliegt, da gewartet werden muss, bis die freigegebenen Sperren gelöscht sind.

Standardmäßig nimmt eine Auswahl (Lesen) eine gemeinsame Sperre.
Gemeinsame (S) Sperren ermöglichen gleichzeitigen Transaktionen das Lesen (SELECT) einer Ressource.
Eine gemeinsame Sperre, die sich nicht auf andere Auswahlen auswirkt (1 oder 1000).

Der Unterschied besteht darin, wie der Nolock- oder der Shared-Lock-Effekt aktualisiert oder eingefügt werden.

Keine anderen Transaktionen können die Daten ändern, solange gemeinsam genutzte (S) Sperren für die Ressource vorhanden sind.

Eine gemeinsame Sperre blockiert ein Update!
Nolock blockiert jedoch kein Update.

Dies kann enorme Auswirkungen auf die Leistung von Updates haben. Es wirkt sich auch auf Einsätze aus.

Dirty Read (Nolock) klingt einfach schmutzig. Sie werden niemals Teildaten erhalten. Wenn ein Update John in Sally ändert, werden Sie niemals Jolly bekommen.

Ich verwende häufig gemeinsam genutzte Sperren für die Parallelität. Daten sind veraltet, sobald sie gelesen werden. Eine Lektüre von John, die in der nächsten Millisekunde zu Sally wechselt, sind veraltete Daten. Eine Lektüre von Sally, die John in der nächsten Millisekunde zurückgesetzt wird, sind veraltete Daten. Das ist im Millisekundenbereich. Ich habe einen Datenlader, dessen Ausführung 20 Stunden dauert, wenn Benutzer gemeinsam genutzte Sperren verwenden, und dessen Ausführung 4 Stunden dauert, wenn Benutzer keine Sperren verwenden. Gemeinsame Sperren führen in diesem Fall dazu, dass die Daten 16 Stunden veraltet sind.

Verwenden Sie keine falschen Nolocks. Aber sie haben einen Platz. Wenn Sie einen Scheck schneiden möchten, wenn ein Byte auf 1 gesetzt ist, und ihn dann auf 2 setzen, wenn der Scheck geschnitten wird - keine Zeit für einen Nolock.


2
Vielen Dank. Wir sehen ähnliche Leistungsmerkmale. Unsere Website würde nicht ausgeführt, wenn wir Sperren für Lesevorgänge benötigen würden, und die Auswirkungen, wenn wir sie nicht haben, sind in den meisten Fällen nur unbedeutend.
Brian White

@BrianWhite Danke. Jemand bekommt es. Und ich nehme viele Tabellensperren beim Aktualisieren und Einfügen. Einsteigen, erledigen und aussteigen ist mein Ansatz.
Paparazzo

2
Dirty Read (Nolock) klingt einfach schmutzig. Sie werden niemals Teildaten erhalten. Wenn ein Update John in Sally ändert, werden Sie niemals Jolly bekommen. - Wir lesen John richtig?
MonsterMMORPG

2
Updates auf dem SQL Server verwenden die Update-Sperre (U), die später in die exklusive Sperre (X) konvertiert wird. (Siehe madeiradata.com/role-update-lock-sql-server. ) Die Aktualisierungssperre blockiert keine freigegebenen Sperren, aber die exklusive Sperre blockiert alle anderen Sperren (siehe msdn.microsoft.com/en-us/library/ms186396(v=) sql.105) .aspx ).
Kolobok

@ Kolobok wird eine Weile dauern, um ein exklusives Schloss zu bekommen
Paparazzo

10

Ich muss einen wichtigen Kommentar hinzufügen. Jeder erwähnt, dass NOLOCKnur schmutzige Daten gelesen werden. Das ist nicht genau. Es ist auch möglich, dass Sie dieselbe Zeile zweimal erhalten oder die gesamte Zeile beim Lesen übersprungen wird. Der Grund dafür ist, dass Sie möglicherweise gleichzeitig nach Daten fragen, wenn SQL Server den B-Baum neu ausbalanciert.

Überprüfen Sie andere Threads

https://stackoverflow.com/a/5469238/2108874

http://www.sqlmag.com/article/sql-server/quaere-verum-clustered-index-scans-part-iii.aspx )

Mit dem NOLOCK-Hinweis (oder dem Festlegen der Isolationsstufe der Sitzung auf READ UNCOMMITTED) teilen Sie SQL Server mit, dass Sie keine Konsistenz erwarten, sodass keine Garantien bestehen. Beachten Sie jedoch, dass "inkonsistente Daten" nicht nur bedeuten, dass Sie möglicherweise nicht festgeschriebene Änderungen sehen, die später zurückgesetzt wurden, oder Datenänderungen in einem Zwischenzustand der Transaktion. Dies bedeutet auch, dass in einer einfachen Abfrage, die alle Tabellen- / Indexdaten scannt, SQL Server möglicherweise die Scanposition verliert oder Sie dieselbe Zeile zweimal erhalten.


9

Bei meiner Arbeit haben wir ein sehr großes System, das auf vielen PCs gleichzeitig läuft, mit sehr großen Tabellen mit Hunderttausenden von Zeilen und manchmal vielen Millionen Zeilen.

Wenn Sie ein SELECT für eine sehr große Tabelle vornehmen, möchten Sie beispielsweise wissen, dass jede Transaktion, die ein Benutzer in den letzten 10 Jahren durchgeführt hat, und der Primärschlüssel der Tabelle nicht effizient erstellt wurde. Die Abfrage kann einige Minuten dauern laufen.

Dann kann unsere Anwendung auf vielen PCs eines Benutzers gleichzeitig ausgeführt werden und auf dieselbe Datenbank zugreifen. Wenn also jemand versucht, in die Tabelle einzufügen, die der andere SELECT liest (auf Seiten, die SQL zu lesen versucht), kann ein LOCK auftreten und die beiden Transaktionen blockieren sich gegenseitig.

Wir mussten unserer SELECT-Anweisung ein "NO LOCK" hinzufügen, da es sich um ein riesiges SELECT auf einer Tabelle handelte, die von vielen Benutzern gleichzeitig häufig verwendet wird, und wir hatten die ganze Zeit LOCKS.

Ich weiß nicht, ob mein Beispiel klar genug ist? Dies ist ein Beispiel aus dem wirklichen Leben.


Vielen Dank für das Beispiel, aber ich wundere mich nur über SELECT-Abfragen, die andere SELECT-Abfragen betreffen (in derselben Tabelle).
Francis P

1
Sie werden es nicht tun, aber eine select-Anweisung könnte Teil einer Transaktion sein, die ein Update enthält. Aktualisiere tbl set x = (wähle max (y) von tbl) wobei z = (wähle min (a) von tbl). Wenn Sie eine gleichzeitige Auswahl von z aus tbl haben, blockieren die anderen Auswahlen diese nicht, aber das Update ist.
Brian White

1
Ich hatte genau das Problem, dass eine lang laufende Auswahl meine Einfügungen blockierte
nojetlag

2
Die Transaktionen blockieren sich nicht gegenseitig - die Auswahl blockiert die Aktualisierung. Hier sind ein paar interessante Links, die mir gerade geholfen haben, ein bisschen mehr darüber zu verstehen, wie dieses Zeug funktioniert: erste eine zweite
JonnyRaa

@JonnyLeeds: Dein 2. Link funktioniert nicht mehr. Hier ist ein archivierter Link von SQL Server:
Sperren von

3

Das SELECT WITH (NOLOCK)ermöglicht es liest von unbestätigten Daten, die mit der Äquivalent READ UNCOMMITTEDIsolationsstufe auf Ihrer Datenbank. Das NOLOCKSchlüsselwort ermöglicht eine feinere Steuerung als das Festlegen der Isolationsstufe für die gesamte Datenbank.

Wikipedia hat einen nützlichen Artikel: Wikipedia: Isolation (Datenbanksysteme)

Es wird auch ausführlich in anderen Stackoverflow-Artikeln besprochen.


Vielen Dank an rghome für die zusätzlichen Informationen, die Sie zur Verfügung gestellt haben.
Francis P

Aus diesem Grund bevorzuge ich die Verwendung des Hinweises READUNCOMMITTED(ein Alias ​​für NOLOCK), wenn dies ein gültiger Anwendungsfall ist. Dadurch wird die tatsächliche Operation, die nicht wirklich "ohne Sperren" ist, weniger unklar.
user2864740

1

Ohne Sperre auswählen - Wählt Datensätze aus, die möglicherweise eingefügt werden oder nicht. Sie werden schmutzige Daten lesen.

Beispiel: Nehmen wir an, eine Transaktion fügt 1000 Zeilen ein und schlägt dann fehl.

Wenn Sie auswählen, erhalten Sie die 1000 Zeilen.


Aber was ist, wenn kein Datensatz in diese Tabelle eingefügt werden soll, ist NO LOCK immer noch relevant?
Francis P

Nein ist es nicht. da read eine gemeinsame Sperre verwendet, die von mehr als einer Sitzung erfasst werden kann. Es gibt keine Möglichkeit, schmutzige Daten zu erhalten.
Royi Namir

Ich möchte lieber nicht auf etwas antworten, dessen ich mir nicht sicher bin. :-)
Royi Namir
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.