
2026/02/10 5:01
MySQL の外部キー・カスケード操作が最終的にバイナリログに記録されるようになった。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
MySQL 9.6 では、外部キー制約を InnoDB 内ではなく SQL レイヤーで強制する新しいモードが導入されました。この変更は、読み取り専用起動変数
innodb_native_foreign_keys(デフォルトは FALSE)によって制御されます。マイグレーションテスト中にレガシー動作を維持したい場合は TRUE に設定できます。外部キーのカスケード更新・削除が SQL で処理されるようになったため、親と子のすべてのステートメントがバイナリログに記録され、Debezium や Readyset のような CDC ツールやレプリケーションに対して可視化されます。従来のリリースでは元の親操作のみがログに残されていたため、カスケードは隠蔽され、CDC パイプラインは削除イベントを見逃すという問題(Bug #32506)が報告されています。ベンチマークでは、SQL エンジンによる強制が従来の InnoDB アプローチと性能面で同等であることが示されています。
このアーキテクチャ変更により、RocksDB や MyISAM など他のストレージエンジンを使用するレプリカは、親行削除後に孤立した子行を残さなくなります。また、将来的にはカスケード変更時のトリガーや追加エンジンへの外部キーサポートといった機能拡張が可能になります。SQL エンジンによる強制が完全に採用されると、レガシーオプション
innodb_native_foreign_keys は削除されます。
結果として、レプリカおよび CDC パイプラインの完全な変更履歴が確保され、孤立行が減少し、監査トレイルが向上し、Debezium や Readyset のようなツールに依存する企業にとってコンプライアンスが簡素化されます。
本文
MySQL 9.6:外部キーのカスケード操作がついにバイナリログへ反映される
数年にわたり、CDC(Change Data Capture)やレプリケーション環境で MySQL を使うユーザーは、根本的な制約を受け入れざるを得ませんでした。外部キーはストレージエンジン(InnoDB)が強制していたため、カスケード操作がバイナリログに現れることはありませんでした。
2026年1月20日にリリースされた MySQL 9.6 は、外部キーの検証を InnoDB から SQL レイヤーへ移行し、カスケードも binlog に可視化されるようにしました。
問題点:ストレージエンジンレベルでの FK 強制
InnoDB が外部キーを実装した際、その処理は完全にストレージエンジン内部で行われました。
SQL エンジンが親テーブルに対して
DELETE や UPDATE を送信すると、InnoDB は内部でカスケード操作を実施しますが、それらの操作は SQL レイヤーに到達せず、結果としてログに残りません。
例:スキーマ
CREATE TABLE orders ( id INT PRIMARY KEY, customer_id INT, total DECIMAL(10,2) ) ENGINE=InnoDB; CREATE TABLE order_items ( id INT PRIMARY KEY, order_id INT, product_name VARCHAR(100), quantity INT, FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE ) ENGINE=InnoDB;
データ
INSERT INTO orders VALUES (1, 100, 250.00); INSERT INTO order_items VALUES (1, 1, 'Widget', 5); INSERT INTO order_items VALUES (2, 1, 'Gadget', 3);
DELETE FROM orders WHERE id = 1; を実行すると、InnoDB は内部で order_items の2件を削除します。バイナリログには親テーブルの削除のみが記録されます。
| Event | Description |
|---|---|
| Table_map (orders) | テーブル ID 90 のマッピング |
| Delete_rows (orders) | 親行が削除された |
| Xid | コミット |
子行の2件は一切現れません。
バイナリログへの影響
- 行ベースレプリケーション:
でもカスケードは不可視。binlog_format = 'ROW'
Bug #32506(2007年11月)でこの制限が文書化されています。 - 異なるストレージエンジン:レプリカが MyISAM、RocksDB など FK をサポートしないエンジンを使っている場合、カスケードはレプリカ側では起こりません。
- CDC パイプライン:Readyset や Debezium のようなツールはバイナリログを読み取ります。カスケードがログに無いと CDC コンシューマはそれらのイベントを完全に見逃します(Debezium FAQ)。
- 監査トレイル:binlog を完全な変更履歴として利用しているシステムは、カスケード時の変更を把握できず盲点が生じます。
MySQL 9.6 の解決策:SQL エンジンでの FK 強制
MySQL 9.6 は外部キー処理を再設計しました:
- SQL エンジンが子テーブルの FK 制約を評価します。
- カスケードは明示的な DML 文として実行されます。
- 親・子両方の操作がバイナリログに記録されます。
これにより、
DELETE FROM orders WHERE id = 1; は親削除と2件の子削除をすべて binlog に出力します。
| Event | Description |
|---|---|
| Table_map (orders) | ID 90 |
| Table_map (order_items) | ID 92 |
| Delete_rows (order_items) | 2 行が削除された |
| Delete_rows (orders) | 親行が削除された |
| Xid | コミット |
すべての downstream コンシューマは完全な変更履歴を取得できます。
innodb_native_foreign_keys
変数
innodb_native_foreign_keys移行を支援するため、MySQL は読み取り専用の起動時変数を導入しました:
[mysqld] innodb_native_foreign_keys=TRUE -- 従来の InnoDB 強制
- デフォルト:
– SQL エンジンでの強制が有効。FALSE
に設定すると旧挙動に戻り、完全採用前のテストに便利です。TRUE
Oracle はコミュニティが SQL エンジンアプローチを受け入れた後、この変数を削除予定です。
パフォーマンス特性
ベンチマークでは、SQL エンジンでの強制は InnoDB のオリジナルメソッドとほぼ同等に動作します。
同じ制約チェックと行変更が行われるだけで、実行ポイントが変わったため、オーバーヘッドはデータ変更自体の I/O コストに比べてごく小さくなります。
今後の展望
Oracle のロードマップには次のような項目があります:
- カスケード変更に対するトリガーの拡張サポート。
- 追加のストレージエンジンでの外部キー強制。
SQL エンジン構造は、ストレージエンジンレベルでは実現できなかったこれらの機能拡張への土台を提供します。
結論
MySQL 9.6 は長年にわたるアーキテクチャ上のギャップを解消しました。バイナリログはすべてのデータ変更、カスケードも含めて完全に反映されるようになり、レプリケーション、CDC パイプライン、および監査システム全体が恩恵を受けます。
参考文献
- MySQL 9.6 リリースノート – Innovation Release, 2026年1月20日
- Oracle MySQL Blog: “No More Hidden Changes” – Prabakaran Thirumalai, 2026年1月30日
- Bug #32506: Foreign‑key cascades do not appear when
– 初期報告、2007年11月binlog_format = 'ROW' - MySQL 8.4 リファレンスマニュアル:InnoDB と MySQL レプリケーション – 歴史的制限の文書化
- Debezium FAQ: “Missing DELETE events” – CDC ツールがカスケード制限を認識していることを示すドキュメント