PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

PostgreSQL 12:Fremdschlüssel und partitionierte Tabellen

Jetzt, da PostgreSQL 12 herausgekommen ist, betrachten wir Fremdschlüssel als vollständig kompatibel mit partitionierten Tabellen. Sie können eine partitionierte Tabelle auf beiden Seiten einer Fremdschlüsselbeschränkung haben, und alles wird korrekt funktionieren.

Warum weise ich darauf hin? Zwei Gründe:Erstens, als partitionierte Tabellen zum ersten Mal in PostgreSQL 10 eingeführt wurden, unterstützten sie überhaupt keine Fremdschlüssel; Sie konnten keine FKs für partitionierte Tabellen erstellen oder FKs erstellen, die auf eine partitionierte Tabelle verweisen. Zweitens, weil die (frühe) Tabellenvererbungsfunktion auch Fremdschlüssel nicht wirklich unterstützte. All dies bedeutet, dass es zum ersten Mal in PostgreSQL möglich ist, große Datenmengen unter Beibehaltung der referenziellen Integrität zu verwalten. Jetzt, da diese Funktion vollständig ist, stehen PostgreSQL einige neue Anwendungsfälle offen, die es zuvor nicht gab.

Hier ist ein ziemlich triviales Beispiel.

CREATE TABLE items (
    item_id integer PRIMARY KEY,
    description text NOT NULL
) PARTITION BY hash (item_id);
CREATE TABLE items_0 PARTITION OF items FOR VALUES WITH (modulus 3, remainder 0);
CREATE TABLE items_1 PARTITION OF items FOR VALUES WITH (modulus 3, remainder 1);
CREATE TABLE items_2 PARTITION OF items FOR VALUES WITH (modulus 3, remainder 2);

CREATE TABLE warehouses (warehouse_id integer primary key, location text not null);

CREATE TABLE stock (
    item_id integer not null REFERENCES items,
    warehouse_id integer not null REFERENCES warehouses,
    amount int not null
) partition by hash (warehouse_id);
CREATE TABLE stock_0 PARTITION OF stock FOR VALUES WITH (modulus 5, remainder 0);
CREATE TABLE stock_1 PARTITION OF stock FOR VALUES WITH (modulus 5, remainder 1);
CREATE TABLE stock_2 PARTITION OF stock FOR VALUES WITH (modulus 5, remainder 2);
CREATE TABLE stock_3 PARTITION OF stock FOR VALUES WITH (modulus 5, remainder 3);
CREATE TABLE stock_4 PARTITION OF stock FOR VALUES WITH (modulus 5, remainder 4);

Sie können sehen, dass es hier zwei Fremdschlüssel gibt. Man zeigt auf eine reguläre (nicht partitionierte) Tabelle warehouses , der andere zeigt auf partitionierte Tabellen items . Ist Ihnen aufgefallen, dass jeder Fremdschlüssel nur einmal deklariert wird?

Es gibt zwei grundlegende Operationen, die der Fremdschlüssel bereitstellen soll. Erstens, wenn Sie eine Zeile in Bestand einfügen (die Referenzierung Tabelle), die keine entsprechende Zeile in items hat oder Lager (die referenzierte Tabelle), muss ein Fehler ausgelöst werden. Zweitens, wenn Sie eine Zeile in einer der referenzierten Tabellen löschen und es übereinstimmende Zeilen im Bestand gibt , muss dieser Vorgang ebenfalls abgelehnt werden.

Beides lässt sich leicht überprüfen:

INSERT INTO stock values (1, 1, 10);
ERROR:  insert or update on table "stock_0" violates foreign key constraint "stock_item_id_fkey"
DETAIL:  Key (item_id)=(1) is not present in table "items".

Gut. Dann können Sie übereinstimmende Zeilen in beide referenzierten Tabellen und eine referenzierende Zeile einfügen. Danach schlägt ein Löschvorgang in einer der referenzierten Tabellen erwartungsgemäß fehl.

INSERT INTO items VALUES (1, 'item 1');
INSERT INTO warehouses VALUES (1, 'The moon');
INSERT INTO stock VALUES (1, 1, 10);

DELETE FROM warehouses;
ERROR:  update or delete on table "warehouses" violates foreign key constraint "stock_warehouse_id_fkey" on table "stock"
DETAIL:  Key (warehouse_id)=(1) is still referenced from table "stock".

DELETE FROM items;
ERROR:  update or delete on table "items_2" violates foreign key constraint "stock_item_id_fkey3" on table "stock"
DETAIL:  Key (item_id)=(1) is still referenced from table "stock".

(Natürlich ein UPDATE Operation ist für die erste Operation dasselbe wie ein INSERT , und für letztere Operation dasselbe wie ein DELETE — was bedeutet, dass sowohl das ursprüngliche Tupel als auch das modifizierte Tupel überprüft werden müssen, wenn das UPDATE modifiziert die am Fremdschlüssel beteiligten Spalten.)

Wenn diese Beispiele erfahrenen Benutzern langweilig erscheinen, liegt das daran, dass diese Dinge für reguläre (nicht partitionierte) Tabellen seit jeher genau gleich funktionieren.

In der realen Verwendung würden Sie Indizes in den referenzierenden Spalten in der Aktie benötigen Tabelle, wenn Sie jemals die referenzierten Tabellen ändern. Dies liegt daran, dass der Server diese referenzierenden Zeilen finden muss, um zu wissen, ob er einen Fehler oder ähnliches auslöst. Das geht ganz einfach mit der partitionierten Referenztabelle:

CREATE INDEX ON stock (item_id);
CREATE INDEX ON stock (warehouse_id);

In diesem Beitrag habe ich die Grundlagen von Fremdschlüsseln gezeigt und wie sie auf partitionierten Tabellen genauso wie auf regulären Tabellen verwendet werden können. In einem späteren Beitrag werde ich einige zusätzliche Funktionen davon behandeln. Lassen Sie mich in einem Kommentar wissen, ob Ihnen diese PostgreSQL 12-Verbesserung gefällt!