关于SqlServer高并发死锁现象的分析排查

news2024/11/30 0:31:55
问题描述

通过定期对生产环境SqlServer日志的梳理,发现经常会出现类似事务与另一个进程被死锁在资源上,并且已被选作死锁牺牲品,请重新运行该事务的异常,简单分析一下原因:在高并发场境下,多个事务同时对某个资源进行持锁 [ 读/写 ] 操作,同时又需要对方释放锁资源,进而出现死锁

下面将通过一个简单的案例来重现这种异常,了解了死锁的原因后,我们在写sql语句、创建索引时,就可以有效避免掉这些坑

创建表
CREATE TABLE [dbo].[t_test](
    [id] [int] NOT NULL,           --主键
    [name] [varchar](50) NULL,     --名称
    [age] [bigint] NULL,           --年龄
    [address] [varchar](50) NULL,  --地址
CONSTRAINT [PK_t_test] PRIMARY KEY CLUSTERED([id] ASC)
添加索引
# 在name列上创建非聚集索引,包含列为age
CREATE UNIQUE NONCLUSTERED INDEX [index_name] ON [dbo].[t_test]([name] ASC) INCLUDE ([age]);
CREATE UNIQUE CLUSTERED INDEX [index_id] ON [dbo].[t_test]([id] ASC);

include 可以指定多个列字段,通常把 select 查询的列放到 include 中,好处是索引查找的开销较小

准备数据
insert into t_test values (1, '张三', 21, '上海市徐汇区');
insert into t_test values (2, '李四', 19, '浙江省杭州市');
insert into t_test values (3, '王五', 28, '湖北省武汉市');
查看执行计划

开始测试之前,我们先通过SqlServer的 执行计划 来了解一下本案例涉及的 select 和 update 操作背后的详细过程

select操作
SELECT address FROM t_test WHERE name = '张三'

执行计划如下:
在这里插入图片描述
如上图,因使用非聚集索引name做为where条件查询,且select查找的address字段不包含在该索引字段上,所以需要根据Index Seek输出的id[聚集键]在具有聚集索引的表中查找对应的行,从面找到address列,我们常称做 回表查询

update操作
UPDATE t_test SET age=age+1 WHERE id = 1

执行计划如下:
在这里插入图片描述
过程分析:首先根据主键id在聚集索引上进行Index Seek(索引查找),输出的字段为[id]和[age],因为我们要更新的数据存储在聚集索引的叶子节点上,所以直接在聚集索引上更新数据(age+1)。其实到这一步还没有结束,因为字段age的值修改了,该字段所在的非聚集索引要进行"旋转"或"页拆分"处理,所以SqlServer还要继续更新非聚集索引栏位(index_name)

示例演示

脚本一:声明一个循环查询语句,其中:where 查询条件使用非聚集索引字段 name ,select 的字段 address 为普通字段(:目的是让其进行回表)

DECLARE @num int
SET @num = 1
While 1=1 
BEGIN   
 SELECT address FROM t_test WHERE name = '张三'
  set @num=@num+1
END

脚本二:声明一个循环更新语句,根据主键修改 age(include字段) 的值

DECLARE @i int  
SET @i=1
While 1=1
 BEGIN   
 UPDATE t_test SET age=age + @i WHERE id = 1  
 SET @i=@i+1  
END

运行了大概6秒钟,死锁(不是阻塞)就出现了,结果直接上图吧

在这里插入图片描述

此时表数据如下:

idnameageaddress
1张三15826967上海市徐汇区
2李四19浙江省杭州市
3王五28湖北省武汉市
原因分析

Query查询时使用非聚集索引来select数据,那么它会在非聚集索引 [name(include age)] 上持有一个S锁,因为select的列不在该索引上,所以它需要根据rowid找到对应的聚集索引的那一行磁盘地址,然后找到其他数据。而此时在第二个更新语句中,update正在聚集索引上进行定位、加锁、修改操作,但因为正在修改的 age 列,是另外一个非聚集索引的某个列,所以此时,它需要同时更改那个非聚集索引的信息,这就需要在非聚集索引 [name(include age)] 上加第二个X锁,select开始等待update的X锁,update开始等待select的S锁,死锁就发生了

图例:
在这里插入图片描述
如上图:update开始等待select的S锁,select开始等待update的X锁

解决方案
  • 持锁时间越长,死锁的概率越大,尽量缩短事务的执行时间,避免长事务产生
  • 按同一顺序访问对象,避免事务交叉进行 [这点很重要]
  • select查询时避免使用通配符*,减少多余的index seek查找
  • 适当允许脏读的情况下,使用WITH(NOLOCK),可以提高查询性能,避免死锁
  • 根据业务场景,可以考虑设置较低的隔离级别降低死锁的发生频率
其它

文章最后补充一下 索引 include 的使用技巧:

索引不包含include列

缺点:会增加一次通过主键索引的回表操作,增加了逻辑读次数,影响性能

索引包含include列

优点:通过非聚集索引就可以直接查询返回include列的数据,不需要通过主键索引回表,减少了逻辑读次数,提升了查询效率(建议当select查询字段较少时,可以用包含include的索引)

缺点:会增加 非集索引的空间占用

(完结)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/363716.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu 使用Nohup 部署/启动/关闭程序

目录 一、什么是nohup? 二、nohup能做什么? 三、nohup如何使用? 四、怎么查看/关闭使用nohup运行的程序? 命令 实例 一、什么是nohup? nohup 命令运行由 Command参数和任何相关的 Arg参数指定的命令&#xff0c…

【微信小程序】--WXML WXSS JS 逻辑交互介绍(四)

💌 所属专栏:【微信小程序开发教程】 😀 作  者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &#…

Kotlin 34. recyclerView 案例:显示列表

Kotlin 案例1. recyclerView:显示列表 这里,我们将通过几个案例来介绍如何使用recyclerView。RecyclerView 是 ListView 的高级版本。 当我们有很长的项目列表需要显示的时候,我们就可以使用 RecyclerView。 它具有重用其视图的能力。 在 Re…

【C语言】-程序编译的环境和预处理详解-让你轻松理解程序是怎么运行的!!

作者:小树苗渴望变成参天大树 作者宣言:认真写好每一篇博客 作者gitee:gitee 如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧! 程序的编译前言一、 程序的翻译环境和执行环境二、 详解翻译环境2.1编译环境2.1.1预编…

代码随想录算法训练营第七天 | 454.四数相加II 、 383. 赎金信、15. 三数之和、18. 四数之和 、总结

打卡第七天&#xff0c;还是哈希表。 今日任务 454.四数相加II383.赎金信15.三数之和18.四数之和总结 454.四数相加II 代码随想录 class Solution { public:int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, ve…

单元测试面试秘籍分享

1. 什么是单元测试 “在计算机编程中&#xff0c;单元测试又称为模块测试&#xff0c;是针对程序模块来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中&#xff0c;一个单元就是单个程序、函数、过程等&#xff1b;对于面向对象编程&#xff0c;最…

j-vxe-table 下拉搜索选择框数据加载过多导致前端崩溃问题

Jeeg-boot j-vxe-table 下拉搜索选择框数据加载过多导致前端崩溃问题 最近用到了Jeeg-boot j-vxe-table的组件&#xff0c;这组件时真J8难用&#xff0c;还好多BUG&#xff0c;想用个slot插槽也用不了&#xff0c;好像官方写了个基础就没怎么管了。&#x1f611; 问题&#xf…

google hacker语句

哎&#xff0c;我就是沾边&#xff0c;就是不打实战(&#xffe3;o&#xffe3;) . z Z 文章目录前言一、什么是谷歌Docker&#xff1f;二、受欢迎的谷歌docker语句谷歌docker的例子日志文件易受攻击的 Web 服务器打开 FTP 服务器SSH私钥电子邮件列表实时摄像机MP3、电影和 PDF…

php调试配置

错误信息输出 错误日志 nginx把对php的请求发给php-fpm fastcgi进程来处理&#xff0c;默认的php-fpm只会输出php-fpm的错误信息&#xff0c;在php-fpm的errors log里也看不到php的errorlog。原因是php-fpm的配置文件php-fpm.conf中默认是关闭worker进程的错误输出&#xff0…

【MySQL进阶】 锁

&#x1f60a;&#x1f60a;作者简介&#x1f60a;&#x1f60a; &#xff1a; 大家好&#xff0c;我是南瓜籽&#xff0c;一个在校大二学生&#xff0c;我将会持续分享Java相关知识。 &#x1f389;&#x1f389;个人主页&#x1f389;&#x1f389; &#xff1a; 南瓜籽的主页…

Mybatis源码学习笔记(四)之Mybatis执行增删改查方法的流程解析

1 Mybatis流程解析概述 Mybatis框架在执行增伤改的流程基本相同&#xff0c; 很简单&#xff0c;这个大家只要自己写个测试demo跟一下源码,基本就能明白是怎么回事&#xff0c;查询操作略有不同&#xff0c; 这里主要通过查询操作来解析一下整个框架的流程设计实现。 2 Mybat…

【python】argparse 模块的使用、Pycharm中使用argparse

目录1、简介2、使用步骤1&#xff09;导入argparse模块&#xff0c;并创建解释器2&#xff09;添加所需参数3&#xff09;解析参数3、使用 pycharm 传递参数给 argparse1、简介 argparse 模块是 Python 标准库中提供的一个命令行解析模块&#xff0c;它可以让使用者以类似 Uni…

给安全平台编写插件模块的思路分享

一、背景 最近在GitHub看到一个新的开源安全工具&#xff0c;可以把工具都集成到一个平台里&#xff0c;觉得挺有意思&#xff0c;但是平台现有的工具不是太全&#xff0c;我想把自己的工具也集成进去&#xff0c;所以研究了一番 蜻蜓安全工作台是一个安全工具集成平台&#x…

我的零分周赛:CSDN周赛第30期,成绩“0”分,天然气定单、小艺读书、买苹果、圆桌

CSDN周赛第30期&#xff0c;成绩“0”分&#xff0c;天然气定单、小艺读书、买苹果&#x1f34e;、圆桌。 (本文获得CSDN质量评分【91】)【学习的细节是欢悦的历程】Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教…

steam搬砖项目,小投入高回报,可放大操作,(内附教学资料)

我必须要说&#xff0c;steam搬砖项目就是全网门槛最低的副业&#xff0c;有手就行&#xff01; 本人90后底层员工一枚&#xff0c;新入csgo搬砖项目&#xff0c;轻松翻身 什么做抖音、海外问卷、直播卖货&#xff0c;电商等等对比我这个都是小钱。我这个方法是利用了大部分人…

C++线程/阻塞/同步异步----2

本章节内容为记录改写RTK代码时&#xff0c;学习的知识 同步和异步区别 1.定义不同&#xff1a;同步需要将通信双方的时钟统一到一个频率上&#xff0c;异步通信发送的字符间隔时间可以是任意的; 2.准确性不同&#xff1a;同步通信需要比较高精度的精确度&#xff0c;异步则不…

【算法基础】栈与队列

一、栈1.1 模拟栈实现一个栈&#xff0c;栈初始为空&#xff0c;支持四种操作&#xff1a;push x – 向栈顶插入一个数 x&#xff1b;pop – 从栈顶弹出一个数&#xff1b;empty – 判断栈是否为空&#xff1b;query – 查询栈顶元素。现在要对栈进行 M 个操作&#xff0c;其中…

【2023最火教程】Python性能测试框架Locust实战教程(建议收藏)

01、认识Locust Locust是一个比较容易上手的分布式用户负载测试工具。它旨在对网站&#xff08;或其他系统&#xff09;进行负载测试&#xff0c;并确定系统可以处理多少个并发用户&#xff0c;Locust 在英文中是 蝗虫 的意思&#xff1a;作者的想法是在测试期间&#xff0c;放…

图解 paxos 论文《The Part-Time Parliament》

本文以图文并茂的方式重新演绎 Paxos 开山之作 《The Part-Time Parliament》[1]&#xff0c;并尝试解释原论文中语焉不详的地方。 背景 在 Paxos 小岛上&#xff0c;施行着一种 Parliament(议会) 政治。小岛上执行的所有 decree(法令) 都需要先由 Parliament 在 Chamber 内表…

leetcode 21~30 学习经历

leetcode 21~30 学习经历21. 合并两个有序链表22. 括号生成23. 合并K个升序链表24. 两两交换链表中的节点25. K 个一组翻转链表26. 删除有序数组中的重复项27. 移除元素28. 找出字符串中第一个匹配项的下标29. 两数相除30. 串联所有单词的子串小结21. 合并两个有序链表 将两个升…