我在下面这两个表上执行DELETE操作,然后执行INSERT操作,但偶尔会遇到死锁.

Schedule.Assignments (Parent table)

[Schedule.Assignments(父表)]

1

Schedule.Schedules (Child table)

[Schedule.Schedules(子表)]

2

在计划上间歇性地发生两种类型的死锁.计划表(子),尽管操作是在计划上执行的.分配表(父).两者具有相同的死锁图,如下所示.

  1. Schedule.Assignments表上INSERT和DELETE语句之间的死锁.

  2. Schedule.Assignments表上相同的Delete语句之间出现死锁.

[死锁图]

3

Deadlock Graph1 : https://pastebin.com/raw/ZpQUrjBV
Deadlock Graph2 : https://pastebin.com/raw/DhnuyZ7a

包含INSERT和DELETE语句的StoredProc:https://pastebin.com/raw/6DNh2RxH

查询执行计划:PasteThePlan

[Edit]

Assignments Schema: Assignments Schema

作业(job)指数:Assignments Indexes

时间表方案:Schedules Schema

排行榜指数:Schedules Indexes

我不能理解的是,为什么死锁对象显示为子表,而死锁中涉及的进程显示父表上的插入/删除.

请分享你的 idea ,如何解决这些僵局?

推荐答案

看起来您的死锁是由Schedules上的大表扫描引起的.扫描在您的程序中的三个不同位置进行.相反,应该发生的是简单的Nested Loops/Index SeekParentId.

进行扫描的原因是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可能无论如何都不是必要的.

Sql相关问答推荐

当编号和版本的唯一状态更改时报告

Postgresql在加入时显示重复的行

帮助修复查询以识别SQL DW中数据中的递归关系

如何实现一个广泛的多级自连接PostgreSQL查询?

将有界时间周期作为阶跃函数,其中周期开始返回1,周期结束返回0

查询多个表并返回合并在联合列上的所有表中的所有行

从列的不同值创建列

Lag()函数的差异:R与SQL(将R代码转换为SQL)

使用WHERE子句进行筛选时,SQL SELECT查询返回总计数

如何在postgres函数中插入后返回布尔值?

替换上一个或下一个值中的空值并添加其价格日期

使用DatePart函数对日期时间值进行分组

仅当交叉应用返回单值时才更新记录

如何解释 SQL Server 中的 Foxpro 语法?

Snowflake中的动态SQL优化

将有效数字作为 varchar 返回的 SQL 函数

Select 多年的日期范围

以 15 分钟为间隔的使用情况SQL 查询

在 PostgreSQL 中,如何将数组中的每个元素用作另一个表中的键?

BigQuery 将一行拆分为多列