外部キーカスケードの複数のパスとサイクルの問題は何ですか?
-
08-07-2019 - |
質問
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データベースシステムは、このような制限を課していません。