Ahora que salió PostgreSQL 12, consideramos que las claves foráneas son totalmente compatibles con las tablas particionadas. Puede tener una tabla particionada a ambos lados de una restricción de clave externa y todo funcionará correctamente.
¿Por qué señalo esto? Dos razones:primero, cuando las tablas particionadas se introdujeron por primera vez en PostgreSQL 10, no admitían claves foráneas en absoluto; no podía crear FK en tablas particionadas, ni crear FK que hicieran referencia a una tabla particionada. En segundo lugar, porque la función de herencia de tablas (en los primeros días) tampoco admitía claves foráneas. Todo esto significa que por primera vez es posible en PostgreSQL mantener grandes volúmenes de datos manteniendo la integridad referencial. Ahora que esta característica está completa, algunos nuevos casos de uso están abiertos a PostgreSQL que antes no lo estaban.
Aquí hay un ejemplo bastante 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);
Puede ver que hay dos claves foráneas aquí. Uno apunta a una tabla regular (no dividida) almacenes , el otro apunta a la tabla particionada items . ¿Te diste cuenta de que cada clave externa solo se declara una vez?
Hay dos operaciones básicas que desea que proporcione la clave externa. Primero, si inserta una fila en stock (la referencia tabla) que no tiene una fila correspondiente en elementos o almacenes (el referenciado tabla), se debe generar un error. En segundo lugar, si elimina una fila en cualquiera de las tablas a las que se hace referencia y hay filas coincidentes en stock , esa operación también debe ser rechazada.
Ambos se verifican fácilmente:
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".
Bien. Luego puede insertar filas coincidentes tanto en las tablas a las que se hace referencia como en una fila de referencia. Después de eso, una eliminación en cualquiera de las tablas a las que se hace referencia fallará, como se esperaba.
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".
(Por supuesto, una ACTUALIZACIÓN operación es para la operación anterior lo mismo que INSERT , y para la última operación lo mismo que un DELETE — lo que significa que deben verificarse tanto la tupla original como la tupla modificada, si la ACTUALIZAR modifica las columnas involucradas en la clave foránea.)
Si estos ejemplos parecen aburridos para los usuarios experimentados, es porque estas cosas funcionan exactamente igual para tablas normales (no particionadas) desde tiempos inmemoriales.
En el uso real, necesitaría índices en las columnas de referencia en el stock tabla, si alguna vez modifica las tablas a las que se hace referencia. Esto se debe a que el servidor necesita ubicar esas filas de referencia para saber si arroja un error o algo así. Puede hacerlo con la tabla de referencias particionada con bastante facilidad:
CREATE INDEX ON stock (item_id); CREATE INDEX ON stock (warehouse_id);
En esta publicación, he mostrado los conceptos básicos de las claves externas y cómo se pueden usar en tablas particionadas al igual que en tablas normales. En una publicación posterior, cubriré un par de características adicionales de esos. ¡Déjame saber en un comentario si te gusta esta mejora de PostgreSQL 12!