多个`ON DELETE CASCADE`外键导致的死锁
Deadlock caused by multiple `ON DELETE CASCADE` Foreign Keys
我遇到了由 ON DELETE CASCADE
FK 链引起的死锁问题。
情况如下:
Table C
有 ON DELETE CASCADE
FK 到 B
.
Table B
有 ON DELETE CASCADE
FK 到 A
.
收到一个或多个请求,导致 SQL 语句 DELETE FROM A where A.id = @0 AND A.userId = @1
。
然而,由于级联的FK,为每个DELETE
语句生成了一个庞大的执行计划,一些操作员请求X
/IX
锁定B
/C
.
当多个删除语句同时尝试执行此操作时,会发生死锁。
有没有一种方法可以解决这个问题而无需重写一大堆删除方法(DB 使用了几个这样的 FK,不知道它会变成这样)到 SP 并手动删除相关表?
感谢任何帮助。
你的问题是 child table 上的外键没有索引 ,所以每个 DELETE
parent table 需要扫描整个 child table 以确保没有 FK 一致性问题。这似乎是造成死锁的原因。
给每个添加索引 child:
CREATE NONCLUSTERED INDEX IX_Parent ON Child (ParentID);
或
CREATE CLUSTERED INDEX IX_Parent ON Child (ParentID, SomeOtherCol);
所有主键和外键都有一个索引(以这些列作为前导键列)是必不可少的。
如果您缺少外键索引,那么您将在 UPDATE
和 DELETE
上针对 parent table 的主键遇到锁定问题。如果您缺少主键上的索引,那么您将在 INSERT
和 UPDATE
上遇到针对 child table.
的锁定问题
我注意到你的大多数 table 甚至没有聚簇索引,只是堆 table,另一个坏主意。
您可以添加其他列作为键的一部分或作为 INCLUDE,但 PK 或 FK 必须是索引中的前导列。
在this fiddle可以看到索引的效果。
我遇到了由 ON DELETE CASCADE
FK 链引起的死锁问题。
情况如下:
Table C
有 ON DELETE CASCADE
FK 到 B
.
Table B
有 ON DELETE CASCADE
FK 到 A
.
收到一个或多个请求,导致 SQL 语句 DELETE FROM A where A.id = @0 AND A.userId = @1
。
然而,由于级联的FK,为每个DELETE
语句生成了一个庞大的执行计划,一些操作员请求X
/IX
锁定B
/C
.
当多个删除语句同时尝试执行此操作时,会发生死锁。
有没有一种方法可以解决这个问题而无需重写一大堆删除方法(DB 使用了几个这样的 FK,不知道它会变成这样)到 SP 并手动删除相关表?
感谢任何帮助。
你的问题是 child table 上的外键没有索引 ,所以每个 DELETE
parent table 需要扫描整个 child table 以确保没有 FK 一致性问题。这似乎是造成死锁的原因。
给每个添加索引 child:
CREATE NONCLUSTERED INDEX IX_Parent ON Child (ParentID);
或
CREATE CLUSTERED INDEX IX_Parent ON Child (ParentID, SomeOtherCol);
所有主键和外键都有一个索引(以这些列作为前导键列)是必不可少的。
如果您缺少外键索引,那么您将在 UPDATE
和 DELETE
上针对 parent table 的主键遇到锁定问题。如果您缺少主键上的索引,那么您将在 INSERT
和 UPDATE
上遇到针对 child table.
我注意到你的大多数 table 甚至没有聚簇索引,只是堆 table,另一个坏主意。
您可以添加其他列作为键的一部分或作为 INCLUDE,但 PK 或 FK 必须是索引中的前导列。
在this fiddle可以看到索引的效果。