外部キー制約:ON UPDATEおよびON DELETEを使用する場合


196

私は、MySQL Workbenchを使用してデータベーススキーマを設計しています。これは、ダイアグラムを実行して、それらを変換できるので、かなりクールです。

とにかく、外部キーをサポートしているため、InnoDBを使用することにしました。ただし、外部キーの[更新時]オプションと[削除時]オプションを設定できることに気づきました。誰かが、「制限」、「カスケード」、およびnullの設定を簡単な例で使用できる場所を説明できますか?

たとえば、userを含むテーブルがあるとしますuserID。そして、私messageは2つの外部キー(テーブルuserID内の同じ主キーを参照する)を持つ多対多のメッセージテーブルがあるとしuserます。この場合、[更新時]および[削除時]オプションの設定は役に立ちますか?もしそうなら、私はどちらを選びますか?これが良い例ではない場合、これらがどのように役立つかを説明する良い例を考え出していただけませんか?

ありがとう

回答:


485

データベースに制約を加えることをためらわないでください。一貫性のあるデータベースが確実に得られます。これがデータベースを使用する理由の1つです。特に、複数のアプリケーションがそれを要求している場合(または1つのアプリケーションのみで、ダイレクトモードと異なるソースを使用するバッチモードの場合)。

MySQLでは、postgreSQLのように高度な制約はありませんが、少なくとも外部キー制約はかなり高度です。

例として、これらの会社のユーザーを含むユーザーテーブルを含む会社テーブルを取り上げます。

CREATE TABLE COMPANY (
     company_id INT NOT NULL,
     company_name VARCHAR(50),
     PRIMARY KEY (company_id)
) ENGINE=INNODB;

CREATE TABLE USER (
     user_id INT, 
     user_name VARCHAR(50), 
     company_id INT,
     INDEX company_id_idx (company_id),
     FOREIGN KEY (company_id) REFERENCES COMPANY (company_id) ON...
) ENGINE=INNODB;

ON UPDATE句を見てみましょう。

  • ON UPDATE RESTRICTデフォルト:テーブルCOMPANYのcompany_idを更新しようとすると、1人のユーザーが少なくともこの会社にリンクしている場合、エンジンは操作を拒否します。
  • 更新時のアクションなし:RESTRICTと同じです。
  • ON UPDATE CASCADE通常は最良のものです。COMPANYテーブルの行でcompany_idを更新すると、エンジンはこのCOMPANYを参照するすべてのUSER行でそれに応じて更新します(ただし、USERテーブルでトリガーがアクティブになっていません、警告)。エンジンが変更を追跡します。
  • ON UPDATE SET NULL:テーブルCOMPANYの行でcompany_idを更新すると、エンジンは関連するユーザーのcompany_idをNULLに設定します(USER company_idフィールドで使用できる必要があります)。アップデートでそれと関係のある面白いことは見当たらないが、私は間違っているかもしれない。

そしてON DELETE側で:

  • ON DELETE RESTRICTデフォルト:テーブルCOMPANYのcompany_id Idを削除しようとすると、1人のユーザーが少なくともこの会社にリンクしている場合、エンジンは操作を拒否し、命を救うことができます。
  • 削除しない場合:RESTRICTと同じ
  • ON DELETE CASCADE危険:テーブルCOMPANYの会社行を削除すると、エンジンは関連するユーザーも削除します。これは危険ですが、セカンダリテーブルを自動的にクリーンアップするために使用できます(したがって、それはあなたが望むものになる可能性がありますが、COMPANY <-> USERの例ではまったくありません)
  • ON DELETE SET NULL一握り:COMPANY行を削除すると、関連するUSERは自動的にNULLとの関係を持ちます。会社を持たないユーザーにとってNullがあなたの価値である場合、これは良い振る舞いである可能性があります。たとえば、一部のコンテンツの作成者としてユーザーをアプリケーションに保持する必要があるかもしれませんが、会社を削除することはあなたにとって問題ではありません。

通常、私のデフォルトはON DELETE RESTRICT ON UPDATE CASCADEです。いくつかON DELETE CASCADEのトラックテーブル(ログ-すべてのログではない-など)を使用ON DELETE SET NULLし、マスターテーブルがUSERテーブルのJOBテーブルのような外部キーを含むテーブルの「単純な属性」である場合。

編集する

私が書いてから久しぶりです。ここで、重要な警告を1つ追加する必要があると思います。MySQLには、カスケードに関する1つの大きな文書化された制限があります。カスケードはトリガーを起動していません。そのため、そのエンジンでトリガーを使用するのに十分な自信がある場合は、カスケード制約を避けてください。

MySQLトリガーは、SQLステートメントによってテーブルに加えられた変更に対してのみアクティブになります。ビューの変更や、SQLステートメントをMySQLサーバーに送信しないAPIによって行われたテーブルの変更によってアクティブ化されません。

==>最後の編集の下を参照してください、物事はこのドメインで動いています

トリガーは、外部キーアクションによってアクティブ化されません。

そして、これはいつか修正されるとは思いません。外部キー制約はInnoDbストレージによって管理され、トリガーはMySQL SQLエンジンによって管理されます。両方が分離されています。Innodbは、制約管理を備えた唯一のストレージです。おそらく、ストレージエンジンに直接トリガーを追加するかもしれませんが、そうしないかもしれません。

しかし、私はあなたが貧弱なトリガー実装と非常に有用な外部キー制約サポートの間で選択すべき要素について私自身の意見を持っています。そして、データベースの整合性に慣れると、PostgreSQLが気に入るはずです。

2017年12月-MySQLに関するこの編集の更新:

コメントで@IstiaqueAhmedが述べたように、この件に関して状況は変わりました。したがって、リンクをたどって、実際の最新の状況をチェックしてください(将来は再び変更される可能性があります)。


8
ON DELETE CASCADE : dangerous-ひとつまみの塩で服用してください。
13:33

3
多くのレコードを変更する必要がある場合は、カスケードに注意する必要があります。システムがロックされる可能性があります。Cascdeの削除は、使用する前に特に注意深く検討する必要があります。子レコードがある場合は、削除を行わないようにすることがよくあります。私は、顧客が以前に持っていたoredersの財務データを消去するために削除したくありません。場合によっては、カスケードがオンになっていないことを確認し、レコードを非アクティブとして無効にする方法を提供する方が良い場合があります。
HLGEM、2011年

1
ビジネスロジックの観点では、に面白いかもしれない一つのケースがあるSET NULLにはON UPDATE会社の更新は会社>ユーザ関係の離脱を表します。例:会社がそのビジネスタイプを変更した場合、以前のユーザーはそのビジネスに関連しなくなっているNULL可能性があるため、このインデックスに適している可能性があります。
CPHPython 2016

1
@ regilero、mysqlサイトへの最初のリンク(dev.mysql.com/doc/refman/5.6/en/triggers.html)のコンテンツが変更されたようです。それはThis includes changes to base tables that underlie updatable viewsあなたが貼り付けたものの代わりに言いますThey do not activate for changes in views
Istiaque Ahmed

6
「顧客が削除して、以前の注文の財務データを消去したくありません。」そのような場合でも、おそらく顧客のデータが必要になるでしょう。設計では、データベースから行を削除するのではなく、おそらく顧客を非アクティブとしてマークする必要があります。実際は、実際にはほとんど何も削除せ、デフォルトで非アクティブにマークすることを好むのは、私の専門的な経験です。恒久的に削除が例である [OK]を、CASCADE DELETE一般的に、また大丈夫でも好ましいです。特に危険だとは思いません。
GrandOpener

3

@MarkR回答への追加-注意すべき1つの点は、ORMを使用する多くのPHPフレームワークが高度なDBセットアップ(外部キー、カスケード削除、一意の制約)を認識または使用しないため、予期しない動作が発生する可能性があることです。

たとえば、ORMを使用してレコードをDELETE CASCADE削除し、関連テーブルのレコードを削除する場合、ORMがこれらの関連レコードを削除しようとすると(多くの場合は自動)、エラーが発生します。


11
それがその特定のORMを使用しない理由です。データベースのサポートが不十分なツールは信頼できません。外部キーとカスケード削除または更新はdbの基本であり、高度な概念ではないため、外部キーの制約なしに現実的なデータベースを設計することはできません。
HLGEM、2011年

問題は、エラーをスローすることです。DELETEを制限することは可能ですが、エンジンでエラーを生成せずにセマンティクスを維持することはできますか?他のデータが削除されないように保護しながら、プログラムを続行します。
TheRealChx101

2

アプリケーションのコンテキストでこれを考慮する必要があります。一般に、データベースではなくアプリケーションを設計する必要があります(データベースは単にアプリケーションの一部です)。

アプリケーションがさまざまなケースにどのように対応するかを検討します。

デフォルトのアクションは、操作を制限する(つまり、許可しない)ことです。これは、愚かなプログラミングエラーを防ぐために通常必要な操作です。ただし、DELETE CASCADEの場合も役立ちます。これは、実際にはアプリケーションと、特定のオブジェクトをどのように削除するかによって異なります。

個人的には、FK制約があるのではなく、データを破棄しないため(MyISAMを参照)、InnoDBを使用します。

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