SQL Server NOLOCK und Joins


153

Hintergrund: Ich habe eine leistungskritische Abfrage, die ich ausführen möchte, und mir sind Dirty Reads egal.

Meine Frage ist; Wenn ich Joins verwende, muss ich auch für diese den NOLOCK-Hinweis angeben?

Zum Beispiel; ist:

SELECT * FROM table1 a WITH (NOLOCK)
INNER JOIN table2 b WITH (NOLOCK) ON a.ID = b.ID

Gleichwertig:

SELECT * FROM table1 a WITH (NOLOCK)
INNER JOIN table2 b ON a.ID = b.ID

Oder muss ich den (NOLOCK)Hinweis auf dem Join angeben, um sicherzustellen, dass ich die verknüpfte Tabelle nicht sperre?

Antworten:


166

Ich werde das READ UNCOMMITTEDArgument nicht ansprechen , nur Ihre ursprüngliche Frage.

Ja, Sie müssen WITH(NOLOCK)auf jeder Tabelle des Joins. Nein, Ihre Fragen sind nicht gleich.

Versuchen Sie diese Übung. Starten Sie eine Transaktion und fügen Sie eine Zeile in Tabelle1 und Tabelle2 ein. Die Transaktion noch nicht festschreiben oder zurücksetzen. Zu diesem Zeitpunkt wird Ihre erste Abfrage erfolgreich zurückgegeben und enthält die nicht festgeschriebenen Zeilen. Ihre zweite Abfrage wird nicht zurückgegeben, da table2 keinen WITH(NOLOCK)Hinweis darauf enthält.


18

Ich war mir ziemlich sicher, dass Sie die NOLOCKfür jeden JOINin der Abfrage angeben müssen . Meine Erfahrung war jedoch auf SQL Server 2005 beschränkt.

Als ich zur Bestätigung nach MSDN suchte, konnte ich nichts Bestimmtes finden. Die folgenden Aussagen scheinen mich zu denken, dass Ihre beiden obigen Aussagen für 2008 gleichwertig sind, obwohl dies für 2005 nicht der Fall ist:

[SQL Server 2008 R2]

Alle Sperrhinweise werden an alle Tabellen und Ansichten weitergegeben, auf die der Abfrageplan zugreift , einschließlich Tabellen und Ansichten, auf die in einer Ansicht verwiesen wird. Außerdem führt SQL Server die entsprechenden Überprüfungen der Sperrkonsistenz durch.

[SQL Server 2005]

In SQL Server 2005 werden alle Sperrhinweise an alle Tabellen und Ansichten weitergegeben, auf die in einer Ansicht verwiesen wird. Außerdem führt SQL Server die entsprechenden Überprüfungen der Sperrkonsistenz durch.

Beachten Sie außerdem, dass dies sowohl für 2005 als auch für 2008 gilt:

Die Tabellenhinweise werden ignoriert, wenn der Abfrageplan nicht auf die Tabelle zugreift. Dies kann daran liegen, dass der Optimierer überhaupt nicht auf die Tabelle zugreift oder stattdessen auf eine indizierte Ansicht zugegriffen wird. Im letzteren Fall kann der Zugriff auf eine indizierte Ansicht mithilfe des OPTION (EXPAND VIEWS)Abfragehinweises verhindert werden .


@In Sane: Interessant ... danke dafür ... Ich gehe davon aus, dass ich keinen Schaden anrichte, indem ich es in die JOINS aufnehme, auch wenn es nicht unbedingt notwendig ist? Die Dokumentation zu NOLOCK ist, wie Sie bereits erwähnt haben, ziemlich spärlich. Ich hatte Probleme, selbst etwas aussagekräftiges zu finden.
DanP

2
@InSane: Woher hast du diese Informationen? Es scheint gegen die akzeptierte Antwort zu gehen.
Jay Sullivan

1
@notfed - siehe technet link technet.microsoft.com/en-us/library/ms187373(v=sql.105).aspx - Sie können die Datenbankversion oben ändern, um denselben Artikel für verschiedene Versionen der Datenbank zu vergleichen
Jagmag

2
Der Text von 2005 spricht über ANSICHTEN. Wenn Sie also "aus myview mit (nolock)" ausführen, heißt es, dass der nolock an alle an myview beteiligten Tabellen und Ansichten weitergegeben wird (Sie könnten dort 10 Joins haben). Ich bin mir nicht sicher, was der Text von 2008 genau bedeutet, da er zusätzlich zu den Ansichten "Zugriff durch den Abfrageplan" hinzufügt.
Thierry_S

9

Weder. Sie legen die Isolationsstufe fest, READ UNCOMMITTEDdie immer besser ist, als einzelne Sperrhinweise zu geben. Oder, noch besser, wenn Sie sich für Details wie Konsistenz interessieren , verwenden Sie die Snapshot-Isolation .


@Remus: Ich bin nicht sicher, ob ich in meinem Fall READ UNCOMMITTED verwenden kann, da ich über NHibernate auf die Verbindung zugreife, um einen speziellen ADO.NET-Rohaufruf auszuführen. Kann dies in der Abfrage inline angegeben werden oder wird die auf der NHibernate-Transaktion vorhandene Transaktionsebene eingehalten?
DanP

Wickeln Sie den Anruf ein using (TransactionScope scope=new TransactionScope(..., TransactionOptions) {...}und stellen Sie die folgenden IsolationLevelOptionen ein: msdn.microsoft.com/en-us/library/…
Remus Rusanu

@Remus: Leider wird das Transaktionsmanagement auf einer viel höheren Ebene erledigt, daher ist dies auch keine Option.
DanP

Aha. Um Ihre Frage zu beantworten: NOLOCK ist ein Tabellenhinweis und gilt als solcher für das Rowset, zu dem hinzugefügt wird (Tabelle, Ansicht, TVF usw.). Wenn Sie mehrere Rowsets in einer Abfrage verknüpft haben, benötigt jedes einen eigenen NOLOCK-Hinweis.
Remus Rusanu

2
Aber haben Sie über eine Schnappschussisolation nachgedacht? ALTER DATABASE ... SET READ_COMMITTED_SNAPSHOT ON;. Die Ergebnisse sind spektakulär, da alle normalen Lesevorgänge zu Lesevorgängen werden, die sperrfrei und dennoch konsistent sind. Die Kosten sind erhöht tempdbladen: msdn.microsoft.com/en-us/library/ms175492.aspx
Remus Rusanu
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.