НЕ ПОШИРЕНИЙ у порівнянні з ПОШУКОВИМ ПЕРШИМ ПЕРЕДАЧ


90

Я прочитав це про ключове слово SQL DEFERRABLEу системі баз даних - Повна книга .

Останнє [NOT DEFERRABLE] за замовчуванням, і означає, що кожного разу, коли виконується оператор модифікації бази даних, обмеження перевіряється відразу після цього, якщо модифікація може порушити обмеження зовнішнього ключа.

Однак, якщо ми оголосимо обмеження РОЗШИРЕНИМ , тоді ми маємо можливість почекати, поки транзакція не завершиться, перед тим, як перевірити обмеження.

Ми слідуємо за ключове слово відкладаються або INITIALLY DEFERRED або INITIALLY IMMEDIATE . У першому випадку перевірка буде відкладена безпосередньо перед кожною транзакцією. В останньому випадку перевірка проводитиметься відразу після кожної заяви.

Чим NOT DEFERRABLEвідрізняється від DEFERRABLE INITIALLY IMMEDIATE? В обох випадках, схоже, будь-які обмеження перевіряються після кожного окремого твердження.

Відповіді:


72

За допомогою DEFERRABLE INITIALLY IMMEDIATEви можете відкласти обмеження на вимогу, коли вам це потрібно.

Це корисно, якщо ви зазвичай хочете перевірити обмеження під час оператора, але, наприклад, пакетне навантаження хоче відкласти перевірку до часу фіксації.

Синтаксис того, як відкласти обмеження, різний для різних СУБД.

З NOT DEFERRABLEвами ви ніколи не зможете відкласти перевірку до часу фіксації.


1
@romkyns: DEFERRABLEзаявляє про намір дизайнера про те, що відстрочка обмеження є корисною або необхідною дією. Це не стосується переважної більшості обмежень та маркування баз даних, оскільки це DEFERRABLEможе втратити цю корисну відмінність.
день, коли

4
@onedaywhen З тих пір мій колега вказав на поважну поважну причину: насправді ви можете покладатися на невідкладані обмеження в будь-якій точці будь-якої транзакції, але відкладені обмеження спостерігаються лише на початку транзакції.
Роман Старков

@RomanStarkov Крім того, це питання продуктивності. NOT DEFERRABLEзазвичай найшвидший.
Teejay

46

Окрім інших (правильних) відповідей, говорячи про PostgreSQL , слід зазначити, що:

  • з NOT DEFERRABLE кожен рядок перевіряється на вставки / оновлення часу

  • з DEFERRABLE ( в даний час НЕГАЙНОЇ ) все рядки перевіряються в кінці вставки / оновлення

  • з DEFERRABLE (на даний момент DEFERRED ) всі рядки перевіряються в кінці транзакції

Тож неправильно стверджувати, що обмеження DEFERRABLE діє як НЕ DEFERRABLE, коли для нього встановлено IMMEDIATE.


Давайте детальніше розберемо цю різницю:

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;

Це правильно виводить:

вихід

Але якщо ми видалимо інструкцію DEFERRABLE ПЕРВОНАЧНІЙ НЕЗАБАЖНО,

ПОМИЛКА: повторюване значення ключа порушує унікальне обмеження "example_row_col_key" ДЕТАЛЬНО: Ключ ("рядок", col) = (2, 2) уже існує. ********** Помилка **********

ПОМИЛКА: повторюване значення ключа порушує унікальне обмеження "example_row_col_key" Стан SQL: 23505 Деталь: Ключ ("рядок", col) = (2, 2) вже існує.


ДОДАТОК (12 жовтня 2017 р.)

Ця поведінка справді задокументована тут , розділ "Сумісність":

Крім того, PostgreSQL перевіряє обмеження унікальності, що не можна відкласти, негайно, а не в кінці заяви, як пропонується стандарт.


Цікаво. Мені здається, що в принципі немає жодної причини віддавати перевагу поведінці "НЕ ВІДМОВЛЯЄМО" перед "ІМЕДІАЦІЙНОЮ" поведінкою, і для Postgres має сенс бути більш прощаючими і змусити НЕ ВИМИНЮВАНИХ поводитися як "ІМЕДІАЦІЙНІ". Порядок, в якому рядки оновлюються в операторі UPDATE, наскільки мені відомо, навіть не задокументований і не описаний, отже, чи не є поведінка цієї перевірки обмежень середнього висловлення принаймні частково невизначеною? Я не можу зрозуміти, чому хтось хотів би такої поведінки - але, можливо, для цього є розумний випадок, який мені не вистачає уяви.
Mark Amery

1
Так, в основному єдина причина віддавати перевагу NOT DEFERRABLEшвидкості ( див. Тут , розділ Невідкладені обмеження унікальності , "Майте на увазі, що це може бути значно повільнішим, ніж негайна перевірка унікальності" ).
Teejay

Крім того, на DEFERRABLEобмеження не можна посилатись як на зовнішні ключі в інших таблицях ( див. Тут , розділ Параметри , "Стовпці, на які посилаються, повинні бути стовпцями обмеженого унікального або обмеження первинного ключа в таблиці, на яку посилаються" ).
Teejay

1
Отже, як правило, якщо для ділової логіки не має значення, коли обмеження перевірено, то чи варто мені за замовчуванням використовувати NOT DEFERRABLEпросто тому, що воно працює ефективніше?
dvtan

1
У нашому ORM ми тепер використовуємо наступні правила: 1) якщо обмеженням є PK, ми використовуємо NOT DEFERRABLE2) якщо принаймні один FK посилається на обмеження, ми також використовуємо NOT DEFERRABLE3) в інших випадках ми використовуємо DEFERRABLE INITIALLY IMMEDIATE. Це може трохи знизити продуктивність цих обмежень, але забезпечує максимальну сумісність з іншими СУБД, якими ми користуємось (Oracle, SqlServer). PK та FK не є проблемою, оскільки ми ніколи не оновлюємо їх значення (що, на мою думку, є хорошою звичкою програмування для БД).
Teejay

29

Окрім очевидної можливості відстрочити, різниця полягає в дійсності. Якби не було покарання за ефективність, тоді б не було потреби мати можливість вибору відкладеного чи ні - всі обмеження просто були б відстрочуваними.

Штраф за продуктивність пов’язаний з оптимізацією, яку може виконувати база даних, знаючи, як обмежуються дані. Наприклад, індекс, який створений для підтримки унікального обмеження в Oracle, не може бути унікальним індексом, якщо обмеження можна відкласти, оскільки тимчасово дозволяється дублікати. Однак, якщо обмеження не можна відкласти, тоді індекс може бути унікальним.


7

Я дуже спізнююсь на вечірку, але я хотів додати, що - станом на грудень 2018 року - лише дві бази даних, які я знаю (їх може бути більше), пропонують певний рівень реалізації цієї стандартної функції 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 Незважаючи на те, що Oracle 12c приймає стан NOT DEFERRABLE обмеження , він фактично ігнорує його та змушує його працювати як DEFERRABLE INITIALLY IMMEDIATE.

Як бачите, Oracle не реалізує перший тип ( NOT DEFERRABLE), і тому розробники, що використовують Oracle (у цьому випадку OP), можуть заплутатися і вважати перші два типи еквівалентними.

Цікаво, що Oracle та PostgreSQL мають інший тип за замовчуванням. Можливо, це має наслідки для продуктивності.


4

NOT DEFERRABLE - ви не можете змінити перевірку обмежень, oracle перевіряє її після кожного оператора (тобто безпосередньо після оператора insert).

ВІДМОВЛЕНО ПЕРШИЙ НЕЗАБАЖНО - oracle перевіряє обмеження після кожного висловлювання. АЛЕ, ви можете змінити його на після кожної транзакції (тобто після коміту):

set constraint pk_tab1 deferred;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.