SQL Server SELECT-Anweisungen verursacht Blockierung
-
06-07-2019 - |
Frage
Wir verwenden eine SQL Server 2005-Datenbank (keine Zeilenversionsverwaltung) mit einer großen select-Anweisung, und wir sehen es andere Aussagen blockieren läuft (mit sp_who2
gesehen). Ich wusste nicht, SELECT-Anweisungen dazu führen könnten, blockiert - gibt es etwas, was ich tun kann, dies zu mildern
Lösung
SELECT können Updates blockieren. Ein richtig entworfenes Datenmodell und Abfrage wird nur eine minimale Blockierung verursachen und kein Problem sein. Die ‚übliche‘ MIT NOLOCK-Hinweis ist fast immer die falsche Antwort. Die richtige Antwort ist, stimmen Sie Ihre Abfrage, damit es nicht riesige Tabellen scannt.
Wenn die Abfrage ist untunable dann sollten Sie zunächst prüfen, Snapshot-Isolationsstufe , die zweite sollten Sie DATABASE SNAPSHOTS und letzte Option sollte DIRTY sein mit berücksichtigen READS (und ist besser in der Isolationsstufe zu ändern anstatt den NOLOCK-Hinweis verwendet wird). Beachten Sie, dass schmutzig liest, wie der Name eindeutig fest, werden inkonsistente Daten zurückgeben (z. Ihre gesamte Folie kann unausgewogen sein).
Andere Tipps
Shared (S)
Schleusen erlauben gleichzeitige Transaktionen(SELECT)
eine Ressource unter pessimistischen Concurrency Control zu lesen. Weitere Informationen finden SieTypes of Concurrency Control
. Keine andere Transaktionen können die Daten ändern, währendshared (S)
Sperren für die Ressource vorhanden ist.Shared (S)
Sperren auf einer Ressource werden, sobald der Lesevorgang abgeschlossen ist freigegeben, es sei denn, die Transaktion Isolationsstufe wiederholbar gesetzt lesen oder höher oder ein Verriegelungs Hinweis verwendet wird, um dieshared (S)
Sperren für die Dauer der Transaktion zu erhalten.
Ein shared lock
ist kompatibel mit anderer gemeinsamen Sperre oder einer Update-Sperre, aber nicht mit einer exklusiven Sperre.
Das bedeutet, dass Ihre SELECT
Abfragen UPDATE
und INSERT
Anfragen blockiert und umgekehrt.
Eine SELECT
Abfrage wird eine temporäre gemeinsame Sperre setzen, wenn es um einen Block von Werten aus der Tabelle liest, und entfernen Sie es, wenn es zu lesen getan.
Für die Zeit die Sperre existiert, werden Sie nicht in der Lage sein, etwas mit den Daten im gesperrten Bereich zu tun.
Zwei SELECT
Abfragen werden nie gegenseitig blockieren
SELECT FOR UPDATE
)
Sie können SNAPSHOT
Isolationsstufe auf Ihrer Datenbank aktivieren und verwenden, aber beachten Sie, dass es UPDATE
Abfragen nicht durch SELECT
Anfragen aus der Verriegelung verhindern (was Ihren Fall zu sein scheint).
Es wird aber verhindern SELECT
Anfragen von durch UPDATE
erfasst werden kann.
Beachten Sie auch, dass SQL Server
, im Gegensatz zu Oracle
, Lock-Manager verwendet und hält sie in einer In-Memory-verkettete Liste sperrt.
Das bedeutet, dass unter hoher Last, die bloße Tatsache des Vergebens und eine Sperre zu entfernen langsam sein kann, da die verkettete Liste sollte sich durch die Transaktion Thread gesperrt werden.
So führen Sie Dirty Reads können Sie entweder:
using (new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions {
IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
//Your code here
}
oder
SelectCommand = "SELECT * FROM Table1 WITH (NOLOCK) INNER JOIN Table2 WITH (NOLOCK) ..."
nicht vergessen, dass Sie WITH (NOLOCK) schreiben müssen nach jeder Tabelle, die Sie schmutzig lesen möchten
Sie können die Transaktionsebene Uncommitted Lesen
Sie können auch Deadlocks erhalten:
„Deadlocks, die nur eine Tabelle“ http: // sqlblog.com/blogs/alexander_kuznetsov/archive/2009/01/01/reproducing-deadlocks-involving-only-one-table.aspx
und oder falsche Ergebnisse:
"Wählen unter READ COMMITTED und wiederholbaren READ möglicherweise falsche Ergebnisse zurück."
Sie können WITH(READPAST)
Tabelle Hinweis verwenden. Es ist anders als die WITH(NOLOCK)
. Es werden die Daten erhalten, bevor die Transaktion gestartet wurde und wird niemanden blockieren. Stellen Sie sich vor, dass Sie die Anweisung lief, bevor die Transaktion gestartet wurde.
SELECT * FROM table1 WITH (READPAST)