いつ/なぜSQL Serverでカスケードを使用するのですか?


149

SQL Serverで外部キーを設定する場合、どのような状況で削除または更新時にカスケードする必要がありますか?その背後にある理由は何ですか?

これはおそらく他のデータベースにも当てはまります。

私は、各シナリオの具体的な例として、できればそれらをうまく使用した人からの検索をしています。


4
この質問はSQL Serverに厳密に関連していないようで、理論的で一般的な質問のように見えます。sql-serverタグを削除すると、コミュニティにとってより便利になります。
clapas 2013

4
@clapas正直なところ、私が今日尋ねると、話題から外れるでしょう。コミュニティにとって価値があることを示す高いビュー/投票がない場合は、削除します。
Joel Coehoorn 2013

6
@JoelCoehoorn-明らかにこれらのタイプの質問には価値があります。この値は、時間の経過によって失われることはありません。私の頭の中での質問は、今日そのような質問を拒否することでどれだけの価値を失うのかということです。
P.Brian.Mackey 2017年

2
@ P.Brian.Mackeyこちら、こちら!私が見た中で最も良い質問/回答のいくつかは、反対票を投じられた、またはトピックから外れていると描かれたものです...しかし、多くの人がまったく同じ質問を持っていたことの膨大な数の賛成票からわかるでしょう!
Anthony Griggs、2017年

カスケードアクションは、シリアル化可能なロックを取得します。
ミッチウィート

回答:


126

これまでに見てきたことの要約:

  • 一部の人々は、カスケードがまったく好きではありません。

カスケード削除

  • カスケード削除は、関係のセマンティクスに排他的な「の一部」の説明が含まれる可能性がある場合に意味があります。たとえば、OrderLineレコードはその親注文の一部であり、OrderLineが複数の注文間で共有されることはありません。Orderが消える場合、OrderLineも同様にはずであり、Orderのない行が問題になります。
  • カスケード削除の標準的な例は、SomeObjectとSomeObjectItemsです。この場合、対応するメインレコードがなければ、アイテムレコードが存在しても意味がありません。
  • あなたはすべきではない、あなたが歴史を保存または使用している場合は、DELETE CASCADEを使用して「ソフト/論理削除」あなただけの1 / trueに削除されたビット列を設定しています。

カスケード更新

  • カスケード更新は、テーブル間で代理キー(ID /自動インクリメント列)ではなく実際のキーを使用する場合に意味があります。
  • カスケード更新の標準的な例は、変更可能なユーザー名などの変更可能な外部キーがある場合です。
  • Identity / autoincrementカラムであるキーでカスケード更新を使用しないでください。
  • カスケード更新は、一意の制約と組み合わせて使用​​するのが最適です。

カスケードを使用する場合

  • 操作のカスケードを許可する前に、ユーザーからさらに強力な確認を取得することもできますが、これはアプリケーションによって異なります。
  • 外部キーを間違って設定すると、カスケードによって問題が発生する可能性があります。しかし、それを正しく行えば、大丈夫です。
  • 完全に理解する前にカスケードを使用することは賢明ではありません。ただし、これは便利な機能であるため、時間をかけて理解する価値があります。

3
カスケード更新は、「いわゆる」自然キーが実際に有効な一意キーではないように見える場合にもよく使用されます。実際、カスケード更新は正規化が不十分なデータベースモデルでのみ必要であり、乱雑なテーブルや乱雑なコードへのオープンゲートであると私は確信しています。
フィリップグロニエ2008年

1
欠落している重要な点が1つあります。子レコードが多い場合、カスケードするとパフォーマンスに大きな問題が発生する可能性があります。
HLGEM 2010年

13
@HLGEM-関連性がわかりません。カスケード操作がスローダウンを引き起こす場合、トランザクションをロールバックする必要がある場合、同等の手動プロセスが同じスローダウンを引き起こすか、正しく保護されません。
Joel Coehoorn、2010年

3
IDENTITY列または自動インクリメント列にカスケード更新があるかどうかが重要なのはなぜですか?これらの(任意の)値を変更する必要がないので、なぜそれが必要ではないのかわかりますが、それらの1つ変更された場合、少なくとも参照整合性は損なわれません。
ケニーエビット

3
10弾?さて、ジョエルがリボルバーを発射していないことがわかりました。
Neil N

68

外部キーは、データベースの参照整合性を保証するための最良の方法です。魔法のせいでカスケードを回避することは、コンパイラの背後にある魔法を信頼しないので、アセンブリですべてを書くようなものです。

悪い点は、例えば、逆にそれらを作成するような外部キーの間違った使い方です。

Juan Manuelの例は標準的な例です。コードを使用すると、データベースに偽のDocumentItemが残り、あなたに噛まれる可能性が高くなります。

カスケード更新は、たとえば、ユーザーテーブルの主キーが名前と姓の組み合わせであるなど、変更可能なものによってデータへの参照がある場合に役立ちます。次に、その組み合わせの変更を参照先に反映させます。

@Aidanは、あなたはを参照することを明快には、高コストであるデータベースに偽のデータを残すチャンス来る小さくはないが。私にとって、それは通常、DBに精通していないことと、DBを操作する前にどのFKが配置されているかを見つけることができないことがその恐れを助長していることです。それ、またはカスケードの継続的な誤用、エンティティが概念的に関連していない場所、または履歴を保持する必要がある場所でのカスケードの使用。


7
そのような「自然な」主キーを使用することは、そもそも非常に悪い考えです。
Nick Johnson、

4
RE:エイダン宛てのコメント。いいえ、FKでCASCADEをオフにしても、偽のデータが残る可能性は高くなりません。予想よりも多くのデータがコマンドの影響を受ける可能性を減らし、コードを増やします。FKを除外すると、誤ったデータの可能性が完全に残ります。
シャノン退職

5
私のキャリアの中で少なくとも2回、誤解されたカスケード削除のビジネスを脅かす結果を見たので、最も明確なカットケースを除いてすべて自分でそれらを使用することに非常に消極的です。どちらの場合も、カスケードの結果としてデータは削除されていましたが、実際には保持されるべきでしたが保持されませんでした。また、データが欠落していたことは、通常のバックアップサイクルが簡単な復元の可能性を失うまで検出されませんでした。ビンコは純粋に論理的な観点からは正しいですが、カスケードを使用する現実の世界では、人間が誤っている可能性と予期しない結果に私が望む以上にさらされています。
Cruachan、

1
ユーザーがマスターを削除する前に、マスター詳細のすべての子を明示的に削除する必要があるという管理上の決定が行われたシステムを実際にコーディングしました。論理的に可能な場合にカスケードを使用しないことは、同様の種類の防火帯です。
Cruachan、

6
@Cruachan:私の考えでは、ルールは単純です。データが親データなしでは役に立たないほど強く関連していない場合、カスケード関係は保証されません。これは私が私の答えの最後のフレーズで対処しようとしたことです。
Vinko Vrsalovic

17

カスケード削除は使用しません。

データベースから何かを削除したい場合は、取り出したいものをデータベースに明示的に伝えたいです。

もちろん、それらはデータベースで使用可能な関数であり、それらを使用しても問題ない場合があります。たとえば、「order」テーブルと「orderItem」テーブルがある場合、削除するときにアイテムをクリアすることができます。注文。

「マジック」が発生するのではなく、コード(またはストアドプロシージャ)でそれを行うことで得られる明快さが好きです。

同じ理由で、私もトリガーのファンではありません。

注目すべき点は、「order」を削除すると、カスケード削除によって50個の「orderItem」が削除された場合でも、「1行の影響」レポートが返されることです。


34
主キーも削除しませんか?コード内で一意の値を確保することが明確になります。
MusiGenesis 2008年

4
@ MusiGenesis、AidanはFKの削除を主張していませんでした。FKは引き続きデータを保護しますが、CASCADE ONがなければ...予期しない魔法は起こりません。
シャノン退職

7
@Vinko:削除と更新には、明確に定義されたデフォルトのセマンティクスがあります。カスケードまたはトリガーを介して動作を変更してより多くの作業を行うと、意図したよりも多くのことが行われた可能性があります。いいえ、私はテストなしで作業することはありません。そうです、私のデータベースは文書化されています。しかし、コードを記述している間、すべてのドキュメントを覚えていますか?親と子を削除するなど、より高いレベルのセマンティクスが必要な場合は、SPを記述して使用します。
シャノン退職

3
@Vinko。魔法の問題は有能な開発者やDBAの問題ではありません。5年後、DBAが休暇中に「シンプルな」保守タスクを与えられ、誰も気づかないうちに企業データを台無しにしてしまうJoe interenの問題です。カスケードはその場所にありますが、展開する前に、ヒューマンファクターを含む完全な状況を考慮することが重要です。
Cruachan、

5
@Vinko:なぜ「Gasp」SPなのですか?SPは、データベースが重要な企業資産であるところへの挑戦的な方法です。SPへのすべてのデータアクセス、または少なくともSelect以外のすべてへのアクセスを制限することについて話していたような状況では、強い議論があります。stackoverflow.com/questions/1171769/…の
Cruachan

13

私はカスケード削除でよく働きます。

データベースに反対する誰もが不要なデータを残さない可能性があることを知っておくのは良いことです。依存関係が大きくなった場合は、Management Studioのダイアグラムで制約を変更するだけで、spやdataaccesを微調整する必要はありません。

とはいえ、削除のカスケードと循環参照に関する問題が1つあります。これにより、データベースの一部に連鎖的な削除がないことがよくあります。


1
私はこれが非常に古いことを知っていますが、CASCADE DELETEでの循環参照の問題に言及するための+1です。
Code Maverick

2
noobの質問を許してください:循環参照を取得した場合、実際にはどうなりますか?
Tim Lovell-Smith

10

私は多くのデータベース作業を行っており、カスケード削除が役立つとは限りません。私がそれらを効果的に使用したのは、夜間のジョブによって更新されるレポートデータベースの場合です。前回のインポート以降に変更された最上位のレコードを削除して、変更されたデータが正しくインポートされることを確認します。次に、変更されたレコードとそれらに関連するものを再インポートします。データベースの下部から上部に向かって複雑な削除をたくさん書く必要がなくなります。

カスケード削除はデータを削除するだけなので、トリガーと同じくらい悪いとは考えていません。トリガーはあらゆる種類の厄介なものを内部に持つことができます。

一般に、私は実際の削除を完全に回避し、代わりに論理削除(つまり、trueに設定されるisDeletedと呼ばれるビット列を持つ)を使用します。


2
あなたは私をもっと知りたいと思った。なぜ論理削除を強く好むのですか?作業しているデータは、それと何か関係がありますか?
Tim Lovell-Smith

9

1つの例は、エンティティ間に依存関係がある場合です。つまり、Document-> DocumentItems(Documentを削除する場合、DocumentItemは存在する理由がありません)


5

参照するPKレコードが削除された場合にFKのあるレコードを削除する場合は、カスケード削除を使用します。つまり、参照するレコードがないと、レコードは無意味です。

カスケード削除は、無効な参照をnull例外を発生させるのではなく、デフォルトで確実に削除するのに役立ちます。


5

カスケードの削除:

あなたがしたい場合は、子テーブルの行を削除する場合は、対応する行が削除された親テーブルで。

カスケード削除を使用しない場合、参照整合性のためにエラーが発生します

カスケード更新:

主キーの変更を更新したい場合外部キー


5

DBAや "会社のポリシー"で、 "On Delete Cascade"(およびその他)の使用を純粋に禁止していると聞いたことがあります。あるケースでは、ある男が3つのトリガーを作成し、その結果、お互いを呼び出しました。3日間の回復により、トリガーの全面的な禁止が行われました。これは、すべて1つのイジットのアクションによるものです。

もちろん、一部の子データを保持する必要がある場合など、「削除時のカスケード」の代わりにトリガーが必要になる場合があります。しかし、他の場合では、On Deleteカスケードメソッドを使用することが完全に有効です。「削除時カスケード」の主な利点は、すべての子をキャプチャすることです。カスタムで記述されたトリガー/ストアプロシージャは、正しくコーディングされていない場合、失敗する可能性があります。

開発者には、開発内容と仕様に基づいて決定を下すことを認めるべきだと思います。悪い経験に基づくカーペットの禁止は、基準とすべきではありません。「使用しない」思考プロセスは、せいぜい厳格です。毎回、判断を下す必要があり、ビジネスモデルの変化に応じて変更を加える必要があります。

これが開発のすべてではありませんか?


私はそれがすべてを削除するとは思わなかった...あなたは機能が実際にそれが行うと言うことを行うことを意味しますか?...
Joel Coehoorn 2014年

3

(コードで行うのではなく)カスケード削除を行う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'

5
使用するデータベースがわからないので、手動での削除はカスケード削除よりもパフォーマンスが悪いことをお勧めします。ほとんどのデータベースでは、別のテーブルへの結合に基づいて削除できるため、レコードをループするよりも、セットベースではるかに高速に削除できます。
HLGEM 2008年

2

SQLサーバーで明示的に要求しなかった削除または更新を回避しようとしています。

カスケードまたはトリガーを使用する。彼らは、バグを追跡しようとするとき、またはパフォーマンスの問題を診断するときのいずれかの時点で、いつかお尻を噛む傾向があります。

それらをどこで使用するかは、あまり努力を払わずに一貫性を保証することです。同じ効果を得るには、ストアドプロシージャを使用する必要があります。


2

私は、他のすべての人と同様に、カスケード削除がほんのわずかしか役に立たないことを発見しました(他のテーブルの参照データを削除するのはそれほど多くの作業ではありません-テーブルがたくさんある場合は、スクリプトでこれを自動化するだけです)。誰かが誤ってカスケードすると、復元が困難ないくつかの重要なデータが削除されます。

私が使用する唯一のケースは、テーブルテーブルのデータが高度に制御されており(たとえば、制限されたアクセス許可)、検証された制御されたプロセス(ソフトウェアの更新など)からのみ更新または削除された場合です。


1

Rのいくつかのタプルで見つかった外部キー値を削除するSの削除または更新は、次の3つの方法のいずれかで処理できます。

  1. 拒絶
  2. 伝搬
  3. 無効化。

伝播はカスケードと呼ばれます。

2つのケースがあります。

S Sのタプルが削除された場合、それを参照していたRタプルを削除します。

S Sのタプルが更新された場合、それを参照するRタプルの値を更新します。


0

異なるバージョンの多数の異なるモジュールを含むシステムで作業している場合、カスケード削除されたアイテムがPKホルダーの一部であるか、PKホルダーによって所有されていると、非常に役立ちます。そうしないと、すべてのモジュールでPK所有者を削除する前に依存アイテムをクリーンアップするための即時パッチが必要になるか、外部キー関係が完全に省略され、クリーンアップが正しく実行されない場合、システムに大量のゴミが残る可能性があります。

カスケード削除がかなり前から推奨されていなかった後、2つの既存のテーブル間の新しい交差テーブル(削除する交差のみ)にカスケード削除を導入しました。データが失われたとしても、それほど悪くはありません。

ただし、列挙型のようなリストテーブルでは悪いことです。誰かがエントリ13-テーブル「色」から黄色を削除し、データベース内のすべての黄色のアイテムが削除されます。また、これらは時々delete-all-insert-allの方法で更新されるため、参照整合性が完全に省略されます。もちろんそれは間違っていますが、真の参照整合性の導入が予期しない副作用のリスクがある状態で、長年実行されている複雑なソフトウェアをどのように変更しますか?

別の問題は、主キーが削除された後でも元の外部キー値が保持される場合です。元のFKにトゥームストーン列とON DELETE SET NULLオプションを作成できますが、これにもトリガー(またはPK削除後を除く)のキー値を維持するための特定のコードが必要です。


0

カスケード削除は、物理データベースに論理スーパータイプおよびサブタイプのエンティティを実装する場合に非常に役立ちます。

個別のスーパータイプテーブルとサブタイプテーブルを使用してスーパータイプ/サブタイプを物理的に実装する場合(すべてのサブタイプ属性を単一の物理スーパータイプテーブルにロールアップするのではなく)、1対1 -これらのテーブルと問題の1つの関係は、これらのテーブル間で主キーを100%同期させる方法になります。

カスケード削除は、次の場合に非常に役立つツールです。

1)スーパータイプのレコードを削除すると、対応する単一のサブタイプのレコードも削除されることを確認してください。

2)サブタイプのレコードを削除すると、スーパータイプのレコードも削除されることを確認してください。これは、サブタイプテーブルに "instead-of"削除トリガーを実装して、対応するスーパータイプレコードを削除することで実現されます。これにより、サブタイプレコードがカスケード削除されます。

この方法でカスケード削除を使用すると、スーパータイプレコードを最初に削除するか、サブタイプレコードを最初に削除するかに関係なく、孤立したスーパータイプまたはサブタイプレコードが存在しないことが保証されます。


良い例え。JPAでは、これはInheritanceStrategy Joined Tableです。1)の場合:通常、永続化レイヤーフレームワーク(EclipseLink、Hibernateなど)を使用します。これは、結合エンティティの削除シーケンスを実装して、最初に結合パーツを削除し、次にスーパーパーツを削除します。ただし、インポートジョブやアーカイブジョブなど、より基本的なソフトウェアを導入している場合は、スーパーパーツに削除を発行することでエンティティを削除できるので便利です。2)について:同意しますが、その場合、クライアントはエンティティの結合/サブパーツに取り組んでいることをすでに認識している必要があります。
レオ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.