MySQL 8.
これまで動いていたDDLが通らなくなるケースがあり、スキーマ管理やデータマイグレーションで思わぬ影響を受けることがあります。本稿では、この変更の前と後の挙動、そして既存環境への影響と対応策について紹介します。
非一意キーを参照する外部キー
MySQLでは長らく、外部キー参照先
SQL標準では、外部キーが参照できるのは
MySQLでは互換性や柔軟性を優先し、これを長らく緩和していました。そのため、次のようなDDLでもエラーにならず、定義が通っていたのです。
たとえば、以下のような場合でもCREATE TABLEが通っていました。
mysql> CREATE TABLE parent ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, code INT, INDEX idx_code (code) ) ENGINE=InnoDB; Query OK, 0 rows affected (0.02 sec) mysql> CREATE TABLE child ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, parent_code INT, FOREIGN KEY (parent_code) REFERENCES parent(code) ) ENGINE=InnoDB; Query OK, 0 rows affected (0.02 sec)
parent.はユニークではないため、child.の親行は複数存在する可能性があります。以下のようなデータを入れると、削除や更新時にエラーになります。
mysql> SELECT * FROM parent; +----+------+ | id | code | +----+------+ | 1 | 100 | | 2 | 100 | | 3 | 200 | +----+------+ 3 rows in set (0.00 sec) mysql> SELECT * FROM child; +----+-------------+ | id | parent_code | +----+-------------+ | 1 | 100 | +----+-------------+ 1 row in set (0.01 sec) // parent_code = 100 と同じ値の code を持つ parent 行の DELETE はエラーとなる mysql> DELETE FROM parent WHERE id = 1; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`d1`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_code`) REFERENCES `parent` (`code`)) mysql> DELETE FROM parent WHERE id = 2; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`d1`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_code`) REFERENCES `parent` (`code`)) // parent_code = 100 と同じ値の code を持つ parent テーブル行の code 値変更もエラーとなる mysql> UPDATE parent SET code = 101 WHERE id = 1; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`d1`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_code`) REFERENCES `parent` (`code`)) mysql> UPDATE parent SET code = 101 WHERE id = 2; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`d1`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_code`) REFERENCES `parent` (`code`))
非一意キーを参照する外部キー制約は標準SQLではなく、現在非推奨となっているInnoDB拡張機能です。MySQL 8.
restrict_fk_on_non_standard_key
非標準キーの作成禁止を制御するためにMySQL 8.restrict_です。デフォルトではONとなっており、非標準キーは作成できません。
試しにMySQL 8.
mysql> CREATE TABLE parent ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, code INT, INDEX idx_code (code) ) ENGINE=InnoDB; Query OK, 0 rows affected (0.02 sec) mysql> CREATE TABLE child ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, parent_code INT, FOREIGN KEY (parent_code) REFERENCES parent(code) ) ENGINE=InnoDB; ERROR 6125 (HY000): Failed to add the foreign key constraint. Missing unique key for constraint 'child_ibfk_1' in the referenced table 'parent'
restrict_に設定することで、MySQL 8.
mysql> SET restrict_fk_on_non_standard_key=OFF; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> CREATE TABLE child ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, parent_code INT, FOREIGN KEY (parent_code) REFERENCES parent(code) ) ENGINE=InnoDB; Query OK, 0 rows affected, 1 warning (0.02 sec) Warning (Code 6124): Foreign key 'child_ibfk_1' refers to non-unique key or partial key. This is deprecated and will be removed in a future release.
移行時の影響と対応策
MySQL 8.
Upgrades to MySQL 8.
4 releases from MySQL 8. 0 are supported even if the old database contains one or more foreign keys referring to non-unique or partial keys. As part of the upgrade process, the server prints a list of warning messages with the names of those foreign keys referring to nonstandard keys.
ただし、新たにテーブルを作成・
- 非ユニークな外部キーを許可する場合は、一時的に
restrict_を設定fk_ on_ non_ standard_ key=OFF - 本番環境では常にONとし、非標準設計を検出したら修正する運用を確立する
まとめ
MySQL 8.restrict_によりそのような非標準キーの作成がデフォルトで禁止されました。互換性を保つためにOFFにすることは可能ですが、非標準キーのサポートは将来のMySQLバージョンで削除される見込みです。
したがって、8.