SQL Serverで外部キーを設定する場合、どのような状況で削除または更新時に外部キーをカスケードする必要がありますか。また、その背後にある理由は何ですか。
これはおそらく他のデータベースにも当てはまります。
私は何よりも、各シナリオの具体的な例を探しています。できれば、それらをうまく使用した人からの例を探しています。
SQL Serverで外部キーを設定する場合、どのような状況で削除または更新時に外部キーをカスケードする必要がありますか。また、その背後にある理由は何ですか。
これはおそらく他のデータベースにも当てはまります。
私は何よりも、各シナリオの具体的な例を探しています。できれば、それらをうまく使用した人からの例を探しています。
これまで見てきたことの要約:
外部キーは、データベースの参照整合性を保証する最良の方法です。魔法であるためにカスケードを回避することは、コンパイラの背後にある魔法を信頼していないため、すべてをアセンブリで記述するようなものです。
悪いのは、外部キーを逆方向に作成するなど、外部キーの間違った使用です。
Juan Manuel の例は標準的な例です。コードを使用すると、データベースに誤った DocumentItems を残す可能性が高くなります。
カスケード更新は、たとえば、users テーブルの主キーが名前と姓の組み合わせであるなど、変更可能なものによってデータへの参照がある場合に役立ちます。次に、その組み合わせの変更を、参照されているすべての場所に反映する必要があります。
@Aidan、あなたが言及しているその明快さには高い代償が伴い、データベースに偽のデータが残る可能性がありますが、これは小さくありません。私にとって、それは通常、DB に慣れていないことと、その恐怖を助長する DB を操作する前に、どの FK が適切に配置されているかを見つけることができないことです。それか、カスケードの絶え間ない誤用、エンティティが概念的に関連していない場所、または履歴を保存する必要がある場所で使用しています。
カスケード削除を使用することはありません。
データベースから何かを削除したい場合は、何を削除したいかをデータベースに明示的に伝えたいと思います。
もちろん、それらはデータベースで利用可能な関数であり、それらを使用しても問題ない場合があります。注文。
「魔法」が起こるよりも、コード(またはストアドプロシージャ)でそれを行うことで得られる明快さが好きです。
同じ理由で、私もトリガーのファンではありません。
注意すべきことは、「注文」を削除すると、カスケード削除によって 50 個の「orderItem」が削除された場合でも、「影響を受ける 1 行」レポートが返されることです。
私はカスケード削除を頻繁に使用しています。
データベースに対して作業を行っている人は誰でも、不要なデータを決して残さない可能性があることを知っていると、気分が良くなります。依存関係が大きくなった場合は、Management Studio のダイアグラムの制約を変更するだけで、sp や dataaccess を微調整する必要はありません。
そうは言っても、カスケード削除には1つの問題があり、それは循環参照です。これにより、カスケード削除のないデータベースの部分が生じることがよくあります。
私は多くのデータベース作業を行っていますが、カスケード削除が役立つことはめったにありません。私がそれらを効果的に使用したのは、夜間のジョブによって更新されるレポート データベースです。前回のインポート以降に変更されたトップレベルのレコードを削除して、変更されたデータが正しくインポートされるようにし、変更されたレコードとそれに関連するものを再インポートします。データベースの一番下から一番上まで見ていく複雑な削除をたくさん書く必要がなくなりました。
カスケード削除はデータを削除するだけなので、トリガーほど悪いとは思いません。トリガーにはあらゆる種類の厄介なものが含まれている可能性があります。
一般に、私は実際の削除を完全に避け、代わりに論理削除を使用します (つまり、isDeleted と呼ばれるビット列を true に設定します)。
1 つの例は、エンティティ間に依存関係がある場合です...つまり、Document -> DocumentItems (Document を削除すると、DocumentItems には存在する理由がありません)
DBA や "企業ポリシー" が、過去の悪い経験を理由に "On Delete Cascade" (およびその他) の使用を禁止していると聞いたことがあります。あるケースでは、男が 3 つのトリガーを作成し、それらが互いに呼び出されることになりました。回復するのに 3 日間かかった結果、トリガーが完全に禁止されました。これはすべて、1 人の idjit の行動が原因でした。
もちろん、子データを保持する必要がある場合など、「カスケード削除時」の代わりにトリガーが必要になることもあります。ただし、それ以外の場合は、On Delete カスケード メソッドを使用することが完全に有効です。「On Delete カスケード」の主な利点は、すべての子をキャプチャすることです。カスタムで作成されたトリガー/ストア プロシージャは、正しくコーディングされていない場合、動作しない場合があります。
開発者は、開発内容と仕様に基づいて決定を下すことが許可されるべきだと思います。悪い経験に基づくカーペットの禁止は、基準であってはなりません。「絶対に使わない」という思考プロセスは、せいぜい過酷です。ビジネスモデルの変化に応じて、毎回判断を下し、変更を加える必要があります。
これこそが開発ではないでしょうか。
参照している PK レコードが削除された場合に FK を含むレコードを削除する場合は、cascade delete を使用します。言い換えれば、レコードが参照レコードなしでは意味がない場合です。
カスケード削除は、無効な参照が null 例外を発生させるのではなく、デフォルトで確実に削除されるようにするのに役立ちます。
子テーブルの行を削除したい場合親テーブルで対応する行を削除した場合。
カスケード削除が使用されていない場合、参照整合性でエラーが発生します。
主キーの変更を外部キーに更新したい場合
カスケード削除を (コードで行うのではなく) 行う理由の 1 つは、パフォーマンスを向上させることです。
ケース 1: カスケード削除の場合
DELETE FROM table WHERE SomeDate < 7 years ago;
ケース 2: カスケード削除なし
FOR EACH R IN (SELECT FROM table WHERE SomeDate < 7 years ago) LOOP
DELETE FROM ChildTable WHERE tableId = R.tableId;
DELETE FROM table WHERE tableId = R.tableid;
/* More child tables here */
NEXT
次に、カスケード削除を使用して追加の子テーブルを追加すると、ケース 1 のコードが機能し続けます。
私は、関係のセマンティクスが「一部」であるカスケードのみを入れます。そうしないと、次のことを行うと、ばかがデータベースの半分を削除します。
DELETE FROM CURRENCY WHERE CurrencyCode = 'USD'
SQL サーバーで明示的に要求していない削除または更新を避けるようにしています。
カスケードまたはトリガーの使用による。バグを追跡しようとするとき、またはパフォーマンスの問題を診断するときに、彼らはあなたのお尻を噛む傾向があります。
私がそれらを使用するのは、あまり労力をかけずに一貫性を保証する場合です。同じ効果を得るには、ストアド プロシージャを使用する必要があります。
ここにいる他のみんなと同じように、カスケード削除は実際にはほんのわずかしか役に立たないことがわかります(他のテーブルで参照されているデータを削除するのはそれほど面倒ではありません-テーブルがたくさんある場合は、スクリプトでこれを自動化するだけです)が、本当に面倒です復元が困難な重要なデータを誰かが誤ってカスケード削除した場合。
私が使用する唯一のケースは、テーブル テーブル内のデータが高度に制御されており (アクセス許可が制限されているなど)、検証済みの制御されたプロセス (ソフトウェア更新など) によってのみ更新または削除される場合です。
R のいくつかのタプルで見つかった外部キー値を削除する S への削除または更新は、次の 3 つの方法のいずれかで処理できます。
伝播はカスケードと呼ばれます。
次の 2 つのケースがあります。
‣ S のタプルが削除された場合、それを参照していた R のタプルを削除します。
‣ S のタプルが更新された場合、それを参照する R タプルの値を更新します。
さまざまなバージョンのさまざまなモジュールを含むシステムで作業している場合、カスケード削除されたアイテムが PK 所有者の一部または所有されている場合、非常に役立ちます。そうしないと、PK 所有者を削除する前に、すべてのモジュールで依存アイテムをクリーンアップするための即時パッチが必要になります。そうしないと、外部キー関係が完全に省略され、クリーンアップが正しく実行されない場合、システムに大量のゴミが残る可能性があります。
カスケード削除がかなり長い間推奨されていなかった後、既存の 2 つのテーブル間の新しい交差テーブル (削除する交差のみ) にカスケード削除を導入しました。データが失われても、それほど悪くはありません。
しかし、enum のようなリスト テーブルでは、これは悪いことです。誰かがエントリ 13 の黄色をテーブル「colors」から削除すると、データベース内のすべての黄色の項目が削除されます。また、これらはすべて削除-すべて挿入-すべての方法で更新されることがあり、参照整合性が完全に省略されます。もちろんそれは間違っていますが、真の参照整合性の導入が予期しない副作用の危険にさらされているため、長年実行されてきた複雑なソフトウェアをどのように変更しますか?
別の問題は、主キーが削除された後でも元の外部キーの値が保持される場合です。元の FK に対して廃棄列と ON DELETE SET NULL オプションを作成することもできますが、これには、冗長な (PK 削除後を除く) キー値を維持するためのトリガーまたは特定のコードが必要です。
カスケード削除は、論理的なスーパータイプおよびサブタイプのエンティティを物理データベースに実装する場合に非常に役立ちます。
スーパータイプ/サブタイプを物理的に実装するために個別のスーパータイプ テーブルとサブタイプ テーブルを使用する場合 (すべてのサブタイプ属性を 1 つの物理スーパータイプ テーブルにロールアップするのではなく)、1 対-これらのテーブル間の関係と問題は、これらのテーブル間で主キーを 100% 同期させる方法になります。
カスケード削除は、次の場合に非常に便利なツールです。
1) スーパータイプのレコードを削除すると、対応する単一のサブタイプのレコードも削除されることを確認してください。
2) サブタイプのレコードを削除すると、スーパータイプのレコードも削除されることを確認してください。これは、対応するスーパータイプ レコードを移動して削除するサブタイプ テーブルに「代わりに」削除トリガーを実装することによって実現されます。これにより、サブタイプ レコードがカスケード削除されます。
この方法でカスケード削除を使用すると、最初にスーパータイプ レコードを削除するかサブタイプ レコードを削除するかに関係なく、孤立したスーパータイプまたはサブタイプ レコードが存在しないことが保証されます。