it-swarm.com.de

Verwendet meine SQL-Abfrage veraltete Daten? Wie kann ich das verhindern?

Ich habe zwei Tabellen (SJob & SJobDependent), die ich für eine Logik in einer gespeicherten Prozedur verbinden muss. Sie haben beide eine Spalte (job), die sie in einer Eins-zu-Viele-Beziehung verbindet - eine SJob Datensatz für null oder mehr SJobDependent Datensätze.

Hier ist meine SQL-Abfrage:

-- Return any records that are active and have no unsatisfied dependencies.
SELECT * FROM SJob
LEFT JOIN SJobDependent
    ON SJob.job = SJobDependent.job
    AND SJobDependent.satisfied = 0
WHERE SJobDependent.jobDependentID IS NULL
AND SJob.state = 'active'

Hier ist der Ist-Ausführungsplan von SQL Server Studio:

(SQL Server Studio Actual Execution Plan

Aufgrund der Art und Weise, wie der Code geschrieben ist:

// Pseudo-code:

// SJob record is added with SJob.state = 'ready'.

// Related SJobDependent record(s) are added.

// SJob record is updated to SJob.state = 'active'.

Ich befürchte, dass dies passieren kann, wenn die SQL-Abfrage ausgeführt wird:

  1. SJobDependent scannen.
  2. SJobDependent-Datensatz (e) eingefügt.
  3. Starten Sie den Scan von SJob. SJob.state ist 'bereit'.
  4. SJob wird aktualisiert. Dies blockiert das Lesen von SJob?
  5. Scan von SJob beenden. SJob.state ist 'aktiv'.

Ich befürchte, dass meine SQL-Abfrage SJob Datensätze zurückgibt, die im Status "aktiv" (SJob.state = 'active') Gefunden wurden, die zugehörigen SJobDependent Datensätze jedoch nicht sehen.

Kann dieses Problem auftreten oder analysiere ich die SQL-Abfrage zu stark?

Was kann ich tun, um das Problem zu lösen, wenn dies ein legitimes Problem ist? Ich bin offen für Lösungen.

Eine Idee, die ich hatte, ist, den Scan von SJobDependent nach dem Scan von SJob zu erzwingen. Ist das überhaupt möglich? Was sind die Implikationen/Konsequenzen davon?

Treten die im tatsächlichen Ausführungsplan angezeigten Scans in einer bestimmten Reihenfolge auf oder sind sie von Anruf zu Anruf immer zufällig?

HINWEIS : Wie in der Antwort von AMtwo erwähnt, wird die Isolationsstufe "Wiederholbares Lesen" mein Problem wahrscheinlich nicht lösen dass es nur wirksam wird, wenn das Lesen startet.

6
Max Jacob

Wenn Sie die Standardisolationsstufe in SQL Server (Read Committed) verwenden, können Sie bei inkonsistenten Lesevorgängen auf alle möglichen Probleme stoßen. Paul White beschreibt die Probleme hier .

Wenn Sie möchten, dass Ihre Leseabfragen Daten lesen, die vollständig mit dem Aussehen zu einem bestimmten Zeitpunkt übereinstimmen, empfehlen wir Ihnen, Read Committed Snapshot Isolation (RCSI) in Betracht zu ziehen. Mit RCSI gibt Ihre Abfrage Daten zurück, die zu einem bestimmten Zeitpunkt (dem Beginn Ihrer Abfrage) konsistent sind. Wenn Benutzer A eine SELECT-Abfrage startet, während Benutzer B gleichzeitig Aktualisierungen durchführt, liest Benutzer A den "alten" Wert, da er einen Schnappschuss der Daten liest konsistent zum Beginn der Abfrage.

Der Haken bei RCSI ist, dass es sich um eine Einstellung auf Datenbankebene handelt. Im Gegensatz zu "Nicht festgeschrieben lesen" können Sie es nicht als sitzungsbezogene Einstellung festlegen. Sie müssen diese Änderung globaler berücksichtigen, bevor Sie die Änderung vornehmen. Wenn Sie jedoch für diese Abfrage konsistente Lesevorgänge benötigen, möchten Sie wahrscheinlich konsistente Lesevorgänge für die gesamte Anwendung.

Während die Isolationsstufe Repeatable Read zur Lösung Ihres Problems ansprechend erscheint, beachten Sie dieses Detail aus dem verlinkten Beitrag:

Die wiederholbare Leseisolationsstufe bietet eine Garantie dafür, dass Daten werden sich nicht ändern für die Dauer der Transaktion sobald sie gelesen wurden zum ersten Mal.

Dies bedeutet, dass die Daten vor dem Zugriff noch geändert werden können, jedoch während der Ausführung Ihrer Abfrage. Es unterliegt auch einigen der gleichen inkonsistenten Lesevorgänge wie die Isolationsstufe "Read Committed" - insbesondere Phantome.

8
AMtwo

Sie müssen darüber nachdenken, wie die Arbeitslast insgesamt abläuft, wie Ihre Anweisungen die Arbeit anderer sehen und wie Sie ihre sehen. Sie sollten auch die möglichen Zeitpunkte von Aktionen aus zwei gleichzeitig ausgeführten Arbeitsabläufen berücksichtigen.

Aus Ihrer Frage geht nicht hervor, aber ich gehe davon aus, dass die Abfrage ("Hier ist meine SQL-Abfrage") in einer Sitzung (S1) und der Pseudocode in einer anderen (S2) ausgeführt wird. Ich nehme an, dass jeder Durchgang durch den Pseudocode nur einen Job einfügt. Die Frage ist, was von S2s Arbeit S1 sehen kann, da S1 an jedem Punkt im S2-Stream ganz oder teilweise ausgeführt werden kann.

Ich werde "keine" sagen. Ich sage das, weil die Abfrage speziell nach SJob.state = 'active' Sucht. S2 fügt einen Wert in SJob mit dem Status 'ready' ein. S1 liest diese Zeile also nicht. Ja, die Zeile kann von S1 überprüft werden (abhängig von der Isolationsstufe von S1), wird jedoch aufgrund des Statuswerts abgelehnt und wird niemals Teil der Ergebnismenge von S1. Obwohl SJobDependent die Build-Seite des Hash-Joins ist, werden alle abgerufenen Zeilen im Filter-Operator zurückgewiesen und werden niemals Teil der Ausgabe von S1.

Erst wenn in beiden Tabellen Zeilen vorhanden sind, setzt S2 den Status auf einen Wert, den S1 lesen kann. Dieses Update ist garantiert atomar (es funktioniert entweder vollständig oder wird vollständig zurückgesetzt). Da nur ein Wert in einer Zeile aktualisiert wird, wird er isoliert - S1 kann niemals einen Wert zwischen "bereit" und "aktiv" sehen.


Ohne das Prädikat für den Status hätte es Probleme geben können. Solange S1 mit READ COMMITTED oder höher ausgeführt wird, gibt es jedoch immer noch kein Problem. S2 könnte eine explizite Transaktion um den gesamten Block legen. Dann würden seine exklusiven Sperren bis zum Ende gehalten (bis in beiden Tabellen ein konsistenter Satz von Zeilen vorhanden ist). S1 wäre entweder abgeschlossen, bevor diese Sperren vorhanden waren und nur konsistente Daten angezeigt wurden, oder hätte gewartet, bis diese Sperren wieder freigegeben wurden, um konsistente Daten zu sehen. Wenn S1 mit READ UNCOMMITTED (oder NOLOCK, dasselbe) ausgeführt wird, wird die Arbeit von S2 zur Hälfte abgeschlossen und es treten Fehler auf.

1
Michael Green