我面临两个表 Table1 和 Table2 之间的死锁。
当一个 sp (sp2) delete from table2 而其他 sp (sp1) 尝试更新 table1 时,就会发生死锁。
在 table2 中删除它的列是 table1 的主键,但是由于设计不好,从未添加外键,即 table2 没有对 table1 的引用,但是从 table2 中删除时会产生排他锁表 1。那么引擎如何在没有 FK 的情况下知道引用呢?
CREATE TABLE [dbo].[Table2] (
[IdTable1] INT NOT NULL,
[IdTable3] INT NOT NULL,
[Sent] BIT CONSTRAINT [DF_Table2_Sent] DEFAULT ((0)) NOT NULL,
[Order] VARCHAR (50) CONSTRAINT [DF_Table2_NewID] DEFAULT (newid()) NOT NULL,
[ToExclude] BIT CONSTRAINT [DF_Table2_ToExclude] DEFAULT ((0)) NOT NULL,
CONSTRAINT [PK_Table2] PRIMARY KEY CLUSTERED ([IdTable1] ASC, [IdTable3] ASC) WITH (FILLFACTOR = 100) ON [FG2]
);
GO
CREATE NONCLUSTERED INDEX [IX_Table2_IdTable1_Sent]
ON [dbo].[Table2]([IdTable1] ASC, [Sent] ASC, [Order] ASC)
INCLUDE([IdTable3]) WITH (FILLFACTOR = 100)
ON [FG2];
这是死锁的细节。https://justpaste.it/700ik
此外,这些表位于不同的文件组(不同的文件)
为什么是这样?
另外,如果我有 FK,如果我只是从 table2 中删除,为什么还需要检查 table1 中的 PK?
编辑感谢乔希的回答。
现在我有 SP2 作为
CREATE PROCEDURE SP2 @value
AS
IF @value = 1
UPDATE dbo.Table1.....
else
BEGIN
EXEC SP3 --This SP update Table1
DELETE FROM Table2...
END
现在为了避免保持对表 1 的锁定,我可以添加如下事务以在 SP3 完成时释放对表 1 的锁定吗?
CREATE PROCEDURE SP2 @value
AS
IF @value = 1
UPDATE dbo.Table1.....
else
BEGIN
BEGIN TRAN T1
EXEC SP3 --This SP update Table1
COMMIT TRAN T1
DELETE FROM Table2...
END
谢谢。
查看死锁信息的一个子集:
这表明会话 342 当前正在执行存储过程的第 47 行
dbo.SP2
,该行是DELETE
关于 的语句dbo.Table2
。在该过程之前的某处,该会话已经获得了对 的
X
独占(密钥)锁定dbo.Table1
。基于非零的“已使用日志”值,似乎此过程对 进行了一些写入dbo.Table1
,从而获得了X
锁并可能产生死锁。这里的要点是死锁 XML 仅向您显示当前正在执行的语句(Erik Darling在他的博客上有一些关于死锁图的精彩演示和其他令人困惑的事情)。在这个存储过程中,一个事务中似乎有多个语句正在执行。
另一种可能性是,这些表中的一个上有一个触发器导致比 T-SQL 语句本身明显的锁更多。
你是对的,即使外键存在于 上,也不需要
Table2
锁定来从 中删除行。如果 FK 被定义为“向后”并且启用了级联删除,则需要锁定。Table1
Table2