BEZ ODROCZENIA W porównaniu z ODROCZONYM WSTĘPNIE NATYCHMIAST

92

Czytałem to o słowie kluczowym SQL DEFERRABLEw Database Systems - The Complete Book .

To ostatnie [NOT DEFERRABLE] jest wartością domyślną i oznacza, że ​​za każdym razem, gdy wykonywana jest instrukcja modyfikacji bazy danych, ograniczenie jest sprawdzane natychmiast po tym, jeśli modyfikacja mogłaby naruszyć ograniczenie klucza obcego.

Jeśli jednak zadeklarujemy ograniczenie jako ODROCZONE , przed sprawdzeniem ograniczenia mamy możliwość, aby czekało do zakończenia transakcji.

Podążamy za słowem kluczowym ODROCZONE przez POCZĄTKOWO ODROCZONE lub POCZĄTKOWO NATYCHMIASTOWE . W pierwszym przypadku sprawdzanie zostanie odroczone tuż przed zatwierdzeniem każdej transakcji. W tym drugim przypadku czek będzie dokonywany natychmiast po każdym wyciągu.

Czym się NOT DEFERRABLEróżni od DEFERRABLE INITIALLY IMMEDIATE? W obu przypadkach wydaje się, że wszelkie ograniczenia są sprawdzane po każdym indywidualnym oświadczeniu.

Pieter
źródło

Odpowiedzi:

74

Dzięki temu DEFERRABLE INITIALLY IMMEDIATEmożesz odroczyć ograniczenia na żądanie, kiedy tego potrzebujesz.

Jest to przydatne, jeśli normalnie chcesz sprawdzić ograniczenia w czasie instrukcji, ale np. W przypadku ładowania wsadowego chcesz odroczyć sprawdzanie do czasu zatwierdzenia.

Składnia, jak odłożyć ograniczenia, jest jednak różna dla różnych DBMS.

Dzięki NOT DEFERRABLEtemu nigdy, przenigdy nie będziesz w stanie odroczyć sprawdzania do czasu zatwierdzenia.

koń bez imienia
źródło
1
@romkyns: DEFERRABLEokreśla zamiar projektanta, że ​​odroczenie ograniczenia jest wartościowym lub koniecznym działaniem. Nie dotyczy to zdecydowanej większości ograniczeń baz danych i oznaczania wszystkiego, co DEFERRABLEspowodowałoby utratę tego przydatnego rozróżnienia.
kiedy
4
@onedaywhen Od tamtej pory mój kolega wskazał na dobry, ważny powód: możesz polegać na niemożliwych do odroczenia ograniczeniach w dowolnym momencie każdej transakcji, ale te, które można odroczyć, są widoczne tylko na początku transakcji.
Roman Starkov
@RomanStarkov Również jest to kwestia wydajności. NOT DEFERRABLEjest zwykle najszybszy.
Teejay,
49

Oprócz innych (poprawnych) odpowiedzi, mówiąc o PostgreSQL należy stwierdzić, że:

  • z NIE ODROCZONY każdy wiersz jest sprawdzany w czasie wstawiania / aktualizacji

  • z ODROCZONYM (obecnie NATYCHMIAST ) wszystkie wiersze są sprawdzane na końcu wstawiania / aktualizacji

  • z ODROCZONYM (obecnie ODROCZONYM ) wszystkie wiersze są sprawdzane na koniec transakcji

Zatem nie jest poprawne stwierdzenie, że ograniczenie ODROCZALNE działa jak NIE ODROCZONE, gdy jest ustawione na NATYCHMIAST.


Opiszmy tę różnicę:

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;

To poprawnie wyświetla:

wynik

Ale jeśli usuniemy instrukcję ODROCZENIE INICJALNIE NATYCHMIAST,

BŁĄD: zduplikowana wartość klucza narusza unikalne ograniczenie „example_row_col_key” DETAIL: Key („row”, col) = (2, 2) już istnieje. ********** Błąd **********

BŁĄD: zduplikowana wartość klucza narusza ograniczenie unikalności "example_row_col_key" Stan SQL: 23505 Szczegóły: Klucz ("wiersz", kolumna) = (2, 2) już istnieje.


ADDENDUM (12 października 2017)

Takie zachowanie jest rzeczywiście udokumentowane tutaj , w sekcji „Zgodność”:

Ponadto PostgreSQL sprawdza natychmiastowo nieodwracalne ograniczenia unikalności, a nie na końcu instrukcji, jak sugerowałby standard.

Teejay
źródło
Ciekawy. Wydaje mi się, że w zasadzie nie ma powodu, aby preferować zachowanie „NIE ODROCZONY” od zachowania „NATYCHMIASTOWEGO” i że Postgres powinien być bardziej wyrozumiały i sprawić, że NIE ODRODZI SIĘ zachowywać się jak „NATYCHMIAST”. Kolejność, w jakiej wiersze są aktualizowane w instrukcji UPDATE, nie jest nawet udokumentowana ani określona, ​​o ile wiem, więc czy zachowanie tego sprawdzania ograniczeń instrukcji w połowie nie jest przynajmniej częściowo nieokreślone? Nie rozumiem, dlaczego ktokolwiek miałby chcieć takiego zachowania - ale być może istnieje uzasadniony przypadek użycia, którego brakuje mi wyobraźni.
Mark Amery,
1
Tak, w zasadzie jedynym powodem preferowania NOT DEFERRABLEjest szybkość ( patrz tutaj , sekcja Nieodroczone ograniczenia niepowtarzalności , „Należy pamiętać, że może to być znacznie wolniejsze niż natychmiastowe sprawdzanie niepowtarzalności” ).
Teejay
Ponadto do DEFERRABLEograniczenia nie można się odwoływać jako do kluczy obcych w innych tabelach ( patrz tutaj , sekcja Parametry , „Kolumny, do których istnieją odwołania, muszą być kolumnami niemożliwego do odroczenia ograniczenia unikalnego lub klucza podstawowego w tabeli, do której się odwołuje” ).
Teejay
1
Z zasady, jeśli tak naprawdę nie ma znaczenia dla logiki biznesowej, kiedy ograniczenie jest sprawdzane, to czy powinienem domyślnie używać go NOT DEFERRABLEpo prostu dlatego, że działa lepiej?
dvtan
1
W naszym ORM używamy teraz następujących reguł: 1) jeśli ograniczenie jest PK, używamy NOT DEFERRABLE2) jeśli co najmniej jeden FK odwołuje się do ograniczenia, używamy NOT DEFERRABLErównież 3) w pozostałych przypadkach używamy DEFERRABLE INITIALLY IMMEDIATE. Może to nieznacznie zmniejszyć wydajność tych ograniczeń, ale zapewnia maksymalną zgodność z innymi używanymi przez nas DBMS (Oracle, SqlServer). PK i FK nie stanowią problemu, ponieważ nigdy nie aktualizujemy ich wartości (co moim zdaniem jest dobrym nawykiem programistycznym dla DB).
Teejay
29

Oprócz oczywistej możliwości odroczenia, różnica polega w rzeczywistości na wydajności. Gdyby nie było spadku wydajności, nie byłoby potrzeby wyboru opcji odroczenia lub nie - wszystkie ograniczenia byłyby po prostu odroczone.

Obniżenie wydajności wiąże się z optymalizacjami, które baza danych może wykonać, wiedząc, jak ograniczone są dane. Na przykład indeks utworzony w celu poparcia unikalnego ograniczenia w Oracle nie może być indeksem unikatowym, jeśli ograniczenie jest możliwe do odroczenia, ponieważ tymczasowe zezwolenie na duplikaty musi być dozwolone. Jeśli jednak ograniczenie nie jest możliwe do odroczenia, indeks może być unikalny.

Ryan
źródło
7

Jestem bardzo spóźniony na imprezę, ale dodam, że - od grudnia 2018 r. - tylko dwie znane mi bazy danych (może być ich więcej) oferują pewien poziom implementacji tej standardowej funkcjonalności SQL :

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 Mimo że Oracle 12c akceptuje NOT DEFERRABLE stan ograniczenia , w rzeczywistości go ignoruje i sprawia, że ​​działa tak, jak DEFERRABLE INITIALLY IMMEDIATE.

Jak widać, Oracle nie implementuje pierwszego typu ( NOT DEFERRABLE), dlatego programiści używający Oracle (w tym przypadku OP) mogą się pomylić i uznać pierwsze dwa typy za równoważne.

Co ciekawe, Oracle i PostgreSQL mają inny domyślny typ. Może ma to wpływ na wydajność.

Palownik
źródło
4

NOT DEFERRABLE - nie możesz zmienić sprawdzania ograniczeń, oracle sprawdza je po każdej instrukcji (tj. Bezpośrednio po instrukcji insert).

ODROCZENIE INICJALNIE NATYCHMIAST - oracle sprawdza ograniczenie po każdej instrukcji. ALE możesz to zmienić na po każdej transakcji (tj. Po zatwierdzeniu):

set constraint pk_tab1 deferred;
hajili
źródło