延期不可と最初は即時延期可能


90

私は、SQLのキーワードについては、これを読んDEFERRABLEコンプリートブック-データベースシステム

後者の[NOT DEFERRABLE]がデフォルトであり、データベースの変更ステートメントが実行されるたびに、変更が外部キー制約に違反する可能性がある場合は、制約がすぐにチェックされます。

ただし、制約がDEFERRABLEであると宣言した場合は、トランザクションが完了するまで待機してから制約をチェックするオプションがあります。

キーワードDEFERRABLEの後INITIALLY DEFERREDまたはINITIALLY IMMEDIATEが続きます。前者の場合、チェックは各トランザクションがコミットする直前に延期されます。後者の場合、チェックは各ステートメントの直後に行われます。

どうNOT DEFERRABLE違うのDEFERRABLE INITIALLY IMMEDIATE?どちらの場合も、個々のステートメントの後に制約がチェックされるようです。

回答:


72

ではDEFERRABLE INITIALLY IMMEDIATE、あなたがそれを必要なときにオンデマンドで制約を延期することができます。

これは通常、ステートメント時に制約をチェックする必要がある場合に便利ですが、たとえば、バッチロードでは、チェックをコミット時まで延期する必要があります。

ただし、制約を延期する構文は、DBMSごとに異なります。

ではNOT DEFERRABLEあなたは今までコミット時までのチェックを延期することはできません。


1
@romkyns:DEFERRABLE制約の延期は価値のある、または必要なアクションであるという設計者の意図を示します。これは、データベースの制約とラベル付けの大部分には当てはまりませんDEFERRABLE。この有用な区別が失われるからです。
onedaywhen

4
@onedaywhen私の同僚が有効な正当な理由を指摘して以来、実際には、トランザクションのどの時点でも遅延不可の制約に依存することができますが、遅延可能の制約はトランザクションの開始時にのみ明確に観察されます。
ロマン・スターコフ2011

@RomanStarkovまた、それはパフォーマンスの問題です。NOT DEFERRABLE通常は最速です。
Teejay

46

他の(正しい)回答とは別に、PostgreSQLについて話すときは、次のように述べる必要があります。

  • 、NOT DEFERRABLE各行が挿入/更新時にチェックされます

  • DEFERRABLE(現在IMMEDIATE)すべての行が挿入/更新の終了時にチェックされます

  • DEFERRABLE(現在はDEFERRED)すべての行は、トランザクションの終了時にチェックされます

したがって、DEFERRABLE制約がIMMEDIATEに設定されている場合、DEFERRABLE制約はNOT DEFERRABLE制約のように機能すると言うのは正しくありません。


この違いについて詳しく説明しましょう。

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)は既に存在します。


補遺 (2017年10月12日)

この振る舞いは確かに、ここのセクション「互換性」に文書化されています

また、PostgreSQLは、標準が示唆するようにステートメントの最後ではなく、遅延できない一意性制約をすぐにチェックします。


面白い。「NOT DEFERRABLE」動作を「IMMEDIATE」動作よりも優先する理由は基本的になく、Postgresがより寛容であり、NOT DEFERRABLEを「IMMEDIATE」のように動作させることは理にかなっているように思えます。UPDATEステートメントで行が更新される順序は、私が知る限り、文書化も指定もされていません。そのため、この中間ステートメントの制約チェックの動作は、少なくとも部分的に指定されていませんか?なぜ誰もがその振る舞いを望んでいる理由はわかりませんが、おそらく想像力に欠ける、妥当なユースケースがあるでしょう。
Mark Amery 2017年

1
はい、基本的に優先する唯一の理由NOT DEFERRABLEは速度です(ここで非遅延一意性制約のセクション、「これは即時の一意性チェックよりも大幅に遅くなる可能性があることに注意してください」を参照)。
Teejay

また、DEFERRABLE制約を他のテーブルの外部キーとして参照することはできません(ここのセクションパラメータを参照してください「参照される列は、参照されるテーブルの遅延不可の一意または主キー制約の列である必要があります」)。
Teejay

1
経験則として、制約がチェックされたときにビジネスロジックにとってそれが本当に重要ではない場合、NOT DEFERRABLEパフォーマンスが優れているという理由だけでデフォルトを使用する必要がありますか?
dvtan 2017年

1
ORMでは、次のルールを使用します。1)制約がPKの場合はNOT DEFERRABLE2)少なくとも1つのFKが制約を参照する場合は、NOT DEFERRABLE3)他の場合はを使用しますDEFERRABLE INITIALLY IMMEDIATE。これにより、これらの制約のパフォーマンスが若干低下する可能性がありますが、使用する他のDBMS(Oracle、SqlServer)との互換性が最大になります。PKとFKは値を更新しないため問題ではありません(これはDBのプログラミング習慣としては適切だと思います)。
Teejay

29

延期できることは明らかですが、違いは実際にはパフォーマンスです。パフォーマンスが低下しない場合は、延期可能かどうかを選択するオプションは必要ありません。すべての制約は単に延期可能です。

パフォーマンスの低下は、データがどのように制限されているかがわかっていれば、データベースが実行できる最適化に関係しています。たとえば、Oracleで一意の制約をサポートするために作成されたインデックスは、一時的に重複を許可する必要があるため、制約が延期可能である場合、一意のインデックスにはなりません。ただし、制約を延期できない場合は、インデックスを一意にすることができます。


7

私はパーティーに非常に遅れていますが、私はそれを追加したいと思います-2018年12月の時点で-私が知っている2つだけのデータベース(もっとあるかもしれません)がこの標準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)を使用する開発者は混乱し、最初の2つのタイプを同等と見なす場合があります。

興味深いことに、OracleとPostgreSQLのデフォルトタイプは異なります。多分それはパフォーマンスに影響を与えます。


4

NOT DEFERRABLE-制約チェックを変更することはできません。Oracleは各ステートメントの後で(つまり、insertステートメントの直後に)チェックします。

DEFERRABLE INITIALLY IMMEDIATE-Oracleは各ステートメントの後に制約をチェックします。しかし、各トランザクションの後(つまり、コミット後)に変更できます。

set constraint pk_tab1 deferred;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.