NON DIFFERIBILE contro DIFFERIBILE INIZIALMENTE IMMEDIATO


90

Ho letto questo sulla parola chiave SQL DEFERRABLEin Database Systems - The Complete Book .

Quest'ultimo [NOT DEFERRABLE] è predefinito e significa che ogni volta che viene eseguita un'istruzione di modifica del database, il vincolo viene verificato immediatamente dopo, se la modifica potrebbe violare il vincolo della chiave esterna.

Tuttavia, se dichiariamo che un vincolo è DEFERRABILE , abbiamo la possibilità di farlo aspettare fino al completamento di una transazione prima di verificare il vincolo.

Seguiamo la parola chiave DIFFERIBILE con INIZIALMENTE DIFFERITO o INIZIALMENTE IMMEDIATO . Nel primo caso, il controllo verrà posticipato appena prima del commit di ogni transazione. In quest'ultimo caso, il controllo verrà effettuato immediatamente dopo ogni dichiarazione.

In che modo è NOT DEFERRABLEdiverso da DEFERRABLE INITIALLY IMMEDIATE? In entrambi i casi, a quanto pare, eventuali vincoli vengono controllati dopo ogni singola istruzione.

Risposte:


72

Con DEFERRABLE INITIALLY IMMEDIATEpuoi differire i vincoli su richiesta quando ne hai bisogno.

Ciò è utile se normalmente si desidera controllare i vincoli al momento dell'istruzione, ma ad esempio un caricamento batch desidera posticipare il controllo fino al momento del commit.

La sintassi su come differire i vincoli è tuttavia diversa per i vari DBMS.

Con NOT DEFERRABLEnon sarai mai in grado di differire il controllo fino al momento del commit.


1
@romkyns: DEFERRABLEafferma l'intenzione del progettista che rinviare il vincolo sia un'azione utile o necessaria. Questo non è il caso per la stragrande maggioranza dei vincoli del database e l'etichettatura di tutto in quanto DEFERRABLEperderebbe questa utile distinzione.
giorno del

4
@onedaywhen Da allora un mio collega ha indicato una buona ragione valida, in realtà: puoi fare affidamento su vincoli non differibili in qualsiasi punto di qualsiasi transazione, ma quelli differibili vengono osservati definitivamente solo all'inizio di una transazione.
Roman Starkov

@RomanStarkov Inoltre, è una questione di prestazioni. NOT DEFERRABLEdi solito è il più veloce.
Teejay

46

A parte le altre risposte (corrette), quando si parla di PostgreSQL , bisogna affermare che:

  • con NOT DEFERRABLE ogni riga viene verificata al momento dell'inserimento / aggiornamento

  • con DEFERRABLE (attualmente IMMEDIATE ) tutte le righe vengono verificate alla fine dell'inserimento / aggiornamento

  • con DEFERRABLE (attualmente DEFERRED ) tutte le righe sono controllati al termine dell'operazione

Quindi non è corretto affermare che un vincolo DEFERRABLE si comporta come un NON DEFERRABLE quando è impostato su IMMEDIATE.


Elaboriamo questa differenza:

CREATE TABLE example(
    row integer NOT NULL,
    col integer NOT NULL,
    UNIQUE (row, col) DEFERRABLE INITIALLY IMMEDIATE
);

INSERT INTO example (row, col) VALUES (1,1),(2,2),(3,3);

UPDATE example SET row = row + 1, col = col + 1;

SELECT * FROM example;

Questo restituisce correttamente:

produzione

Ma se rimuoviamo l'istruzione DIFFERIBILE INIZIALMENTE IMMEDIATO,

ERRORE: il valore della chiave duplicato viola il vincolo univoco "example_row_col_key" DETTAGLIO: Key ("row", col) = (2, 2) esiste già. ********** Errore **********

ERRORE: il valore della chiave duplicato viola il vincolo univoco "example_row_col_key" Stato SQL: 23505 Dettaglio: Key ("row", col) = (2, 2) già esistente.


ADDENDUM (12 ottobre 2017)

Questo comportamento è effettivamente documentato qui , sezione "Compatibilità":

Inoltre, PostgreSQL verifica i vincoli di unicità non differibili immediatamente, non alla fine dell'istruzione come suggerirebbe lo standard.


Interessante. Mi sembra che non ci sia fondamentalmente alcun motivo per preferire il comportamento "NON DIFFERIBILE" al comportamento "IMMEDIATO" e che avrebbe senso per Postgres essere più indulgente e fare in modo che NON DIFFERIBILE si comporti come "IMMEDIATO". L'ordine in cui le righe vengono aggiornate in un'istruzione UPDATE non è nemmeno documentato o specificato per quanto ne so, quindi il comportamento di questo controllo dei vincoli a metà istruzione non è almeno parzialmente non specificato? Non riesco a capire perché qualcuno vorrebbe quel comportamento, ma forse c'è un caso d'uso ragionevole per questo che mi manca l'immaginazione di vedere.
Mark Amery

1
Sì, fondamentalmente l'unico motivo per preferire NOT DEFERRABLEè la velocità ( vedere qui , sezione Vincoli di unicità non differiti , "Tieni presente che questo può essere significativamente più lento del controllo di unicità immediato" ).
Teejay

Inoltre, DEFERRABLEnon è possibile fare riferimento al vincolo come chiavi esterne in altre tabelle ( vedere qui , sezione Parametri , "Le colonne a cui si fa riferimento devono essere le colonne di un vincolo di chiave univoca o primaria non differibile nella tabella di riferimento" ).
Teejay

1
Quindi, come regola generale, se non è davvero importante per la logica di business quando il vincolo viene controllato, allora dovrei usarlo per impostazione predefinita NOT DEFERRABLEsemplicemente perché funziona meglio?
dvtan

1
Nel nostro ORM ora usiamo le seguenti regole: 1) se il vincolo è un PK, usiamo NOT DEFERRABLE2) se almeno un FK fa riferimento al vincolo, usiamo NOT DEFERRABLEanche 3) negli altri casi, usiamo DEFERRABLE INITIALLY IMMEDIATE. Ciò potrebbe diminuire leggermente le prestazioni di tali vincoli, ma garantisce la massima compatibilità con altri DBMS che utilizziamo (Oracle, SqlServer). PK e FK non sono un problema perché non aggiorniamo mai i loro valori (che penso sia una buona abitudine di programmazione per i DB).
Teejay

29

A parte l'ovvio di poter differire, la differenza è in realtà la prestazione. Se non ci fosse una penalità sulle prestazioni, non sarebbe necessario avere un'opzione per scegliere differibile o meno: tutti i vincoli sarebbero semplicemente differibili.

La penalizzazione delle prestazioni ha a che fare con le ottimizzazioni che il database può eseguire data la conoscenza di come i dati sono limitati. Ad esempio, l'indice creato per supportare un vincolo univoco in Oracle non può essere un indice univoco se il vincolo è rinviabile poiché è necessario consentire temporaneamente i duplicati. Tuttavia, se il vincolo non è rinviabile, l'indice può essere univoco.


7

Sono molto in ritardo per la festa ma volevo aggiungere che, a partire da dicembre 2018, solo due database di cui sono a conoscenza (potrebbero essercene di più) offrono un certo livello di implementazione di questa funzionalità SQL standard :

Database    NOT DEFERRABLE  DEFERRABLE           DEFERRABLE 
                            INITIALLY IMMEDIATE  INITIALLY DEFERRED
----------  --------------  -------------------  ------------------
Oracle      N/A *1          Yes (default)        Yes
PostgreSQL  Yes (default)   Yes                  Yes
DB2         -               -                    -
SQL Server  -               -                    -
MySQL       -               -                    -
MariaDB     -               -                    -
SAP Sybase  -               -                    -
HyperSQL    -               -                    -
H2          -               -                    -
Derby       -               -                    -

* 1 Anche se Oracle 12c accetta lo NOT DEFERRABLE stato del vincolo , in realtà lo ignora e lo fa funzionare come DEFERRABLE INITIALLY IMMEDIATE.

Come vedi, Oracle non implementa il primo tipo ( NOT DEFERRABLE), ed è per questo che gli sviluppatori che utilizzano Oracle (l'OP in questo caso) potrebbero confondersi e considerare i primi due tipi equivalenti.

È interessante notare che Oracle e PostgreSQL hanno un tipo predefinito diverso. Forse ha implicazioni sulle prestazioni.


4

NON DIFFERIBILE - non è possibile modificare il controllo dei vincoli, Oracle lo controlla dopo ogni istruzione (cioè direttamente dopo l'istruzione insert).

DIFFERIBILE INIZIALMENTE IMMEDIATO - Oracle controlla il vincolo dopo ogni istruzione. MA, puoi cambiarlo in dopo ogni transazione (cioè dopo il commit):

set constraint pk_tab1 deferred;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.