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

Il vincolo definito DIFFERIBILE INIZIAMENTE IMMEDIATO è ancora RINVIATO?

Ricordo di aver sollevato un punto quasi identico quando PG9 era in stato alfa. Ecco la risposta di Tom Lane (sviluppatore principale PG di alto profilo):
http://archives.postgresql.org/pgsql-general/2010-01/msg00221.php

In breve:non si risolve.

Per non dire che sono d'accordo con il tuo suggerimento che il comportamento attuale è un bug. Guardalo dall'angolo opposto:è il comportamento di NOT DEFERRABLE non è corretto.

Infatti la violazione del vincolo in questo UPDATE non dovrebbe mai verificarsi in ogni caso, poiché al termine dell'UPDATE il vincolo è soddisfatto. Lo stato alla fine del comando è ciò che conta. Gli stati intermedi durante l'esecuzione di una singola istruzione non dovrebbero essere esposti all'utente.

Sembra che PostgreSQL implementi il ​​vincolo non differibile controllando i duplicati dopo ogni riga aggiornata e fallendo immediatamente al primo duplicato, il che è essenzialmente difettoso. Ma questo è un problema noto, probabilmente vecchio quanto PostgreSQL. Al giorno d'oggi la soluzione alternativa è proprio usare un vincolo DEFERRABLE. E c'è un po' di ironia nel fatto che lo consideri carente perché non riesce a fallire, mentre in qualche modo dovrebbe essere la soluzione al fallimento in primo luogo!

Riepilogo dello status quo da PostgreSQL 9.1

  • NOT DEFERRABLE UNIQUE o PRIMARY KEY i vincoli vengono controllati dopo ogni riga .

  • DEFERRABLE vincoli impostati su IMMEDIATE (INITIALLY IMMEDIATE o tramite SET CONSTRAINTS ) vengono controllati dopo ogni affermazione .

  • DEFERRABLE vincoli impostati su DEFERRED (INITIALLY DEFERRED o tramite SET CONSTRAINTS ) vengono controllati dopo ogni transazione .

Nota il trattamento speciale di UNIQUE / PRIMARY KEY vincoli. Citando la pagina di manuale per CREATE TABLE :

Un vincolo non differibile verrà verificato immediatamente dopo ogni comando .

Mentre viene indicato più in basso nella Compatibilità sezione in Non-deferred uniqueness constraints :

Quando un UNIQUE o PRIMARY KEY il vincolo non è differibile, PostgreSQL verifica immediatamente l'unicità ogni volta che una riga viene inserita o modificata. Lo standard SQL dice che l'unicità dovrebbe essere forzata solo alla fine dell'istruzione; questo fa la differenza quando, ad esempio, un singolo comando aggiorna più valori chiave. Per ottenere un comportamento conforme allo standard, dichiara il vincolo come DEFERRABLE ma non differito (cioè, INITIALLY IMMEDIATE ). Tieni presente che questo può essere significativamente più lento del controllo immediato dell'unicità.

Enfasi in grassetto la mia.

Se hai bisogno di qualsiasi FOREIGN KEY vincoli per fare riferimento alle colonne, DEFERRABLE non è un'opzione perché (per documentazione):

Le colonne di riferimento devono essere le colonne di un vincolo di chiave primaria o univoca non differibile nella tabella di riferimento.