我在下面这两个表上执行删除,然后执行插入,但遇到间歇性死锁。
Schedule.Assignments(父表)
Schedule.Schedules(子表):
尽管正在schedule.Schedules
表(父表)上执行操作,但
schedule.Assignments
表(子表)上间歇性地发生两种类型的死锁。两者都有相同的死锁图,如下所示。
schedule.Assignments
表上的Insert和Delete语句之间出现死锁。
schedule.Assignments
表上的相同删除语句之间出现死锁。
Deadlock Graph1 : https://pastebin.com/raw/ZpQUrjBV
Deadlock Graph2 : https://pastebin.com/raw/DhnuyZ7a
包含插入和删除语句的存储过程:https://pastebin.com/raw/6DNh2RxH
查询执行计划:[编辑]
作业架构:作业索引:计划架构:时间表索引:我无法理解为什么死锁对象显示为子表,而死锁涉及的进程显示父表上的插入/删除。请分享您对如何解决这些僵局的想法?
Schedules
上的大表扫描引起的。扫描发生在手术过程中的三个不同位置。相反,应该发生的是
Nested Loops
上的简单
Index Seek
/
ParentId
。您进行扫描的原因是因为
ParentId
上的连接条件位于
nvarchar(50)
列和
bigint
之间。我建议您通过将
ParentId
设为
bigint
来解决此问题。
ALTER TABLE schedule.Schedules
ALTER COLUMN ParentId bigint NULL;
执行此操作时,您可能需要删除并重新创建索引或约束。
schedule.Assignments (OldResourceRequestId)
上有一个索引,但它并不是唯一的。这会导致各个子查询出现
Assert
,以确保只返回一行,并且还可能影响查询统计/估计。我建议您将其更改为唯一索引(如果可能)。如果存在重复项,那么您无论如何都需要重新考虑这些连接,因为您会得到重复的结果或失败
Assert
。
CREATE NONCLUSTERED INDEX [IX_Assignments_OldResourceRequestId] ON schedule.Assignments
(
OldResourceRequestId ASC
)
WITH (DROP_EXISTING = ON, ONLINE = ON) ON PRIMARY;
IF
陈述。它们没有缩进,并且不清楚实际发生的情况是,由于缺少
BEGIN
END
,只有后面的第一个语句是有条件的。正如另一个答案中提到的,无论如何,
IF
可能都没有必要。
我不确定这些改变是否会消除问题,但在我看来,它们会降低这种可能性。您可以通过减少语句数量来增加原子性,并通过消除分支来强制过程的每次调用执行完全相同的逻辑序列。