PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

PostgreSQL 12 :clés étrangères et tables partitionnées

Maintenant que PostgreSQL 12 est sorti, nous considérons que les clés étrangères sont entièrement compatibles avec les tables partitionnées. Vous pouvez avoir une table partitionnée de chaque côté d'une contrainte de clé étrangère, et tout fonctionnera correctement.

Pourquoi est-ce que je le signale ? Deux raisons :premièrement, lorsque les tables partitionnées ont été introduites pour la première fois dans PostgreSQL 10, elles ne prenaient pas du tout en charge les clés étrangères; vous ne pouviez pas créer de FK sur des tables partitionnées, ni créer de FK faisant référence à une table partitionnée. Deuxièmement, parce que la fonction d'héritage de table (au début) ne supportait pas vraiment les clés étrangères non plus. Tout cela signifie que pour la première fois, il est possible dans PostgreSQL de maintenir de gros volumes de données tout en maintenant l'intégrité référentielle. Maintenant que cette fonctionnalité est terminée, de nouveaux cas d'utilisation sont ouverts à PostgreSQL qui ne l'étaient pas auparavant.

Voici un exemple assez trivial.

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);

Vous pouvez voir qu'il y a deux clés étrangères ici. On pointe vers une table régulière (non partitionnée) entrepôts , l'autre pointe vers la table partitionnée items . Avez-vous remarqué que chaque clé étrangère n'est déclarée qu'une seule fois ?

Il y a deux opérations de base que vous voulez que la clé étrangère fournisse. Tout d'abord, si vous insérez une ligne dans stock (le référencement table) qui n'a pas de ligne correspondante dans items ou entrepôts (le référencé table), une erreur doit être levée. Deuxièmement, si vous supprimez une ligne dans l'une des tables référencées et qu'il existe des lignes correspondantes dans stock , cette opération doit également être rejetée.

Les deux sont facilement vérifiables :

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".

Bon. Vous pouvez ensuite insérer des lignes correspondantes dans les tables référencées et une ligne de référence. Après cela, une suppression dans l'une des tables référencées échouera, comme prévu.

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".

(Bien sûr, une MISE À JOUR l'opération est pour l'ancienne opération la même chose qu'un INSERT , et pour cette dernière opération la même chose qu'un DELETE - ce qui signifie que le tuple d'origine et le tuple modifié doivent être vérifiés, si le UPDATE modifie les colonnes impliquées dans la clé étrangère.)

Si ces exemples semblent boiteux pour les utilisateurs expérimentés, c'est parce que ces choses fonctionnent exactement de la même manière pour les tables régulières (non partitionnées) depuis des temps immémoriaux.

En utilisation réelle, vous auriez besoin d'index dans les colonnes de référencement du stock table, si jamais vous modifiez les tables référencées. En effet, le serveur doit localiser ces lignes de référence afin de savoir émettre une erreur ou autre. Vous pouvez le faire assez facilement avec la table de référence partitionnée :

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

Dans cet article, j'ai montré les bases des clés étrangères et comment elles peuvent être utilisées sur des tables partitionnées comme elles le peuvent sur des tables normales. Dans un article ultérieur, je couvrirai quelques fonctionnalités supplémentaires de ceux-ci. Faites-moi savoir dans un commentaire si vous aimez cette amélioration de PostgreSQL 12 !