Serialisierbare Isolierung - Amazon Redshift

Serialisierbare Isolierung

Einige Anwendungen erfordern nicht nur gleichzeitiges Abfragen und Laden, sondern auch die Fähigkeit, gleichzeitig zu mehreren Tabellen oder zur selben Tabelle zu schreiben. In diesem Zusammenhang bedeutet gleichzeitig überlappend, nicht die Ausführung zu exakt demselben Zeitpunkt. Zwei Transaktionen werden als gleichzeitig betrachtet, wenn die zweite Transaktion gestartet wird, bevor für die erste Transaktion ein Commit ausgeführt wird. Gleichzeitige Operationen können ihren Ursprung in verschiedenen Sitzungen haben, die vom selben Benutzer oder von verschiedenen Benutzern kontrolliert werden.

Anmerkung

Amazon Redshift unterstützt standardmäßig automatische Commits, bei denen für jeden getrennt ausgeführten SQL-Befehl ein einzelnes Commit ausgeführt wird. Wenn Sie in einem Transaktionsblock einen Satz von Befehlen einschließen (definiert durch die Anweisungen BEGIN und END), wird der Block als eine einzige Transaktion übergeben, sodass Sie ein Rollback für ihn ausführen können, wenn notwendig. Ausnahmen von diesem Verhalten sind die Befehle TRUNCATE und VACUUM, die automatische alle ausstehenden Änderungen, die in der aktuellen Transaktion vorgenommen wurden, übergeben.

Einige SQL-Clients geben automatisch BEGIN- und COMMIT-Befehle aus, sodass der Client steuert, ob eine Gruppe von Anweisungen als Transaktion oder jede einzelne Anweisung als eigene Transaktion ausgeführt wird. Konsultieren Sie die Dokumentation zu der von Ihnen verwendeten Schnittstelle. Wenn Sie zum Beispiel den JDBC-Treiber von Amazon Redshift verwenden, führt ein JDBC PreparedStatement mit einer Abfragezeichenfolge, die mehrere (durch Semikolon getrennte) SQL-Befehle enthält, alle Anweisungen als eine einzige Transaktion aus. Wenn Sie dagegen SQL Workbench/J verwenden und AUTO COMMIT ON festlegen, wird beim Ausführen mehrer Anweisungen jede Anweisung als eigene Transaktion ausgeführt.

Gleichzeitige Schreiboperationen werden in Amazon Redshift auf geschützte Art unterstützt, indem Schreibsperren für Tabellen und der Grundsatz der serialisierbaren Isolierung angewendet werden. Die serialisierbare Isolierung bewahrt die Illusion, dass eine Transaktion, die für eine Tabelle ausgeführt wird, die einzige Transaktion ist, die für diese Tabelle ausgeführt wird. Beispielsweise müssen zwei gleichzeitig ausgeführte Transaktionen T1 und T2 in mindestens einer der folgenden Varianten dieselben Ergebnisse produzieren:

  • T1 und T2 werden seriell in dieser Reihenfolge ausgeführt.

  • T2 und T1 werden seriell in dieser Reihenfolge ausgeführt.

Gleichzeitige Transaktionen können sich gegenseitig nicht sehen, d. h., sie können die Änderungen der jeweils anderen Transaktionen nicht erkennen. Jede gleichzeitige Transaktion erstellt zu Beginn der Transaktion einen Snapshot der Datenbank. Innerhalb der Transaktion wird beim ersten Auftreten der meisten SELECT-Anweisungen, von DML-Befehlen wie COPY, DELETE, INSERT, UPDATE und TRUNCATE und der folgenden DDL-Befehle ein Datenbank-Snapshot erstellt:

  • ALTER TABLE (Hinzufügen oder Entfernen von Spalten)

  • CREATE TABLE

  • DROP TABLE

  • TRUNCATE TABLE

Wenn eine beliebige serielle Ausführung der gleichzeitigen Transaktionen dieselben Ergebnisse wie ihre gleichzeitige Ausführung produzieren würde, gelten diese Transaktionen als „serialisierbar“ und können sicher ausgeführt werden. Wenn keine serielle Ausführung dieser Transaktionen dieselben Ergebnisse produziert, wird die Transaktion abgebrochen, die eine Anweisung ausführt, die die Serialisierbarkeit verhindern würde. Für diese Transaktion wird ein Rollback ausgeführt.

Systemkatalogtabellen (PG) und andere Amazon-Redshift-Systemtabellen (STL und STV) sind in einer Transaktion nicht gesperrt. Daher sind Änderungen an Datenbankobjekten, die aufgrund von DDL- und TRUNCATE-Transaktionen entstanden sind, beim Commit für alle gleichzeitigen Transaktionen erkennbar.

Angenommen, Tabelle A ist in der Datenbank vorhanden, wenn zwei gleichzeitige Transaktionen, T1 und T2, gestartet werden. Angenommen, T2 gibt eine Liste von Tabellen zurück, indem Sie aus der Katalogtabelle PG_TABLES auswählen. Dann löscht T1 Tabelle A und Commits, und dann listet T2 die Tabellen erneut auf. Tabelle A ist jetzt nicht mehr aufgeführt. Wenn T2 versucht, eine Abfrage für die entfernte Tabelle auszuführen, gibt Amazon Redshift den Fehler „Beziehung nicht vorhanden“ zurück. Die Katalogabfrage, die die Liste von Tabellen an T2 zurückgibt oder überprüft, ob Tabelle A vorhanden ist, unterliegt nicht denselben Isolierungsregeln wie Operationen in Benutzertabellen.

Transaktionen für Aktualisierungen dieser Tabellen werden im Isolierungsmodus read committed ausgeführt. PG-prefix-Katalogtabellen unterstützen die Snapshot-Isolierung nicht.

Serialisierbare Isolierung für Systemtabellen und Katalogtabellen

Ein Datenbank-Snapshot wird auch in einer Transaktion für eine SELECT-Abfrage erstellt, die eine benutzererstellte Tabelle oder eine Amazon-Redshift-Systemtabelle (STL oder STV) referenziert. SELECT-Abfragen, die keine Tabellen referenzieren, erstellen keinen neuen Transaktionsdatenbank-Snapshot. Die Anweisungen INSERT, DELETE und UPDATE, die ausschließlich für Systemkatalogtabellen (PG) ausgeführt werden, erstellen ebenfalls keinen neuen Transaktionsdatenbank-Snapshot.

Beheben von Fehlern für die serialisierbare Isolierung

FEHLER: 1023 DETAIL: Serialisierbare Isolationsverletzung für eine Tabelle in Redshift

Wenn Amazon Redshift einen Fehler für die serialisierbare Isolierung erkennt, wird Ihnen eine Fehlermeldung ähnlich der folgenden Fehlermeldung angezeigt.

ERROR:1023 DETAIL: Serializable isolation violation on table in Redshift

Um einen Fehler für die serialisierbare Isolierung zu beheben, können Sie die folgenden Methoden anwenden:

  • Wiederholen der abgebrochenen Transaktion.

    Amazon Redshift hat festgestellt, dass ein gleichzeitiger Workload nicht serialisierbar ist. Dies weist auf Lücken in der Anwendungslogik hin, die normalerweise bearbeitet werden können, indem die Transaktion erneut versucht wird, bei der der Fehler aufgetreten ist. Wenn das Problem weiterhin besteht, wenden Sie eine der anderen Methoden an.

  • Verschieben Sie alle Operationen, die sich nicht in derselben atomaren Transaktion befinden müssen, aus der Transaktion.

    Diese Methode kann angewendet werden, wenn sich einzelne Operationen innerhalb von zwei Transaktion gegenseitig so referenzieren, dass das Ergebnis der jeweils anderen Transaktion beeinflusst werden kann. Die folgenden beiden Sitzungen starten beispielsweise jeweils eine Transaktion.

    Session1_Redshift=# begin;
    Session2_Redshift=# begin;

    Das Ergebnis einer SELECT-Anweisung in einer der beiden Transaktionen könnte durch eine INSERT-Anweisung in der jeweils anderen Transaktion beeinflusst werden. Angenommen, Sie führen die folgenden Anweisungen seriell in beliebiger Reihenfolge aus. In jedem Fall besteht das Ergebnis darin, dass eine der SELECT-Anweisungen eine Zeile mehr zurückgibt, als dies bei einer gleichzeitigen Ausführung der Transaktionen der Fall wäre. Es gibt keine Reihenfolge, in der die Operationen seriell ausgeführt werden können und zum gleichen Ergebnis wie bei einer gleichzeitigen Ausführung führen. Daher führt die zuletzt ausgeführte Operation zu einem Fehler für die serialisierbare Isolierung.

    Session1_Redshift=# select * from tab1; Session1_Redshift=# insert into tab2 values (1);
    Session2_Redshift=# insert into tab1 values (1); Session2_Redshift=# select * from tab2;

    In vielen Fällen ist das Ergebnis der SELECT-Anweisungen nicht wichtig. Mitanderen Worten: Die Atomizität der Operationen in den Transaktionen ist nicht wichtig. In diesen Fällen verschieben Sie die SELECT-Anweisungen aus den Transaktionen wie in den folgenden Beispielen gezeigt.

    Session1_Redshift=# begin; Session1_Redshift=# insert into tab1 values (1) Session1_Redshift=# end; Session1_Redshift=# select * from tab2;
    Session2_Redshift # select * from tab1; Session2_Redshift=# begin; Session2_Redshift=# insert into tab2 values (1) Session2_Redshift=# end;

    In diesen Beispielen gibt es keine Querbezüge in den Transaktionen. Die beiden INSERT-Anweisungen beeinflussen sich nicht gegenseitig. In diesen Beispielen gibt es mindestens eine Reihenfolge, in der die Transaktionen seriell ausgeführt werden können und zum gleichen Ergebnis wie bei einer gleichzeitigen Ausführung führen. Das bedeutet, dass die Transaktionen serialisierbar sind.

  • Sie können die Serialisierung erzwingen, indem Sie alle Tabellen in jeder Sitzung sperren.

    Der Befehl LOCK blockiert Operationen, die zu Fehlern für die serialisierbare Isolierung führen können. Wenn Sie den Befehl LOCK verwenden, müssen Sie Folgendes ausführen:

    • Sperren Sie alle Tabellen, die von der Transaktion betroffen sind, einschließlich Tabellen, die von schreibgeschützten SELECT-Anweisungen innerhalb der Transaktion betroffen sind.

    • Sperren Sie die Tabellen in derselben Reihenfolge, unabhängig von der Reihenfolge, in der die Operationen ausgeführt werden.

    • Sperren Sie alle Tabellen zu Beginn der Transaktion, bevor Operationen ausgeführt werden.

FEHLER: 1018 DETAIL: Beziehung existiert nicht

Wenn Sie Amazon-Redshift-Vorgänge in verschiedenen Sitzungen ausführen, wird Ihnen eine Fehlermeldung ähnlich der folgenden Fehlermeldung angezeigt.

ERROR: 1018 DETAIL: Relation does not exist.

Transaktionen in Amazon Redshift folgen der Snapshot-Isolation. Nachdem eine Transaktion gestartet wurde, erstellt Amazon Redshift einen Snapshot der Datenbank. Während des gesamten Lebenszyklus der Transaktion arbeitet die Transaktion mit dem Status der Datenbank, wie sie im Snapshot wiedergegeben wird. Wenn die Transaktion aus einer Tabelle liest, die nicht im Snapshot vorhanden ist, wird die zuvor angezeigte Fehlermeldung 1018 ausgelöst. Selbst wenn eine andere gleichzeitige Transaktion eine Tabelle erstellt, nachdem die Transaktion den Snapshot erstellt hat, kann die Transaktion nicht aus der neu erstellten Tabelle lesen.

Um diesen Serialisierungsisolationsfehler zu beheben, können Sie versuchen, den Start der Transaktion an einen Punkt zu verschieben, an dem Sie wissen, dass die Tabelle existiert.

Wenn die Tabelle von einer anderen Transaktion erstellt wird, liegt dieser Punkt nach dem Commit dieser Transaktion. Stellen Sie außerdem sicher, dass gleichzeitig für keine Transaktion ein Commit durchgeführt wurde, das die Tabelle möglicherweise gelöscht hat.

session1 = # BEGIN; session1 = # DROP TABLE A; session1 = # COMMIT;
session2 = # BEGIN;
session3 = # BEGIN; session3 = # CREATE TABLE A (id INT); session3 = # COMMIT;
session2 = # SELECT * FROM A;

Daher führt die zuletzt von session2 als Lesevorgang ausgeführte Operation zu einem serialisierbaren Isolierungsfehler. Dieser Fehler tritt auf, wenn session2 einen Snapshot erstellt und die Tabelle bereits von einer festgeschriebenen session1 gelöscht wurde. Mit anderen Worten, obwohl eine gleichzeitige session3 die Tabelle erstellt hat, sieht session2 die Tabelle nicht, da sie sich nicht im Snapshot befindet.

Um diesen Fehler zu beheben, können Sie die Sitzungen wie folgt neu anordnen.

session1 = # BEGIN; session1 = # DROP TABLE A; session1 = # COMMIT;
session3 = # BEGIN; session3 = # CREATE TABLE A (id INT); session3 = # COMMIT;
session2 = # BEGIN; session2 = # SELECT * FROM A;

Wenn nun session2 seinen Snapshot erstellt, wurde für session3 bereits ein Commit ausgeführt, und die Tabelle befindet sich in der Datenbank. Session2 kann fehlerfrei aus der Tabelle lesen.