2009-10-06 12 views
29

Ich habe viele Beispiele des HOLDLOCK Hinweises gesehen, der in Verbindung mit UPDLOCK (like this) benutzt wird. Jedoch scheint Microsoft's documentation für diese Hinweise, wie HOLDLOCK sollte redundant sein, da UPDLOCK die Sperre bereits bis zum Ende der Transaktion besteht. (Es scheint auch zu sagen, dass HOLDLOCK sowieso nur für gemeinsame Sperren gilt.)Welchen Einfluss hat HOLDLOCK auf UPDLOCK?

Wie wirkt sich HOLDLOCK auf die Abfrage aus, wenn überhaupt?

Antwort

59

Es hat eine große Auswirkung.

Die Update-Sperre erfordert eine Update-Sperre für die Zeile, eine Intent-Aktualisierung auf der Seite und eine gemeinsame Sperre für die Tabelle/Datenbank.

Das hindert andere Abfragen nicht daran, auf die Daten innerhalb der Tabelle zuzugreifen, da die Sperren auf der Seite/Datenbank reine Freigabe-Sperren sind. Sie können Sperren nur nicht gegen die einzelne Zeile/Seite/Tabelle stoßen, indem Sie versuchen, eine Operation auszuführen, die Sperren widerspricht. Wenn dies der Fall wäre, würde die Anfrage hinter den aktuellen Sperren in die Warteschlange gestellt und darauf warten, dass sie verfügbar wird, bevor sie fortfahren kann.

Mit Hilfe von Holdlock wird die Abfrage serialisiert und die Tabelle wird ausschließlich gesperrt, bis die Aktion abgeschlossen ist. Dies verhindert, dass jemand die Tabelle liest, es sei denn, der Nolock-Hinweis wird verwendet, was ein potenziell schmutziges Lesen ermöglicht.

Um den Effekt zu sehen, erstellen Sie eine Beispieltabelle 'foo' und fügen Sie einige Daten in den Papierkorb ein.

begin tran 

select * from foo with (updlock) 
where tableid = 1 
-- notice there is no commit tran 

öffnen ein weiteres Fenster und versuchen:

select * from foo 

Die Reihen zurückkommen, begehen nun die ursprüngliche Abfrage-Transaktion. Re-run es verändert auch die Verwendung holdlock:

begin tran 

select * from foo with (updlock, holdlock) 
where tableid = 1 

in das andere Fenster Gehen Sie zurück und versuchen, die Daten erneut auswählen, wird die Abfrage nicht Werte zurückgeben, da es durch die exklusive Sperre blockiert wird. Übernehmen Sie die Transaktion im ersten Fenster und die Ergebnisse in der zweiten Abfrage werden angezeigt, da sie nicht mehr blockiert sind.

Abschließender Test ist die Verwendung der Nolock, führen Sie die Transaktion erneut mit Hilfe von Update und Holdlock. dann läuft nach der im zweiten Fenster:

select * from foo (nolock) 

Die Ergebnisse kommen wieder automatisch, da Sie das Risiko einer schmutzigen Lese angenommen haben (lesen Sie uncommitted).

Es hat also einen großen Einfluss darauf, dass Sie Aktionen gegen diese Tabelle zur Serialisierung erzwingen, was Sie wünschen (abhängig von der durchgeführten Aktualisierung) oder einen sehr großen Engpass in dieser Tabelle erzeugen . Wenn dies bei einer ausgelasteten Tabelle mit lang laufenden Transaktionen der Fall wäre, würde dies zu erheblichen Verzögerungen innerhalb einer Anwendung führen.

Wie bei allen SQL-Funktionen können sie bei richtiger Verwendung sehr leistungsfähig sein, aber die falsche Verwendung eines Features/Hinweises kann zu erheblichen Problemen führen. Ich ziehe es vor, Hinweise als letzte Möglichkeit zu verwenden, wenn ich die Engine außer Kraft setzen muss - nicht als Standardansatz.

Bearbeiten als angefordert: Getestet in SQL 2005, 2008, 2008R2 (Alle Unternehmen) - alle auf ziemlich viele Standardeinstellungen installiert, Test-Datenbank erstellt mit allen Standardeinstellungen (nur den Namen der DB eingegeben).

+0

große antwort, danke – marijne

+0

nette erklärung, das hilft sehr! – Mercurybullet

+0

@Darren - Ich habe die von Ihnen vorgenommene Änderung rückgängig gemacht, keine Sperre ist nicht die Standardeinstellung und die zweite Auswahl sollte keine Update-Sperre übernehmen. – Andrew

12

Andrews Antwort richtig ist, ist laut MSDN-Dokumentation, jedoch habe ich getestet gegen 2008R2 und 2012 und ich sah mich nicht dieses Verhalten Sie sich so, TEST bitte

Das Verhalten, das ich zu sehen bin, ist wie folgt:

Führe das zuerst in einer Spieldatenbank aus.

CREATE TABLE [dbo].[foo](
    [tableid] [int] IDENTITY(1,1) NOT NULL, 
    [Col2] [varchar](100) NOT NULL, 
    CONSTRAINT [PK_foo] PRIMARY KEY CLUSTERED 
    (
     [tableid] ASC 
    ) 
) 

... und setzen ein paar Zeilen in

nun diesen Code in zwei Abfrage Registerkarten einfügen (die 'Reiter ein' Text in Tab wechseln zwei).

begin tran 

select * from foo with (UPDLOCK, HOLDLOCK) 
where tableid = 1 

UPDATE foo SET Col2 = 'tab one' 
where tableid = 1 

commit tran 

Und setzen diese in einem anderen Tab 3:

select * from foo 
where tableid = 1 
  1. Stellen Sie sicher, dass Sie auf Ihre Spieldatenbank zeigen, wo sich der Tisch befindet.

  2. Highlight alles vor die Update-Anweisung in Registerkarte 1 und auszuführen.

  3. Machen Sie dasselbe in Registerkarte 2 Sie finden Tab 2 wird nicht abgeschlossen und wird noch ausgeführt.

  4. nun die einfache SELECT in Tab 3in meiner Umgebung ausführen es vervollständigt.

  5. Markieren Sie die Update-Anweisung in Registerkarte 1 und führen Sie es (tun das noch nicht tun begehen), sehen Sie Tab 2 wird noch ausgeführt.

  6. Gehen Sie voran und führen die in Registerkarte begehen 1 ... Tab 2 wird nun die Auswahl vervollständigen ... Sie den Rest laufen kann.

+0

Welche Version von SQL Server wurde gegen diese Version ausgeführt? Wenn 2012, dann könnte das Verhalten geändert werden, aber 2005/2008/2008R2 holdlock würde es in den serialisierbaren Modus zwingen und alles andere daran hindern, eine gemeinsame Sperre zu übernehmen - was die "einfache" Auswahl versuchen wird auszugeben. – Andrew

+1

Eine andere Möglichkeit ist, dass Sie die isolierte Versionierung der Zeilenversion aktiviert haben - wenn die isolierte Versionierung der Zeilenversion vorhanden ist, gibt die "einfache" Auswahl keine gemeinsame Sperre, sondern nur eine Sch-S-Sperre aus Diese Isolationsstufe ist nicht die Standardeinstellung in 2008. Es wird interessant sein, den Unterschied in den Tests zu identifizieren. – Andrew

+0

@Andrew und Darren: Bitte bearbeiten Sie Ihre jeweiligen Beiträge und notieren Sie, welche Versionen von SQL Server * Sie * Ihre Lösungen getestet haben. Links, die alle Änderungen im Standardverhalten (oder Einstellungen, die Sie vorgenommen haben) beschreiben, würden ebenfalls geschätzt werden =) –

Verwandte Themen