SQL Antipatterns ch5 Keyless Entry
- Keyless Entry
- Objective: Simplify Database Architecture
- Antipattern: Leave Out the Constraints
- How to Recognize the Antipattern
- Legitimate Uses of the Antipattern
- Solution: Declare Constraints
Make your database mistake-proof with constraints.
Keyless Entry
- FK制約を使わなかったところDBに齟齬が生じた話
- 品質管理スクリプトを定期実行
- 孤立した子レコードを探し、見つけたらメール通知
- レコードが増えるにつれ処理時間もレポート内容も長くなっていった...
- 真に必要だったのは、不正な入力があった時点で早々にアプリケーションを落とすこと
Objective: Simplify Database Architecture
- 参照整合性は、DB設計やDB運用において重要な位置をしめる
- これを確保するのがFK制約
- しかし下記理由をつけて忌避されることがある
- データ更新が制約とぶつかる
- 柔軟な設計につき、FK制約を適用できない
- 暗黙に作成されるインデックスがパフォーマンスに悪影響を及ぼす
- FKをサポートしていない製品を使用している
- FK宣言のシンタックスをいちいち調べなければならない
Antipattern: Leave Out the Constraints
- メリット
- 設計の単純化
- 柔軟性の向上
- 高速化
- デメリット
- 参照整合性を自前で確保しなければならない
Assuming Flawless Code
- アプリケーション側で参照整合性の確保を自前実装しなければならない
- INSERT前に親をSELECT
- DELETE前に子をSELECT
- ロック等しない限り、race condition (競合状態)にはなりうる
One in a million is next Tuesday. (Gordon Letwin)
- ロックは並列制御やスケーラビリティと相性悪い
Checking for Mistakes
- 孤児レコードを探す
LEFT OUTER JOIN
で駆動表側がNULLになる行 = 内部表側が孤児
- 疑問
- どれだけの頻度で実行すればいいの?
- 見つかったらどうすればいいの?修正できる?
- そもそも孤児が生じないのが一番
"It's Not My Fault!"
- DBのデータはつねに一貫性のある状態でなければならない
- アプリケーションコードに変更を加えた後でも
- DBを直接触った後でも
Catch-22 Updates
- 親子を別々に更新できなくなることがある
- 親を更新しないと子を更新できない
- 子は親にない値に変更できない
- 子を更新しないと親を更新できない
- 親は子から参照されている値を変更できない
- 親を更新しないと子を更新できない
How to Recognize the Antipattern
- こんなのが聞こえてきたら注意
- 「一方のテーブルに存在する値が、他方のテーブルに存在しないことを確認するには、どうクエリすればいい?」
- 孤児レコードを探そうとしている
- 「INSERTしようとしている値が他方のテーブルに存在することを確認する高速な方法は?」
- 親レコードが存在することを確認しようとしている
- FK使え
- 「FKはDBを遅くするから使うなと習った」
- より大きな問題を生じる
- パフォーマンス問題が生じることも
- より大きな問題を生じる
- 「一方のテーブルに存在する値が、他方のテーブルに存在しないことを確認するには、どうクエリすればいい?」
Legitimate Uses of the Antipattern
- 製品がFK制約をサポートしていない場合
- FK制約を適用できない、柔軟な設計の場合
Solution: Declare Constraints
- FK制約使え
- アプリケーション/DB直操作に共通の制限をかけられる
- コード減る
- バグも減る
Supporting Multitable Changes
- 複数テーブルの更新をAtomicに行える
- 親子同時更新
- "Catch-22 Updates"にて挙げた、「親子を別々には更新できない状況」の打破
- 親子同時更新
- ON UPDATE/ON DELETE句を利用可能
- テーブル追加時なども、アプリケーションコードの変更不要
Overhead? Not Really
- 少しのオーバーヘッドがあるのは確か
- だが、トータルで見るとむしろ効率が上がる説
- INSERT/UPDATE/DELETE前のSELECT確認が不要に
- 複数テーブル更新時のロックが不要に
- 孤児レコードの修正のための定期スクリプトが不要に