2011-03-14 10 views
53

He leído esto sobre la palabra clave SQL DEFERRABLE en Sistemas de bases de datos - El libro completo.NO DEFERRABLE versus DEFERRABLE INICIALMENTE INMEDIATO

The latter [NOT DEFERRABLE] is default, and means that every time a database modification statement is executed, the constraint is checked immediately afterwards, if the modification could violate the foreign-key constraint.

However, if we declare a constraint to be DEFERRABLE, then we have the option of having it wait until a transaction is complete before checking the constraint.

We follow the keyword DEFERRABLE by either INITIALLY DEFERRED or INITIALLY IMMEDIATE. In the former case, checking will be deferred to just before each transaction commits. In the latter case, the check will be made immediately after each statement.

¿Cómo es diferente de NOT DEFERRABLEDEFERRABLE INITIALLY IMMEDIATE? En ambos casos, parece que cualquier restricción se verifica después de cada declaración individual.

Respuesta

44

Con DEFERRABLE INITIALLY IMMEDIATE puede aplazar las restricciones a pedido cuando lo necesite.

Esto es útil si normalmente desea verificar las restricciones en el momento de la declaración, pero por ejemplo, una carga por lotes desea aplazar la verificación hasta el momento de la confirmación.

La sintaxis de cómo diferir las restricciones es diferente para los diversos DBMS.

Con NOT DEFERRABLE nunca podrá postergar la verificación hasta el momento de la confirmación.

+0

Debo señalar que aún estoy para ver una buen uso para 'NOT DEFERRABLE'. Todo lo que hace es causar problemas. Recomiendo usar 'DEFERRABLE INICIALMENTE INMEDIATO' de forma predeterminada. –

+1

@romkyns: 'DEFERRABLE' indica la intención del diseñador de diferir la restricción es una acción que vale la pena o es necesaria. Este no es el caso para la gran mayoría de las restricciones de base de datos y el etiquetado como 'DEFERRABLE 'perdería esta útil distinción. – onedaywhen

+3

@onedaywhen Un colega mío ha señalado desde entonces una buena razón válida, en realidad: puede confiar en restricciones no diferibles en cualquier punto de cualquier transacción, pero las diferibles solo se observan definitivamente al comienzo de una transacción. –

22

Aparte de lo obvio de poder posponer, la diferencia es en realidad el rendimiento. Si no hubiera una penalización por desempeño, entonces no habría necesidad de tener una opción para elegir diferible o no, todas las restricciones serían simplemente diferibles.

La penalización del rendimiento tiene que ver con las optimizaciones que la base de datos puede realizar dado el conocimiento de cómo se restringen los datos. Por ejemplo, el índice que se crea para respaldar una restricción única en Oracle no puede ser un índice único si la restricción es diferible, ya que se deben permitir temporalmente los duplicados. Sin embargo, si la restricción no es diferible, entonces el índice puede ser único.

2

NO DEFERIDA: no puede cambiar la comprobación de restricciones, Oracle la verifica después de cada instrucción (es decir, directamente después de insertar la instrucción).

DEFERRABLE INMEDIATAMENTE INMEDIATO: Oracle verifica la restricción después de cada instrucción. Pero, se puede cambiar a después de cada transacción (es decir, después de comprometerse):

set constraint pk_tab1 deferred; 
11

Aparte de las otras respuestas (correctas), es preciso señalar que:

  • con NO DEFERRABLE cada fila se comprueba en el momento de inserción/actualización

  • con DEFERRABLE (actualmente INMEDIATA) todas las filas son c hecked al final de la inserción/actualización

  • con DEFERRABLE (actualmente DIFERIDO) todas las filas se comprueban al final de la transacción

Así no es correcta decir que una restricción DEFERRABLE actúa como una NO DEF ERRABLE cuando está configurada como INMEDIATA.


Vamos a explicar en detalle esta diferencia:

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; 

Esto da salida correcta:

output

Pero si quitamos la instrucción INICIALMENTE INMEDIATA DEFERRABLE,

ERROR: duplicate key value violates unique constraint "example_row_col_key" DETAIL: Key ("row", col)=(2, 2) already exists. ********** Error **********

ERROR: duplicate key value violates unique constraint "example_row_col_key" SQL state: 23505 Detail: Key ("row", col)=(2, 2) already exists.


ADENDA(12 de octubre, 2017)

Este comportamiento es, en efecto documentado here, sección "Compatibilidad":

Also, PostgreSQL checks non-deferrable uniqueness constraints immediately, not at end of statement as the standard would suggest.

+0

Interesante. Me parece que básicamente no hay ninguna razón para preferir el comportamiento "NO DEFERSABLE" al comportamiento "INMEDIATO" y que tendría sentido que Postgres fuera más indulgente y que el comportamiento NO DEFERRABLE se comportara como "INMEDIATO". El orden en que las filas se actualizan en una instrucción UPDATE ni siquiera está documentado o especificado, por lo que yo sé, así que, ¿no es el comportamiento de esta comprobación de restricción de declaraciones intermedias al menos parcialmente no especificado? No puedo entender por qué * alguien * querría ese comportamiento, pero tal vez haya un caso de uso razonable que me falte imaginación para ver. –

+0

Sí, básicamente la única razón para preferir 'NOT DEFERRABLE' es la velocidad ([consulte aquí] (https://www.postgresql.org/docs/current/static/sql-createtable.html), sección ** No diferido Restricciones de unicidad **, * "Tenga en cuenta que esto puede ser significativamente más lento que la comprobación de exclusividad inmediata" *). – Teejay

+0

Además, la restricción 'DEFERRABLE' no se puede hacer referencia como claves externas en otras tablas ([consulte aquí] (https://www.postgresql.org/docs/current/static/sql-createtable.html), sección ** Parámetros * *, * "Las columnas a las que se hace referencia deben ser las columnas de una restricción de clave primaria única o no diferida en la tabla a la que se hace referencia" *). – Teejay

Cuestiones relacionadas