Transaktionsisolationsproblem oder falscher Ansatz?

7

Ich habe meinen Kollegen mit einem SQL-Problem geholfen. Hauptsächlich wollten sie alle Zeilen von Tabelle A nach Tabelle B verschieben (beide Tabellen haben die gleichen Spalten (Namen und Typen)). Obwohl dies in Oracle 11g gemacht wurde, glaube ich nicht, dass es wirklich wichtig ist.

Ihre anfängliche naive Implementierung war etwas wie

%Vor%

Sie hatten Bedenken, wenn INSERTs während des Kopierens von A nach B in Tabelle A eingefügt wurden und das "DELETE FROM A" (oder TRUNCATE für was es wert war) zu Datenverlust führen würde (die neu eingefügten Zeilen in A wurden gelöscht).

Natürlich empfahl ich schnell, die IDs der kopierten Zeilen in einer temporären Tabelle zu speichern und dann nur die Zeilen in A zu löschen, die mit der IDS in der temporären Tabelle übereinstimmten.

Aus Neugier haben wir jedoch einen kleinen Test gemacht, indem wir zwischen INSERT und DELETE einen Wartebefehl (erinnern Sie sich nicht an die PL / SQL-Syntax) hinzugefügt haben. Aus einer anderen Verbindung würden wir Zeilen WÄHREND DER WARTE einfügen.

Wir haben festgestellt, dass dies ein Datenverlust war. Ich reproduzierte den gesamten Kontext in SQL Server und wickelte alles in eine Transaktion ein, aber die neuen Daten gingen auch in SQL Server verloren. Dies ließ mich glauben, dass es einen systematischen Fehler / Fehler in der anfänglichen Herangehensweise gibt.

Ich kann jedoch nicht sagen, ob es die Tatsache war, dass die TRANSACTION nicht (irgendwie?) von den frischen neuen INSERTs oder der Tatsache, dass die INSERTs während des WAIT-Befehls kamen, isoliert wurde.

Am Ende wurde es mit der von mir vorgeschlagenen temporären Tabelle implementiert, aber wir konnten die Antwort "Warum der Datenverlust" nicht bekommen. Weißt du warum?

    
Andrei Rînea 29.09.2008, 19:09
quelle

11 Antworten

8

Abhängig von Ihrer Isolationsstufe verhindert die Auswahl aller Zeilen einer Tabelle keine neuen Einfügungen. Sie werden nur die Zeilen sperren, die Sie gelesen haben. Wenn Sie in SQL Server die Isolationsstufe Serializable verwenden, werden neue Zeilen verhindert, wenn sie in die ausgewählte Abfrage aufgenommen wurden.

Ссылка -

SERIALIZABLE Gibt Folgendes an:

  • Anweisungen können keine Daten lesen, die von anderen Transaktionen geändert, aber noch nicht festgelegt wurden.

  • Keine anderen Transaktionen können Daten ändern, die von der aktuellen Transaktion gelesen wurden, bis die aktuelle Transaktion abgeschlossen ist.

  • Andere Transaktionen können keine neuen Zeilen mit Schlüsselwerten einfügen, die in den Bereich von Schlüsseln fallen, die von Anweisungen in der aktuellen Transaktion gelesen werden, bis die aktuelle Transaktion abgeschlossen ist.

jwanagel 29.09.2008, 19:26
quelle
7

Ich kann nicht mit der Transaktionsstabilität sprechen, aber ein alternativer Ansatz bestünde darin, den zweiten Schritt aus der Quellentabelle löschen zu lassen, wo er existiert (wählen Sie IDs aus der Zieltabelle).

Verzeihen Sie die Syntax, ich habe diesen Code nicht getestet, aber Sie sollten in der Lage sein, die Idee zu bekommen:

%Vor%

Auf diese Weise verwenden Sie die relationale Engine, um zu erzwingen, dass keine neueren Daten gelöscht werden, und Sie müssen die zwei Schritte in einer Transaktion nicht durchführen.

Update: korrigierte Syntax in Unterabfrage

    
Guy Starbuck 29.09.2008 19:17
quelle
5

Dies kann in Oracle mithilfe von

erreicht werden %Vor%

Dies kann in PL / SQL mit EXECUTE IMMEDIATE:

gesetzt werden %Vor%

Siehe Fragen Sie Tom: On Transaction Isolation Levels

    
Tony Andrews 29.09.2008 19:19
quelle
2

Es ist nur so, wie Transaktionen funktionieren. Sie müssen die richtige Isolationsstufe für die jeweilige Aufgabe auswählen.

Sie tun INSERT und DELETE in derselben Transaktion. Sie erwähnen nicht die Isolationsmodus-Transaktion, die verwendet wird, aber es ist wahrscheinlich "Read Committed". Dies bedeutet, dass der DELETE-Befehl die Datensätze anzeigen wird, die in der Zwischenzeit festgeschrieben wurden. Für diese Art von Job ist es viel besser, den Snapshot-Typ der Transaktion zu verwenden, da dann sowohl INSERT als auch DELETE über die gleiche Menge von Datensätzen verfügen - nur diese und nichts anderes.

    
Milan Babuškov 29.09.2008 19:20
quelle
1

Ich weiß nicht, ob das relevant ist, aber in SQL Server ist die Syntax

%Vor%

nicht nur 'beginnen'

    
Steven A. Lowe 29.09.2008 19:13
quelle
1

Sie müssen Ihre Transaktionsisolationsstufe so festlegen, dass die Einfügungen aus einer anderen Transaktion Ihre Transaktion nicht beeinflussen. Ich weiß nicht, wie ich das in Oracle machen soll.

    
Paul Tomblin 29.09.2008 19:14
quelle
1

In Oracle wird die Standardtransaktionsisolationsstufe gelesen, festgeschrieben. Das bedeutet, dass Oracle die Ergebnisse so zurückgibt, wie sie beim SCN (System Change Number) vorhanden waren, als Ihre Abfrage gestartet wurde. Wenn Sie die Transaktionsisolationsstufe auf serializable festlegen, bedeutet dies, dass der SCN zu Beginn der Transaktion erfasst wird, sodass alle Abfragen in Ihrer Transaktion Daten ab diesem SCN zurückgeben. Dies gewährleistet konsistente Ergebnisse unabhängig davon, was andere Sitzungen und Transaktionen tun. Auf der anderen Seite kann es zu Kosten kommen, da Oracle feststellen kann, dass es Ihre Transaktion aufgrund von Aktivitäten, die andere Transaktionen ausführen, nicht serialisieren kann, sodass Sie diese Art von Fehlern behandeln müssten.

Tony's Link zu der AskTom-Diskussion geht wesentlich ausführlicher über all das - ich empfehle es sehr.

    
Justin Cave 29.09.2008 20:27
quelle
0

Ja Milan, ich habe die Transaktionsisolationsstufe nicht angegeben. Ich nehme an, es ist die Standard-Isolationsstufe, von der ich nicht weiß, welche es ist. Weder in Oracle 11g noch in SQL Server 2005.

Außerdem wurde das INSERT, das während des WAIT-Befehls (auf der zweiten Verbindung) gemacht wurde, innerhalb einer Transaktion NICHT gemacht. Sollte es gewesen sein, diesen Datenverlust zu verhindern?

    
Andrei Rînea 29.09.2008 19:25
quelle
0

Dies ist das Standardverhalten des Standard-Read-Committed-Modus, wie oben erwähnt. Der WAIT-Befehl verursacht nur eine Verzögerung bei der Verarbeitung, es gibt keine Verknüpfung zu irgendeiner DB-Transaktionsverarbeitung.

Um das Problem zu beheben, können Sie entweder:

  1. setze die Isolationsstufe auf serialisierbar, aber dann kannst du ORA-Fehler bekommen, die du mit Wiederholungen behandeln musst! Außerdem können Sie einen ernsthaften Leistungseinbruch erleiden.
  2. Verwenden Sie eine temporäre Tabelle, um die Werte zuerst zu speichern
  3. Wenn die Daten nicht zu groß sind, um in den Speicher zu passen, können Sie eine RETURNING-Klausel verwenden, um BULK COLLECT IN eine geschachtelte Tabelle zu erstellen, und nur löschen, wenn die Zeile in der geschachtelten Tabelle vorhanden ist.
Andrew not the Saint 30.09.2008 07:27
quelle
0

Alternativ können Sie die Snapshot-Isolation verwenden, um verloren gegangene Updates zu erkennen:

Wenn Snapshot Isolation hilft und wenn es wehtut

    
A-K 13.07.2009 14:16
quelle
0
%Vor%

U kann es testen, indem neue Zeilen wie von oracle definiert eingefügt werden: -  Ein Phantom-Lesen tritt auf, wenn die Transaktion A eine Reihe von Zeilen abruft, die eine gegebene Bedingung erfüllen, die Transaktion B anschließend eine Zeile einfügt oder aktualisiert, so dass die Zeile nun die Bedingung in Transaktion A erfüllt, und Transaktion A später die bedingte Suche wiederholt. Transaktion A sieht jetzt eine zusätzliche Zeile. Diese Zeile wird als Phantom bezeichnet. Es wird das obige Szenario ebenso vermeiden wie TRANSACTION_SERIALIZABLE. Es wird die strengste Sperre für das Oracle festlegen. Oracle unterstützt nur zwei Typen von Transaktionsisolationsstufen: - TRANSACTION_READ_COMMITTED und TRANSACTION_SERIALIZABLE.

    
Goyal Vicky 04.08.2015 19:27
quelle