InnoDB
は外部キー制約をサポートします。InnoDB
内の外部キー制約定義の構文は次のようになります:
[CONSTRAINT [symbol
]] FOREIGN KEY [index_name
] (index_col_name
, ...) REFERENCEStbl_name
(index_col_name
,...) [ON DELETEreference_option
] [ON UPDATEreference_option
]reference_option
: RESTRICT | CASCADE | SET NULL | NO ACTION
index_name
は外部キーの ID
を表します。これを指定しても、外部キーのインデックスが明示的に定義された場合にはこれは無視されます。それ以外の場合、InnoDB
は外部キーのインデックスを作成する場合に、index_name
をインデックス名として使用します。
外部キー定義には次のような条件があります:
両方のテーブルは
InnoDB
テーブルである必要があり、それらは
TEMPORARY
テーブルではいけません。
型変換をせずに比較できるよう、外部キーと参照キー内の対応するカラムは
InnoDB
内に類似内部データ型を持つ必要があります。整数型のサイズとサインは同じである必要があります。文字列型の長さは同じである必要はありません。非バイナリ列
(文字列)
の場合、キャラクタセットと照合が同一である必要があります。
InnoDB
は、外部キーチェックが速くなり、テーブル走査を必要としないよう、外部キーと参照キー上にインデックスを要求します。参照表の中では、外部キーカラムが同じ順番で
first
カラムとしてリストされているインデックスが存在する必要があります。もしそのようなインデックスが無ければ、自動的に参照表上に作成されます。(これは、いくつかの古いバージョン内での、インデックスが明示的に作成される必要があり、そうでなければ外部キー制約の作成が失敗する、というものとは対照的です。)
index_name
を指定した場合、その名前は前述のように使用されます。
InnoDB
では、外部キーは任意のインデックスカラムやカラムグループを参照できます。ただし、参照表の中では、参照カラムが同じ順番で
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
つのオプションをサポートします.
ON DELETE
または
ON UPDATE
が指定されていない場合のデフォルトのアクションは、RESTRICT
になります。
CASCADE
:親テーブルから行を削除または更新し、子テーブル内で自動的に適合行を削除または更新します。ON
DELETE CASCADE
と ON
UPDATE CASCADE
の両方がサポートされています。2
つのテーブルの間で、親テーブル内、または子テーブル内で同じカラム上に機能するいくつかの
ON UPDATE CASCADE
節を定義するべきではありません。
現時点では、カスケード外部キーアクションがトリガーを有効にしません。
SET
NULL
:親テーブルから行を削除または更新し、子テーブル内で外部キーカラムを
NULL
に設定します。これは外部キーカラムが指定された
NOT NULL
修飾子を持たないときだけ有効です。ON
DELETE SET NULL
と ON
UPDATE SET NULL
節の両方がサポートされています。
SETNULL
アクションを指定した場合、テーブル内のカラムを
NOTNULL
として宣言していないことを確認してください。
NO
ACTION
:スタンダード SQL
内で、NO ACTION
は、もし参照表内に関連する外部キーがあれば主キー値を削除または更新しようとすることは許容されていないという意味で、no
action
を意味します。InnoDB
は親テーブルの削除または更新操作を拒否します。
RESTRICT
:親テーブルの削除または更新操作を拒否します。RESTRICT
(または NO ACTION
)
を指定することは、ON
DELETE
または ON
UPDATE
節を省略することと同じです。(いくつかのデータベースシステムが据え置き確認を持ち、NO
ACTION
が据え置き確認です。MySQL
では外部キー制約の確認は即座に行われるため、NO
ACTION
は
RESTRICT
と同じになります。)
SET
DEFAULT
:このアクションはパーサーによって認識されますが、InnoDB
は ON DELETE SET DEFAULT
か ON UPDATE SET DEFAULT
節を含むテーブル定義を拒否します。
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 TABLEtbl_name
ADD [CONSTRAINT [symbol
]] FOREIGN KEY [index_name
] (index_col_name
, ...) REFERENCEStbl_name
(index_col_name
,...) [ON DELETEreference_option
] [ON UPDATEreference_option
]
外部キーは、自己参照型にする
(同じテーブルを参照する)
ことができます。ALTER
TABLE
を使って外部キー制約をテーブルに追加する場合には、まず必要なインデックスを忘れずに作成してください。
InnoDB
は外部キーを削除するための
ALTER TABLE
の利用をサポートします。
ALTER TABLEtbl_name
DROP FOREIGN KEYfk_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
テーブルの
ALTER TABLE
を実行した結果、カラムの切り詰めなどの理由によりカラムの値が変更されても、InnoDB
の FOREIGN KEY
制約チェックはその値の変更によって発生した可能性のある違反を通知しません。
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 FROMdb_name
LIKE 'tbl_name
';
外部キー制約は出力の
Comment
カラム内にリストされています。
外部キーチェックを行っているとき、InnoDB
はそれが見なければいけない子または親レコード上に共有行レベルロックを設定します。InnoDB
は外部キー制約の確認を即座に行います。その確認がトランザクションコミットまで遅延されることはありません。
外部キー関係を持つテーブルのダンプファイルの再ロードを簡単にするために、mysqldump
は
foreign_key_checks
を 0
に設定するために自動的にダンプ出力内にステートメントを含みます。これは、ダンプが再ロードされたときにテーブルが特定の順番で再ロードされなければいけないという問題を防ぎます。この変数をマニュアルで設定することも可能です:
mysql>SET foreign_key_checks = 0;
mysql>SOURCE
mysql>dump_file_name
;SET foreign_key_checks = 1;
これは、もしダンプファイルが外部キーに対して正しい順番でオーダされていないテーブルを含んでいたら、テーブルをどんな順番でインポートしてもよいと許容します。これはインポート操作のスピードも上げます。foreign_key_checks
を 0
に設定することは、LOAD
DATA
と ALTER
TABLE
操作の最中に外部キー制約を無視するためにも役に立ちます。しかし、foreign_key_checks
= 0
であったとしても、InnoDB
は、カラムが非適合カラム型の参照をつける外部キー制約の作成を許容しません。また、外部キー制約を含む
InnoDB
テーブルでは、ALTER
TABLE
を使ってそのテーブルが別のストレージエンジンを使用するように変更することはできません。ストレージエンジンを変更するには、まずすべての外部キー制約を削除する必要があります。
InnoDB
は、SET foreign_key_checks =
0
を行わないかぎり、FOREIGNKEY
制約から参照されているテーブルを削除することを許容しません。テーブルを削除するとき、その作成ステートメント内で定義された制約もまた削除されます。
それは、もし削除されたテーブルを再作成すると、それに参照をつける外部キー制約と同一の定義を持つはずです。それは右側のカラム名と型を持ち、先に述べたように参照キー上にインデックスを持つはずです。もしそれらが満たされなければ、MySQL はエラー番号 1005 を返し、エラーメッセージ内で エラー 150 を参照します。
もし MySQL が
CREATETABLE
ステートメントからエラー番号 1005
を報告し、そのエラーメッセージがエラー 150
を参照していたら、外部キー制約が正しく形作られていないためにテーブル作成は失敗します。同じように、もし
ALTERTABLE
が失敗し、それがエラー 150
を参照していたら、それは変更したテーブルに対して外部キー制約が間違って形作られるという意味になります。サーバー内に一番新しい
InnoDB
外部キーエラーの詳細説明を表示するために
SHOW ENGINE INNODB STATUS
を利用することができます。
ANSI/ISO SQL
標準を熟知しているユーザーであれば、参照整合性制約定義で使用されている
MATCH
節を認識または実行するストレージエンジンは、InnoDB
も含めて存在しない点に注意してください。明示的な
MATCH
節を使用しても、規定された効果が得られないだけでなく、ON
DELETE
および ON
UPDATE
節が無視されてしまいます。これらの理由により、MATCH
を指定するのは避けるべきです。
SQL 標準の MATCH
節は、複合 (複数カラム) 外部キーの
NULL
値が主キーとの比較時にどのように処理されるのかを制御します。InnoDB
は基本的に MATCH
SIMPLE
で定義されたセマンティクスを実装していますが、このセマンティクスでは外部キーの一部または全部を
NULL
にすることができます。その場合、そうした外部キーを含む
(子テーブルの)
行は、挿入が許可されますが、参照 (親)
テーブルのどの行ともマッチしません。トリガーを使ってほかのセマンティクスを実装することが可能です。
さらに、MySQL や
InnoDB
では、参照カラムにインデックスを設定してパフォーマンスを向上させる必要があります。ところがシステムは、参照カラムを
UNIQUE
にしたり
NOT NULL
として宣言したりしなければならないという要件を強制しません。UPDATE
や DELETE CASCADE
などの操作では、非ユニークキーや
NULL
値を含むキーへの外部キー参照の処理が明確に定義されていません。UNIQUE
かつ NOT NULL
なキーのみを参照する外部キーを使用することをお勧めします。
さらに、InnoDB
は、(SQL 標準で定義されている)
参照をカラム指定の一部として定義する
「インライン
REFERENCES
指定」
の認識やサポートを行いません。InnoDB
が REFERENCES
節を受け付けるのは、独立した
FOREIGN KEY
指定の一部としてこの節が指定された場合だけです。MySQL
サーバーはその他のストレージエンジンでは、外部キーの指定を解析時に無視します。
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
が据え置き制約チェックを実装するまでは、外部キーを通してそれ自身を参照するレコードを削除するというような、いくつかの操作を行うことが不可能になります。