PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

PostgreSQL 12:chiavi esterne e tabelle partizionate

Ora che PostgreSQL 12 è uscito, consideriamo le chiavi esterne completamente compatibili con le tabelle partizionate. Puoi avere una tabella partizionata su entrambi i lati di un vincolo di chiave esterna e tutto funzionerà correttamente.

Perché lo faccio notare? Due ragioni:in primo luogo, quando le tabelle partizionate sono state introdotte per la prima volta in PostgreSQL 10, non supportavano affatto le chiavi esterne; non è possibile creare FK su tabelle partizionate, né creare FK che fanno riferimento a una tabella partizionata. In secondo luogo, perché la funzione di ereditarietà delle tabelle (primi giorni) non supportava nemmeno le chiavi esterne. Tutto ciò significa che per la prima volta è possibile in PostgreSQL mantenere grandi volumi di dati mantenendo l'integrità referenziale. Ora che questa funzionalità è completa, in PostgreSQL sono aperti alcuni nuovi casi d'uso che in precedenza non lo erano.

Ecco un esempio piuttosto banale.

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

Puoi vedere che ci sono due chiavi esterne qui. Uno punta a una tabella normale (non partizionata) magazzini , l'altro punta agli elementi della tabella partizionata . Hai notato che ogni chiave esterna viene dichiarata una sola volta?

Ci sono due operazioni di base che vuoi che la chiave esterna fornisca. Innanzitutto, se inserisci una riga in stock (il riferimento tabella) che non ha una riga corrispondente in ites o magazzini (il riferito tabella), deve essere generato un errore. In secondo luogo, se elimini una riga in una delle tabelle di riferimento e ci sono righe corrispondenti in stock , anche quell'operazione deve essere rifiutata.

Entrambi sono facilmente verificabili:

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

Bene. Quindi puoi inserire righe corrispondenti sia nelle tabelle referenziate che in una riga referenziata. Dopodiché, un'eliminazione in una delle tabelle di riferimento avrà esito negativo, come previsto.

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

(Ovviamente, un AGGIORNAMENTO l'operazione è per la precedente operazione la stessa di un INSERT , e per quest'ultima operazione lo stesso di un DELETE — il che significa che sia la tupla originale che la tupla modificata devono essere verificate, se UPDATE modifica le colonne coinvolte nella chiave esterna.)

Se questi esempi sembrano zoppi agli utenti esperti, è perché queste cose funzionano esattamente allo stesso modo per le tabelle normali (non partizionate) da tempo immemorabile.

Nell'uso reale, avresti bisogno di indici nelle colonne di riferimento nel stock tabella, se si modificano le tabelle di riferimento. Questo perché il server deve individuare quelle righe di riferimento per sapere se generare un errore o qualcosa del genere. Puoi farlo con la tabella di riferimento partizionata abbastanza facilmente:

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

In questo post ho mostrato le basi delle chiavi esterne e come possono essere utilizzate su tabelle partizionate proprio come nelle tabelle normali. In un post successivo tratterò un paio di funzionalità aggiuntive di quelli. Fammi sapere in un commento se ti piace questo miglioramento di PostgreSQL 12!