RDS SQL Server死锁(Deadlock)系列之一使用DBCC捕获死锁
问题引入
在日常运维阿里云RDS SQL Server产品过程中,经常会被客户问道:“应用程序被死锁报错啦?影响很大,到底是哪个进程导致了死锁发生的啊?怎么解决啊?怎么办呀?”。从客户一连串的问题中,我们深刻体会到了死锁问题的紧迫性和影响之大。授人予鱼而不如授人予渔,RDS SQL Server死锁系列文章就是为了帮助客人彻底解决死锁问题为初衷而诞生的。本篇文章是系列文章的开篇,主要是讨论如何使用DBCC来捕获死锁信息,内容包括:
DBCC捕获死锁
死锁测试
死锁分析
解决方法
DBCC捕获死锁
DBCC捕获死锁是利用了SQL Server死锁自动监测机制(默认每5秒运行一次)的返回信息,来将死锁信息记录到数据库日志记录中,我们可以事后从错误日中来查看这些有用的死锁信息,包括:
死锁的牺牲进程
死锁发生时的进程信息
死锁发生时争抢的资源
其实,DBCC捕获死锁信息的方法本身非常简单,只需要使用DBCC命令打开两个跟踪标记(1222和1204)即可。方法如下:
USE master GO DBCC TRACEON(1222,-1) GO --also write like this, that’s fine to use any one DBCC TRACEON (1204, 1222, -1) GO
跟踪标记打开后,我们可以使用下面的语句再次检查,确保标记打开成功:
DBCC TRACESTATUS(-1) GO
截图如下所示:
在这里也顺便把如何关闭死锁跟踪标记的方法写到这里:
DBCC TRACEOFF (1204, 1222, -1) GO --split into two stats DBCC TRACEOFF (1204,-1) GO DBCC TRACEOFF (1222,-1) GO
死锁测试
获取死锁信息的跟踪标记已经打开,接下来进行死锁测试。首先,在Test数据库下创建两个测试表,表名分别为:dbo.test_deadlock1和dbo.test_deadlock2,代码如下:
IF DB_ID('Test') IS NULL CREATE DATABASE Test; GO USE Test GO -- create two test tables IF OBJECT_ID('dbo.test_deadlock1','u') IS NOT NULL DROP TABLE dbo.test_deadlock1 GO CREATE TABLE dbo.test_deadlock1( id INT IDENTITY(1,1) not null PRIMARY KEY ,name VARCHAR(20) null ); IF OBJECT_ID('dbo.test_deadlock2','u') IS NOT NULL DROP TABLE dbo.test_deadlock2 GO CREATE TABLE dbo.test_deadlock2( id INT IDENTITY(1,1) not null PRIMARY KEY ,name VARCHAR(20) null ); INSERT INTO dbo.test_deadlock1 SELECT 'AA' UNION ALL SELECT 'BB'; INSERT INTO dbo.test_deadlock2 SELECT 'AA' UNION ALL SELECT 'BB'; GO
接下来,我们使用SSMS打开一个新的连接,我们假设叫session 1,执行如下语句:
--session 1 USE Test GO BEGIN TRAN UPDATE dbo.test_deadlock1 SET name = 'CC' WHERE id = 1 ; WAITFOR DELAY '00:00:05' UPDATE dbo.test_deadlock2 SET name = 'CC' WHERE id = 1 ; ROLLBACK
紧接着,我们使用SSMS打开第二个连接,假设叫Session 2,执行下面的语句:
--session 2 USE Test GO BEGIN TRAN UPDATE dbo.test_deadlock2 SET name = 'CC' WHERE id = 1 ; UPDATE dbo.test_deadlock1 SET name = 'CC' WHERE id = 1 ; COMMIT
一段时间以后,你会发现Session 2执行的语句会被死锁,做为了死锁的牺牲品,错误信息如下:
Msg 1205, Level 13, State 51, Line 11 Transaction (Process ID 62) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
截图为证:
死锁分析
死锁场景,我们已经模拟出来了,接下来就是分析死锁的时候了。让我们查看错误日志:
EXEC sys.sp_readerrorlog
截图如下所示:
从这个死锁信息中,我们不难发现几个非常有用的信息:
参与死锁的进程(process-list):锁住其他进程的进程和死锁牺牲者进程(会有deadlock victim标记)。
死锁发生时,进程执行的语句(inputbuf):这个很重要,找到了语句就可以针对死锁的语句进行针对性的优化解决。
进程争抢的资源(resource-list):死锁发生时,到底进程之间在争抢什么资源,死锁的类型是什么?本例资源争抢发生在表Test.dbo.test_deadlock1 的主键上indexname=PK__test_dea__3213E83F07020F21,死锁类型为X锁(排他锁)。
解决方法
通过SQL Server错误日志中死锁信息的分析,我们可以从死锁发生时进程执行的语句发现,死锁发生的原因是两个UPDATE进程操作的表顺序不一致导致的。我们只需要调整其中一个进程的UPDATE表顺序即可解决这个死锁问题。比如,调整Session 2的执行语句,如下:
--session 2 USE Test GO BEGIN TRAN UPDATE dbo.test_deadlock1 SET name = 'CC' WHERE id = 1 ; UPDATE dbo.test_deadlock2 SET name = 'CC' WHERE id = 1 ; COMMIT
最后总结
本篇分享讲解了使用DBCC命名捕获SQL Server死锁信息,是RDS SQL Server死锁系列文章的开篇,我们还会在后续系列文章分享更多的方法来捕获死锁信息,敬请期待。
原文地址https://yq.aliyun.com/articles/73856
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
无法连接到远程Geth,connect: permission denied.
无法连接到远程Geth,connect: permission denied. 我在安装了Geth节点的ubuntu服务器X上创建了一个shell脚本,在测试链中插入智能合约数据。此外,我通过使用Shell脚本命令在同一服务器X上创建一个PHP文件insertscript.php。当我从命令提示符调用PHP脚本时,它会成功执行,并且数据被插入到区块链中。但是当我用CURL调用另一个服务器的PHP脚本或在浏览器中打开它时,我会看到错误: Fatal: Unable to attach to remote geth: dial unix ///home/ubuntu/.ethereum/testnet/geth.ipc: connect: permission denied 我的shell脚本如下: #!/bin/sh ATTACHPARAMETER="ipc:///home/ubuntu/.ethereum/testnet/geth.ipc" INCIDENTUUID=${1:-"photo-55697b7f4a550511448499999999"} USERUUID=${2:-"nu...
- 下一篇
为什么我对签名消息的签名验证在PHP代码中未工作?
我正在尝试验证PHP中的签名消息。 我不希望与JSON-RPC或任何外部服务有接口,我知道这两个服务都是可以成功地验证了我提供的示例签名消息。 另外,我很清楚message prefix和消息长度问题。 这个问题似乎源于我正在使用的Signature类或对R和S值的GMP转换,在签名本身中起的作用。 在我的代码中使用的唯一外部库是https://github.com/0xbb/php-sha3/blob/master/src/Sha3.php,它需要对第334行进行修改,将0x06更改为0x01,用于keccak兼容,这是以太坊所使用的。这里的改变应该说是一个正确的改变,因为在用web3库hash同一条消息时,当哈希原始消息时,将其保持为0x01会产生不同的结果。 下面是我的代码。如果有人能告诉我哪里出了问题,我将不胜感激。 <?php use bb\Sha3\Sha3; require_once('./Sha3.php'); $message = 'This is an example of a signed message.'; $signerAddress = '0xd4e...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Windows10,CentOS7,CentOS8安装Nodejs环境
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Red5直播服务器,属于Java语言的直播服务器
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS6,CentOS7官方镜像安装Oracle11G