НЕ ОТЛОЖЕННЫЙ или ОТЛОЖЕННЫЙ НА ПЕРВОНАЧАЛЬНО НЕМЕДЛЕННОМ

92

Я читал об этом ключевом слове SQL DEFERRABLEв книге «Системы баз данных - Полная книга» .

Последнее [NOT DEFERRABLE] используется по умолчанию и означает, что каждый раз, когда выполняется оператор модификации базы данных, ограничение проверяется сразу же после этого, если модификация может нарушить ограничение внешнего ключа.

Однако, если мы объявляем ограничение как ОТЛОЖЕННОЕ , у нас есть возможность дождаться завершения транзакции перед проверкой ограничения.

Мы следуем за ключевым словом ОТЛОЖЕННЫЙ либо на НАЧАЛЬНО ОТЛОЖЕННЫЙ, либо на НАЧАЛЬНО НЕМЕДЛЕННО . В первом случае проверка будет отложена непосредственно перед фиксацией каждой транзакции. В последнем случае проверка будет производиться сразу после каждой выписки.

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

Питер
источник

Ответы:

74

С DEFERRABLE INITIALLY IMMEDIATEего помощью вы можете отложить ограничения по запросу, когда вам это нужно.

Это полезно, если вы обычно хотите проверить ограничения во время выполнения оператора, но, например, для пакетной загрузки нужно отложить проверку до времени фиксации.

Однако синтаксис того, как отложить ограничения, отличается для разных СУБД.

С NOT DEFERRABLEвы никогда не сможете отложить проверку до времени фиксации.

a_horse_with_no_name
источник
1
@romkyns: DEFERRABLEзаявляет о намерении разработчика, что отсрочка ограничения является стоящим или необходимым действием. Это не относится к подавляющему большинству ограничений базы данных и маркировке всех, так как DEFERRABLEэто полезное различие потеряно.
однажды, когда
4
@onedaywhen Мой коллега с тех пор указал на вескую вескую причину, на самом деле: вы можете полагаться на неотложные ограничения в любой момент любой транзакции, но откладываемые ограничения обязательно наблюдаются только в начале транзакции.
Роман Старков
@RomanStarkov Кроме того, это вопрос производительности. NOT DEFERRABLEобычно самый быстрый.
Teejay
50

Помимо других (правильных) ответов, говоря о PostgreSQL , необходимо указать, что:

  • с NOT DEFERRABLE каждая строка проверяется во время вставки / обновления

  • с DEFERRABLE (в настоящее время IMMEDIATE ) все строки проверяются в конце вставки / обновления

  • с DEFERRABLE (в настоящее время DEFERRED ) все строки проверяются в конце транзакции

Поэтому неправильно говорить, что ограничение DEFERRABLE действует как NOT 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 INITIALLY IMMEDIATE,

ОШИБКА: повторяющееся значение ключа нарушает уникальное ограничение "example_row_col_key" ДЕТАЛИ: Ключ ("row", col) = (2, 2) уже существует. ********** Ошибка **********

ОШИБКА: повторяющееся значение ключа нарушает уникальное ограничение "example_row_col_key" Состояние SQL: 23505 Деталь: Ключ ("row", col) = (2, 2) уже существует.


ДОБАВЛЕНИЕ (12 октября 2017 г.)

Это поведение действительно задокументировано здесь , в разделе «Совместимость»:

Кроме того, PostgreSQL проверяет неотложные ограничения уникальности немедленно, а не в конце оператора, как предполагает стандарт.

Тиджей
источник
Интересно. Мне кажется, что в принципе нет причин предпочитать поведение «НЕ ОТЛОЖЕННОЕ» поведению «НЕМЕДЛЕННО» и что для Postgres было бы разумно быть более снисходительным и заставить НЕ ОТЛОЖИТЬ вести себя как «НЕМЕДЛЕННОЕ». Насколько мне известно, порядок, в котором обновляются строки в операторе UPDATE, даже не задокументирован и не указан, так что, по крайней мере, частично не определено поведение этой проверки ограничений в середине оператора? Я не понимаю, почему кому-то может понадобиться такое поведение, но, возможно, есть разумный вариант его использования, на который у меня не хватает воображения.
Марк Эмери
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

НЕ ОТЛОЖЕННЫЙ - вы не можете изменить проверку ограничений, oracle проверяет ее после каждого оператора (т.е. непосредственно после оператора вставки).

ОТЛОЖЕННЫЙ НАЧАЛЬНО НЕМЕДЛЕННО - oracle проверяет ограничение после каждого оператора. НО, вы можете изменить его на после каждой транзакции (т.е. после фиксации):

set constraint pk_tab1 deferred;
хаджили
источник