MySQL 5.1 リファレンスマニュアル :: 13 ストレージエンジンとテーブルタイプ :: 13.5 InnoDB ストレージ エンジン :: 13.5.6 InnoDB テーブルの作成と利用 :: 13.5.6.4 FOREIGN KEY 制約
« 13.5.6.3 AUTO_INCREMENT カラムが InnoDB 内でどのように機能するか

13.5.6.5 InnoDB と MySQL 複製 »
Section Navigation      [Toggle]
  • 13.5.6 InnoDB テーブルの作成と利用
  • 13.5.6.1 異なる API と共に InnoDB 内でトランザクションをどのように利用するか
  • 13.5.6.2 MyISAM テーブルを InnoDB に変換する
  • 13.5.6.3 AUTO_INCREMENT カラムが InnoDB 内でどのように機能するか
  • 13.5.6.4 FOREIGN KEY 制約
  • 13.5.6.5 InnoDB と MySQL 複製

13.5.6.4. FOREIGN KEY 制約

InnoDB は 外部キー制約もまたサポートします。InnoDB 内の外部キー制約定義の構文は次のようになります:

[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)
    REFERENCES tbl_name (index_col_name, ...)
    [ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION}]
    [ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION}]

外部キー定義には次のような条件があります:

  • 両方のテーブルは InnoDB テーブルである必要があり、それらは TEMPORARY テーブルではいけません。

  • 参照表の中では、外部キーカラムが同じ順番で first カラムとしてリストされているインデックスが存在する必要があります。もしそのようなインデックスが無ければ、自動的に参照表上に作成されます。

  • 参照表の中では、参照カラムが同じ順番で first カラムとしてリストされているインデックスが存在する必要があります。

  • 外部キー カラム上のインデックス プリフィックスはサポートされていません。この1つの結論は、それらのカラム上のインデックスは常にプリフィックス長を含む必要がある為、BLOB と TEXT カラムを外部キー内に含む事ができないという事です。

  • もし CONSTRAINT symbol 条項が与えられると、symbol 値はデータベース上で固有である必要があります。もし条項が与えられなければ、InnoDB は名前を自動的に作成します。

もし親テーブル内に適合する候補キー値が無ければ、InnoDB は子テーブル内に外部キー値を作成しようとする INSERT か UPDATE 操作を拒絶します。子テーブル内にいくつかの適合する行を持つ親テーブル内で、候補キー値を更新または削除しようとする UPDATE や DELETE 操作に対して InnoDB が取るアクションは、FOREIGN KEY 条項の ON UPDATE と ON DELETE サブ条項を利用して指定された referential action 上で依存しています。ユーザが親テーブルから行を削除または更新しようとして、子テーブル内に1つ以上の適合する行がある時、InnoDB は取るべきアクションを考慮して5つのオプションをサポートします:

  • CASCADE:親テーブルから行を削除または更新し、子テーブル内で自動的に適合行を削除または更新します。ON DELETE CASCADE と ON UPDATE CASCADE の両方がサポートされています。2つのテーブルの間で、親テーブル内、または子テーブル内で同じカラム上に機能するいくつかの ON UPDATE CASCADE 条項を定義するべきでは有りません。

  • SET NULL:親テーブルから行を削除または更新し、子テーブル内で外部キー カラムを NULL に設定します。これは外部キー カラムが指定された NOT NULL 修飾子を持たない時だけ有効です。 ON DELETE SET NULL と ON UPDATE SET NULL 条項の両方がサポートされています。

  • NO ACTION:スタンダード SQL 内で、NO ACTION は、もし参照表内に関連する外部キーがあれば主キー値を削除または更新しようとする事は許容されていないという意味で、 no action を意味します。InnoDB は親テーブルの削除または更新操作を拒否します。

  • RESTRICT:親テーブルの削除または更新操作を拒否します。NO ACTION と RESTRICT は ON DELETE か ON UPDATE 条項を省略する事と同じです。(いくつかのデータベース システムが据え置きチェックを持ち、NO ACTION が据え置きチェックです。MySQL 内では、外部キー制約は即座に確認されるので、NO ACTION と RESTRICT は同じです。)

  • SET DEFAULT:このアクションはパーサによって認識されますが、InnoDB は ON DELETE SET DEFAULT か ON UPDATE SET DEFAULT 条項を含むテーブル定義を拒否します。

InnoDB がテーブル内で外部キー制約をサポートする事に注意してください。これらのような場合、「子テーブル レコード」 は本当に同じテーブル内で依存レコードを参照します。

InnoDB は、外部キー チェックが速くなり、テーブル スキャンを必要としないよう、外部キーと参照キー上にインデックスを要求します。外部キー上のインデックスは自動的に作成されます。これは、いくつかの古いバージョン内での、インデックスが明示的に作成される必要があり、そうでなければ外部キー制約の作成が失敗する、という物とは対照的です。

タイプ変換をせずに比較できるよう、外部キーと参照キー内の対応するカラムは InnoDB 内に類似内部データ タイプを持つ必要があります。整数タイプのサイズとサインは同じである必要があります。文字列タイプの長さは同じである必要はありません。もし SET NULL アクションを指定したら、 子テーブル内のカラムを NOT NULL として宣言していない事を確認してください。

もし MySQL が CREATE TABLEステートメントからエラー番号1005を報告し、そのエラーメッセージがエラー150を参照していたら、外部キー制約が正しく形作られていない為にテーブル作成は失敗します。 同じように、もし ALTER TABLE が失敗し、それがエラー150を参照していたら、それは変更したテーブルに対して外部キー制約が間違って形作られるという意味になります。 サーバ内に一番新しい InnoDB 外部キー エラーの詳細説明を表示する為に SHOW ENGINE INNODB STATUS を利用する事ができます。

注意:InnoDB は NULL カラムを含む外部キーや参照キー上で外部キー制約を確認しません。

注意:トリガは現在、転送された外部キー アクションによって有効化されません。

内部 InnoDB カラムの名前と一致するカラム名を持つテーブルを作成する事はできません。(DB_ROW_ID、DB_TRX_ID、DB_ROLL_PTR そして DB_MIX_ID を含む)MySQL 5.1.10以前のバージョン内ではこれはクラッシュの原因となり、5.1.10からはサーバがエラー1005を報告し、エラーメッセージ内で errno -1 を参照します。

SQL スタンダードからの逸脱:InnoDB は同じ参照キー値を持つ親テーブル内にいくつかの行があると、外部キーチェック内で同じキー値を持つ別の親行がまるで存在しないかのように機能します。例えば、もし RESTRICT タイプ制約を定義し、いくつかの親行を持つ子行があれば、InnoDB はそれらの親行の削除を許可しません。

InnoDB は、外部キー制約に対応するインデックス内のレコードに基づいた、縦型アルゴリズムを通して転送操作を行います。

SQL スタンダードからの逸脱:非 UNIQUE キーを参照する FOREIGN KEY 制約はスタンダード SQL ではありません。それはスタンダード SQL への InnoDB 拡張子です。

SQL スタンダードからの逸脱:もし ON UPDATE CASCADE か ON UPDATE SET NULL が転送の最中に既に更新された 同じテーブル の更新を反復すると、それは RESTRICT のように機能します。これは、自己参照型 ON UPDATE CASCADE か ON UPDATE SET NULL 操作を利用する事ができないという意味です。これは転送更新の結果に起きる無限ループを防ぐ為の物です。反対に、自己参照型 ON DELETE SET NULL は、自己参照型 ON DELETE CASCADE と同様可能です。転送操作は15レベルより深くネスト化される事はないでしょう。

SQL スタンダードからの逸脱:通常の MySQL のように、挿入、削除、または多くの行の更新を行う SQL ステートメント内では、InnoDB は UNIQUE と FOREIGN KEY 制約を行ごとに行います。SQL スタンダードによると、デフォルト動作は据え置きチェックでなければいけません。それは、SQL ステートメント全体 が処理された後に制約の確認だけが行われるいう事です。InnoDB が据え置き制約チェックを実装するまでは、外部キーを通してそれ自身を参照するレコードを削除するというような、いくつかの操作を行う事が不可能になります。

ここに、単一カラム外部キーを通して parent と child テーブルを関連させるシンプルな例があります:

CREATE TABLE parent (id INT NOT NULL,
                     PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE child (id INT, parent_id INT,
                    INDEX par_ind (parent_id),
                    FOREIGN KEY (parent_id) REFERENCES parent(id)
                      ON DELETE CASCADE
) ENGINE=INNODB;

product_order テーブルが別の2つのテーブルに外部キーを持つ、さらに複雑な例。1つの外部キーが product テーブル内の2段インデックスに参照をつけます。その他の物は customer テーブル内で単一カラム インデックスに参照をつけます:

CREATE TABLE product (category INT NOT NULL, id INT NOT NULL,
                      price DECIMAL,
                      PRIMARY KEY(category, id)) ENGINE=INNODB;
CREATE TABLE customer (id INT NOT NULL,
                       PRIMARY KEY (id)) ENGINE=INNODB;
CREATE TABLE product_order (no INT NOT NULL AUTO_INCREMENT,
                            product_category INT NOT NULL,
                            product_id INT NOT NULL,
                            customer_id INT NOT NULL,
                            PRIMARY KEY(no),
                            INDEX (product_category, product_id),
                            FOREIGN KEY (product_category, product_id)
                              REFERENCES product(category, id)
                              ON UPDATE CASCADE ON DELETE RESTRICT,
                            INDEX (customer_id),
                            FOREIGN KEY (customer_id)
                              REFERENCES customer(id)) ENGINE=INNODB;

InnoDB は ALTER TABLE を利用してテーブルに新しい外部キー制約を追加する事を許容します:

ALTER TABLE tbl_name
    ADD [CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)
    REFERENCES tbl_name (index_col_name, ...)
    [ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION}]
    [ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION}]

要求されたインデックスを最初に作成する事を忘れないでください。.ALTER TABLE を利用して、自己参照型外部キー制約をテーブルに追加する事もできます。

InnoDB は外部キーをドロップする為の ALTER TABLE の利用もサポートします。

ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;

もし外部キーを作成した時に FOREIGN KEY 条項が CONSTRAINT 名を含んでいたら、外部キーをドロップする為にその名前を参照する事ができます。そうでなければ、fk_symbol 値は外部キーが作成された時に InnoDB によって内部的に生成されます。 外部キーをドロップしたい時にシンボル値を見つけるには、SHOW CREATE TABLE ステートメントを利用してください。例:

mysql> SHOW CREATE TABLE ibtest11c\G
*************************** 1. row ***************************
       Table: ibtest11c
Create Table: CREATE TABLE `ibtest11c` (
  `A` int(11) NOT NULL auto_increment,
  `D` int(11) NOT NULL default '0',
  `B` varchar(200) NOT NULL default '',
  `C` varchar(175) default NULL,
  PRIMARY KEY  (`A`,`D`,`B`),
  KEY `B` (`B`,`C`),
  KEY `C` (`C`),
  CONSTRAINT `0_38775` FOREIGN KEY (`A`, `D`)
REFERENCES `ibtest11a` (`A`, `D`)
ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `0_38776` FOREIGN KEY (`B`, `C`)
REFERENCES `ibtest11a` (`B`, `C`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB CHARSET=latin1
1 row in set (0.01 sec)

mysql> ALTER TABLE ibtest11c DROP FOREIGN KEY `0_38775`;

単一 ALTER TABLE ステートメントの別々の条項の中に外部キーを追加したりドロップしたりはできません。別々のステートメントが要求されます。

InnoDB パーサは、FOREIGN KEY ... REFERENCES ... 条項内のテーブルとカラム識別子がバックフォート内で参照される事を許容します。(あるいは、もし ANSI_QUOTES SQL モードが有効であれば二重引用符を利用する事もできます。)InnoDB パーサは、lower_case_table_names システム変数の設定も考慮します。

InnoDB はテーブルの外部キー定義を SHOW CREATE TABLE ステートメントのアウトプットの一部として返します:

SHOW CREATE TABLE tbl_name;

mysqldump はダンプ ファイルのテーブルの正しい定義も作成し、外部キーの事も忘れません。

次のようにテーブルの外部キー制約を表示する事もできます:

SHOW TABLE STATUS FROM db_name LIKE 'tbl_name';

外部キー制約はアウトプットの Comment カラム内にリストされています。

外部キー チェックを行っている時、InnoDB はそれが見なければいけない子または親レコード上に共有行レベル ロックを設定します。 InnoDB は直ちに外部キー制約を確認します。その確認はトランザクション コミットに据え置きされません。

外部キー関係を持つテーブルのダンプ ファイルの再ロードを簡単にする為に、mysqldump は FOREIGN_KEY_CHECKS を0に設定する為に自動的にダンプ アウトプット内にステートメントを含みます。これは、ダンプが再ロードされた時にテーブルが特定の順番で再ロードされなければいけないという問題を防ぎます。この変数をマニュアルで設定する事も可能です:

mysql> SET FOREIGN_KEY_CHECKS = 0;
mysql> SOURCE dump_file_name;
mysql> SET FOREIGN_KEY_CHECKS = 1;

これは、もしダンプ ファイルが外部キーに対して正しい順番でオーダされていないテーブルを含んでいたら、テーブルをどんな順番でインポートしてもよいと許容します。これはインポート操作のスピードも上げます。FOREIGN_KEY_CHECKS を0に設定する事は、LOAD DATA と ALTER TABLE 操作の最中に外部キー制約を無視する為にも役に立ちます。しかし、FOREIGN_KEY_CHECKS=0 であったとしても、InnoDB は、カラムが非適合カラム タイプの参照をつける外部キー制約の作成を許容しません。

InnoDB は、SET FOREIGN_KEY_CHECKS=0 を行わない限り、FOREIGN KEY 制約によって参照を付けられたテーブルをドロップする事を許容しません。テーブルをドロップする時、その作成ステートメント内で定義された制約もまたドロップされます。

それは、もしドロップされたテーブルを再作成すると、それに参照をつける外部キー制約と同一の定義を持つはずです。それは右側のカラム名とタイプを持ち、先に述べたように参照キー上にインデックスを持つはずです。もしそれらが満たされなければ、MySQL はエラー番号1005を返し、エラー メッセージ内で errno 150を参照します。

Copyright © 1997, 2010, Oracle and/or its affiliates. All rights reserved. Legal Notices
Top / Previous / Next / Up / Table of Contents
© 2010, Oracle Corporation and/or its affiliates