私はカスケード削除を使用したことはありません(また、正当な必要性もありませんでした)。また、これを強制するためにトリガーを使用したこともありません。これの主な理由は、通常、次のとおりです。
- アプリでは削除も許可されていません。削除済みのマークが付けられているか、すべての時間で時間的に一貫しており、発効日や終了日などがあります。
- 親が誤って削除された場合、それらに関連付けられているすべてのものが単に消えるわけではないことを知りたいので、削除をカスケードせずにRIを使用すると、依存関係のツリー全体を削除できなくなります。
- アプリケーションとデータベースの設計で、エンティティの相互依存性についてより慎重になり、構造とプロセスの両方を適切にリファクタリングできるようにします。
- エンティティに適切な削除手順を強制的に作成することで、すべてのステップの順序を選択し、デッドロックを回避できる可能性があります。また、クエリが調整されていることを確認できます。
私が見ることができるカスケード削除の唯一の利点は、それが宣言型であり、テーブルで定義されており、おそらく可能な限り最小のロックエスカレーションフットプリントを持つことです。上記の利点は、私の見解ではその使用を上回ります。
2番目の例のように、トランザクション(通常はストアドプロシージャ)で囲みます。
DELETE FROM child WHERE child.fk IN (set to delete);
DELETE FROM parent WHERE parent.pk IN (set to delete);
何らかの理由で子または親をすべて削除できない場合、つまり、削除で考慮されていない子または親への別のFK参照があった場合、トランザクション全体がデータベースを一貫した状態のままにして成功するか、変更をコミットできません。 。
データベースは、常に参照整合性を保証します。
USE SandBox
GO
IF EXISTS ( SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'Child')
AND type IN ( N'U' ) )
DROP TABLE dbo.Child
GO
IF EXISTS ( SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'Parent')
AND type IN ( N'U' ) )
DROP TABLE dbo.Parent
GO
CREATE TABLE Parent
(
PK INT NOT NULL
IDENTITY
,Nm VARCHAR(15)
,PRIMARY KEY ( PK )
)
GO
CREATE TABLE Child
(
PK INT NOT NULL
IDENTITY
,FK INT NOT NULL
,Nm VARCHAR(15)
,PRIMARY KEY ( PK )
)
GO
ALTER TABLE Child
WITH CHECK
ADD CONSTRAINT FK_Child_Parent FOREIGN KEY ( FK ) REFERENCES Parent ( PK )
GO
DECLARE @LastParent AS INT
INSERT INTO Parent ( Nm )
VALUES ( 'Donald Duck' )
SET @LastParent = SCOPE_IDENTITY()
INSERT INTO Child ( FK, Nm )
VALUES ( @LastParent, 'Huey' )
INSERT INTO Child ( FK, Nm )
VALUES ( @LastParent, 'Dewey' )
INSERT INTO Child ( FK, Nm )
VALUES ( @LastParent, 'Louie' )
SELECT *
FROM Parent
SELECT *
FROM Child
GO
BEGIN TRANSACTION
DELETE FROM Child
WHERE FK = ( SELECT PK
FROM Parent
WHERE Nm = 'Donald Duck'
)
-- Run just to here
-- In another session do this:
-- INSERT INTO Child (FK, Nm) VALUES ((SELECT PK FROM Parent WHERE Nm = 'Donald Duck'), 'Cuckoo')
-- Then return here
DELETE FROM Parent
WHERE Nm = 'Donald Duck' -- Should fail
IF @@ERROR <> 0
ROLLBACK TRANSACTION
ELSE
COMMIT TRANSACTION
SELECT *
FROM Parent
SELECT *
FROM Child