18

SQL Server 2005 で、悪名高いエラー メッセージが表示されました。

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

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

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

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

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

他の SO トピックでは、カスケードの使用を「危険」とラベル付けし、「カスケード パスの解決は複雑な問題です」と述べています。なんで?リスクはどこにありますか?問題はどこだ?

4

6 に答える 6

4

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

何が優先されますか?その後、何を期待していますか?等

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

于 2009-10-31T19:25:12.153 に答える
2

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

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

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

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

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

于 2009-10-28T15:32:28.250 に答える
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";

おっと。誰もが解雇されました!

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

于 2009-10-30T05:16:39.897 に答える
0

カスケードが「危険」であり、避けるべきであることに同意します。(個人的には、変更を手動でカスケードするほうが、SQL サーバーに自動的に処理させるよりも好きです)。これは、SQL サーバーが数百万行を削除した場合でも、出力が次のように表示されるためです。

(1 行が影響を受けます)

于 2009-10-28T15:04:25.167 に答える
-1

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

于 2010-10-27T07:21:48.983 に答える