質問

MSSQL 2005では、悪名高いエラーメッセージを見つけました。

  

テーブルYYYにFOREIGN KEY制約XXXを導入すると、サイクルまたは複数のカスケードパスが発生する場合があります。 ON DELETE NO ACTIONまたはON UPDATE NO ACTIONを指定するか、他の外部キー制約を変更します。

今、StackOverflowにはこのエラーメッセージに関するいくつかのトピックがありますので、解決策は既に得ています(私の場合はトリガーを使用する必要があります)が、なぜこのような問題が発生するのか興味があります。

私が理解しているように、基本的に回避したいシナリオは2つあります。1つのサイクルと複数のパスです。サイクルは、2つのテーブルが互いに外部キーをカスケードしている場合です。サイクルは複数のテーブルにまたがることもできますが、これは基本的なケースであり、分析が容易になります。

TableAにはTableBとTableCへの外部キーがあり、TableBにはTableCへの外部キーもある場合、複数のパスになります。繰り返しますが、これは最低限の基本的なケースです。

これらのテーブルのいずれかでレコードが削除または更新されたときに発生する問題を確認できません。確かに、どのレコードを更新/削除する必要があるかを確認するために同じテーブルを複数回クエリする必要があるかもしれませんが、それは本当に問題ですか?これはパフォーマンスの問題ですか?

他のSOトピックでは、カスケードを使用して" 危険" " カスケードパスの解決は複雑な問題"。どうして?リスクはどこにありますか?問題はどこにありますか?

役に立ちましたか?

解決

同じ親からの2つのカスケードパスを持つ子テーブルがあります。1つは「削除」、もう1つは「null」です。

何が優先されますか?その後何を期待しますか?など

注意:トリガーはコードであり、カスケードにインテリジェンスまたは条件を追加できます。

他のヒント

カスケード削除の使用を禁止する理由は、パフォーマンスとロックに関係しています。はい、1つのレコードを削除してもそれほど悪くはありませんが、遅かれ早かれ、大量のレコードを削除する必要があり、データベースが停止します。

十分なレコードを削除している場合、SQL Serverはテーブルロックにエスカレートする可能性があり、テーブルが完了するまで誰もテーブルを操作できません。

最近、クライアントの1つを自分のサーバーに移動しました。取引の一環として、元のサーバーからそのクライアントのレコードをすべて削除する必要もありました。 (他のユーザーに問題が発生しないように)彼のすべての情報を一括で削除するには、数か月かかりました。カスケード削除を設定した場合、1つのトランザクションで数百万のレコードが削除され、トランザクションが完了するまで数百のテーブルがロックされたため、他のクライアントはデータベースに長時間アクセスできませんでした。

カスケード削除の使用中にデッドロックが発生した可能性があります。これは、カスケードパスの順序を制御できないため、ほとんどのテーブルに表示されるclientidでデータベースが多少非正規化されているためです。したがって、外部キーを持つ1つのテーブルを、3番目のテーブルと異なるパスにあるクライアントテーブルにもロックした場合、3番目のテーブルから削除するためにそのテーブルをチェックできなかった可能性があります。 1つのトランザクションとロックは、完了するまで解放されません。そのため、トランザクションでデッドロックが発生する可能性がある場合、カスケード削除を設定できなかった可能性があります。

カスケード削除を回避するもう1つの理由は、子レコードの存在が親レコードを削除しない理由である場合があることです。たとえば、顧客テーブルがあり、その顧客が過去に注文したことがある場合、彼を削除して実際の注文に関する情報を失いたくないでしょう。

従業員の表を検討する:

CREATE TABLE Employee
(
    EmpID   INTEGER NOT NULL PRIMARY KEY,
    Name    VARCHAR(40) NOT NULL,
    MgrID   INTEGER NOT NULL REFERENCES Employee(EmpID) ON DELETE CASCADE
);

INSERT INTO Employees(     1, "Bill",   1);
INSERT INTO Employees(    23, "Steve",  1);
INSERT INTO Employees(234212, "Helen", 23);

今、ビルが引退したとします:

DELETE FROM Employees WHERE Name = "Bill";

Ooooppps;全員解雇されました!

[構文の詳細が正しいかどうかを議論できます。コンセプトは立っていると思います。]

問題は、1つのパスを「ON DELETE CASCADE」にすると、その他の「ON DELETE RESTRICT」、または「NO ACTION」結果(結果)は予測不能です。どの削除トリガー(これもトリガーですが、自分でビルドする必要はありません)が最初に実行されるかどうかによって異なります。

カスケードが「危険」であることには同意します。避けるべきです。 (個人的には、SQLサーバーが自動的に変更を処理するのではなく、変更を手動でカスケードすることを好みます)。これは、SQLサーバーが数百万行を削除しても、出力が

として表示されるためです。

(1行が影響を受けました)

ON DELETE CASCADEオプションを使用するかどうかは、実装するビジネスモデルの問題だと思います。 2つのビジネスオブジェクト間のリレーションシップは、リレーションシップの両端が関連する単純な「アソシエーション」の場合もありますが、それ以外の場合はライフサイクルが異なり、他のロジックによって制御される独立したオブジェクトです。ただし、「集計」もあります。関係。1つのオブジェクトが実際に「親」と見なされる場合があります。または「所有者」 「子供」のまたは" detail"オブジェクト。 「組成物」という概念はさらに強力です。関係。オブジェクトは、多数の部分の構成としてのみ存在します。 「関連付け」では、通常、ON DELETE CASCADE制約は宣言しません。ただし、集計または構成の場合、ON DELETE CASCADEを使用すると、ビジネスモデルをより正確に宣言的な方法でデータベースにマッピングできます。 これが、MS SQL Serverがこのオプションの使用を単一のカスケードパスに制限していることを悩ませている理由です。誤解しない限り、他の多くの広く使用されているSQLデータベースシステムは、このような制限を課していません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top