Wie füge ich eine Prüfbedingung in Postgres hinzu, ohne die Tabelle zu sperren?

9

Ich möchte einer sehr großen Tabelle eine Prüfbedingung hinzufügen. Etwas wie:

ALTER TABLE "accounts" ADD CONSTRAINT "positive_balance" CHECK ("balance" >= 0);

Leider blockiert PostgreSQL 9.3 Lese- oder Schreibvorgänge, bis die Einschränkungsprüfung abgeschlossen ist. Ich habe dies überprüft, indem ich eine Transaktion gestartet, die ausgeführt ALTER TABLE, dann eine zweite Transaktion geöffnet und überprüft habe, ob ich bis zum Abschluss der ersten Transaktion nicht aus der Tabelle lesen oder schreiben konnte.

Kann ich diese CHECKEinschränkung auf irgendeine Weise hinzufügen , ohne die Tabelle zu sperren?

Kevin Burke
quelle
Dies ist nicht spezifisch für die Prüfbedingung. Alle (oder fast alle) DDL-Anweisungen erfordern eine exklusive Sperre für die Tabelle. Dies ist auch nichts Besonderes für Postgres. Die meisten DBMS-Anweisungen funktionieren auf diese Weise für DDL-Anweisungen.
a_horse_with_no_name

Antworten:

11

Sie können eine NOT VALIDCHECK-Einschränkung erstellen , die die Einschränkung in Zukunft erzwingt, jedoch nicht die gesamte Tabelle beim Erstellen auf Validierung überprüft. Zu einem späteren Zeitpunkt können Sie versuchen, VALIDATEdie Einschränkung zu ändern (wenn eine Sperre für die Tabelle in Ordnung ist).

Bitte überprüfen Sie die Dokumentation - Zitat unten:

ADD table_constraint [ NOT VALID ]

Dieses Formular fügt einer Tabelle eine neue Einschränkung hinzu, die dieselbe Syntax wie CREATE TABLEund die Option verwendet NOT VALID, die derzeit nur für Fremdschlüssel- und CHECK-Einschränkungen zulässig ist. Wenn die Einschränkung markiert ist NOT VALID, wird die möglicherweise langwierige Erstprüfung, um sicherzustellen, dass alle Zeilen in der Tabelle die Einschränkung erfüllen, übersprungen. Die Einschränkung wird weiterhin für nachfolgende Einfügungen oder Aktualisierungen erzwungen (dh, sie schlagen fehl, es sei denn, die referenzierte Tabelle enthält eine übereinstimmende Zeile, bei Fremdschlüsseln, und sie schlagen fehl, es sei denn, die neue Zeile entspricht der angegebenen Prüfung Einschränkungen). Die Datenbank geht jedoch nicht davon aus, dass die Einschränkung für alle Zeilen in der Tabelle gilt, bis sie mithilfe der VALIDATE CONSTRAINTOption überprüft wird.

Joishi Bodio
quelle
6

(Nicht genug Vertreter, um die andere Antwort zu kommentieren)

Aus der Formulierung in der akzeptierten Antwort geht nicht hervor, was "wenn eine Sperre auf dem Tisch in Ordnung ist" bedeutet.

Laut Postgres ALTER TABLE docs :

VALIDATE CONSTRAINTschnappt sich einen SHARE UPDATE EXCLUSIVEauf dem veränderten Tisch,

und aus den Sperrdokumenten

SHARE UPDATE EXCLUSIVEkönnen andere gleichzeitige Transaktionen eine bekommen ROW EXCLUSIVESperre (die durch benutzt wird INSERT, UPDATE, DELETE) und SELECTist mit jedem Lock-Typ neben erlaubt ACCESS EXCLUSIVE.

Bedeutung - "Lesen / Schreiben" wird beim Ausführen nicht blockiert VALIDATE CONSTRAINT- Sie müssen nicht "warten, bis das Sperren der Tabelle in Ordnung ist".

Dan Anderson
quelle
1
Zum Zeitpunkt des Schreibens (PostgreSQL 9.3) VALIDATE CONSTRAINTschnappte sich ein ACCESS EXCLUSIVESchloss. Dies sind jedoch gute Informationen für zukünftige Leser und Versionen. +1 von mir
Joishi Bodio
Ah, gut zu wissen - danke für das Update / die Klarstellung!
Dwanderson