NÃO DEFERRÁVEL versus DEFERRÁVEL INICIALMENTE IMEDIATO


90

Eu li sobre a palavra-chave SQL DEFERRABLEem Database Systems - The Complete Book .

O último [NOT DEFERRABLE] é o padrão e significa que toda vez que uma instrução de modificação do banco de dados é executada, a restrição é verificada imediatamente depois, se a modificação puder violar a restrição de chave estrangeira.

No entanto, se declararmos uma restrição como DEFERRABLE , temos a opção de esperar até que uma transação seja concluída antes de verificar a restrição.

Seguimos a palavra-chave DEFERRABLE por INITIALLY DEFERRED ou INITIALLY IMMEDIATE . No primeiro caso, a verificação será adiada para pouco antes de cada confirmação de transação. Neste último caso, a verificação será feita imediatamente após cada declaração.

Como é NOT DEFERRABLEdiferente de DEFERRABLE INITIALLY IMMEDIATE? Em ambos os casos, ao que parece, todas as restrições são verificadas após cada declaração individual.

Respostas:


72

Com DEFERRABLE INITIALLY IMMEDIATEvocê pode adiar as restrições sob demanda quando precisar.

Isso é útil se você normalmente deseja verificar as restrições no momento da instrução, mas por exemplo, um carregamento em lote deseja adiar a verificação até o momento do commit.

A sintaxe de como adiar as restrições é diferente para os vários SGBDs.

Com NOT DEFERRABLEvocê, você nunca será capaz de adiar a verificação até a hora de confirmação.


1
@romkyns: DEFERRABLEdeclara a intenção do designer de que adiar a restrição é uma ação válida ou necessária. Este não é o caso para a grande maioria das restrições de banco de dados e rotulagem de todos, pois DEFERRABLEperderia essa distinção útil.
— dia em

4
@onedaywhen Desde então, um colega meu apontou um bom motivo válido, na verdade: você pode contar com restrições não diferíveis em qualquer ponto de qualquer transação, mas aquelas que podem ser diferidas só são definitivamente observadas no início de uma transação.
— Roman Starkov

@RomanStarkov Além disso, é uma questão de desempenho. NOT DEFERRABLEgeralmente é o mais rápido.
— Teejay

46

Além das outras respostas (corretas), quando se fala em PostgreSQL , deve-se afirmar que:

  • com NOT DEFERRABLE, cada linha é verificada no momento da inserção / atualização

  • com DEFERRABLE (atualmente IMMEDIATE ) todas as linhas são verificadas no final da inserção / atualização

  • com DEFERRABLE (atualmente DEFERRED ) todas as linhas são verificadas no final da transação

Portanto , não é correto dizer que uma restrição DEFERRABLE age como uma NOT DEFERRABLE quando definida como IMMEDIATE.


Vamos elaborar essa diferença:

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;

Isso resulta corretamente:

resultado

Mas se removermos a instrução DEFERRABLE INITIALLY IMMEDIATE,

ERRO: o valor da chave duplicado viola a restrição exclusiva "example_row_col_key" DETALHE: A chave ("linha", col) = (2, 2) já existe. ********** Erro **********

ERRO: o valor da chave duplicado viola a restrição exclusiva "example_row_col_key" Estado SQL: 23505 Detalhe: a chave ("linha", col) = (2, 2) já existe.


ADENDO (12 de outubro de 2017)

Este comportamento está realmente documentado aqui , seção "Compatibilidade":

Além disso, o PostgreSQL verifica as restrições de exclusividade não diferíveis imediatamente, não no final da instrução como o padrão sugere.


Interessante. Parece-me que basicamente não há razão para preferir o comportamento "NÃO DEFERRÁVEL" ao comportamento "IMEDIATO" e que faria sentido para o Postgres ser mais indulgente e fazer com que NÃO DEFERRÁVEL se comporte como "IMEDIATO". A ordem na qual as linhas são atualizadas em uma instrução UPDATE nem mesmo é documentada ou especificada, pelo que eu sei, então o comportamento dessa verificação de restrição no meio da instrução não é pelo menos parcialmente não especificado? Não consigo ver por que alguém iria querer esse comportamento - mas talvez haja um caso de uso razoável para ele que não tenho imaginação para ver.
— Mark Amery

1
Sim, basicamente a única razão para preferir NOT DEFERRABLEé a velocidade ( veja aqui , a seção Restrições de exclusividade não adiadas , "Esteja ciente de que isso pode ser significativamente mais lento do que a verificação de exclusividade imediata" ).
— Teejay

Além disso, a DEFERRABLErestrição não pode ser referenciada como chaves estrangeiras em outras tabelas ( veja aqui , seção Parâmetros , "As colunas referenciadas devem ser as colunas de uma restrição de chave primária ou única não diferível na tabela referenciada" ).
— Teejay

1
Portanto, como regra geral, se realmente não importa para a lógica de negócios quando a restrição é verificada, devo usar o padrão NOT DEFERRABLEsimplesmente porque tem um desempenho melhor?
— dvtan

1
Em nosso ORM agora usamos as seguintes regras: 1) se a restrição for PK, usamos NOT DEFERRABLE2) se pelo menos um FK referenciar a restrição, usamos NOT DEFERRABLEtambém 3) nos outros casos, usamos DEFERRABLE INITIALLY IMMEDIATE. Isso pode diminuir ligeiramente o desempenho dessas restrições, mas garante a compatibilidade máxima com outros DBMS que usamos (Oracle, SqlServer). PK e FK não são um problema porque nunca atualizamos seus valores (o que eu acho um bom hábito de programação para bancos de dados).
— Teejay

29

Além do óbvio de ser capaz de adiar, a diferença é realmente o desempenho. Se não houvesse uma penalidade de desempenho, não haveria necessidade de ter a opção de escolher diferível ou não - todas as restrições seriam simplesmente postergáveis.

A penalidade de desempenho tem a ver com otimizações que o banco de dados pode realizar dado o conhecimento de como os dados são restritos. Por exemplo, o índice criado para apoiar uma restrição exclusiva no Oracle não pode ser um índice exclusivo se a restrição for postergável, pois a permissão temporária de duplicatas deve ser permitida. No entanto, se a restrição não for postergável, o índice pode ser exclusivo.


7

Estou muito atrasado para a festa, mas gostaria de acrescentar que - em dezembro de 2018 - apenas dois bancos de dados que eu conheço (pode haver mais) oferecem algum nível de implementação desse recurso SQL padrão :

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 Embora o Oracle 12c aceite o NOT DEFERRABLE estado de restrição , ele realmente o ignora e o faz funcionar como DEFERRABLE INITIALLY IMMEDIATE.

Como você pode ver, o Oracle não implementa o primeiro tipo ( NOT DEFERRABLE) e é por isso que os desenvolvedores que usam o Oracle (o OP, neste caso) podem ficar confusos e considerar os primeiros dois tipos equivalentes.

Curiosamente, o Oracle e o PostgreSQL têm um tipo padrão diferente. Talvez tenha implicações de desempenho.


4

NOT DEFERRABLE - você não pode alterar a verificação de restrição, o oracle verifica após cada instrução (ou seja, diretamente após a instrução insert).

DEFERRABLE INITIALLY IMMEDIATE - o oracle verifica a restrição após cada instrução. MAS, você pode alterá-lo para após cada transação (ou seja, após o commit):

set constraint pk_tab1 deferred;
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.