一个特殊的SQL Server阻塞案例分析
上周,在SQL Server数据库下面遇到了一个有意思的SQL阻塞(SQL Blocking)案例。其实个人对SQL Server的阻塞还是颇有研究的。写过好几篇相关文章。 至于这里为什么要总结一下这个案例,因为这个案例有点意思:
1:使用DMV视图捕获到的Blocking SQL为一个查询语句(这个不是真正引起阻塞的源头SQL语句),等待事件为LCK_M_S。
2:出现阻塞的会话非常多,阻塞的量非常大,使用DMV视图始终捕获不到相关表的DML操作语句。捕获到全是SELECT语句。
我们知道,在SQL Server中SELECT查询是不会阻塞SELECT查询的(不了解这个问题的,具体可以参考博客SQL Server中SELECT会真的阻塞SELECT吗? )。而且被阻塞的语句的等待类型为LCK_M_S,那么可以肯定:那个阻塞的源头会话中,存在对该表的DML操作,而且事务由于某些原因未提交。只是那个会话最后执行的SQL语句为一个SELECT查询。因为有时候,我们根本不能定位到SQL阻塞的源头SQL语句,具体参考我的博客“为什么数据库有时候不能定位阻塞(Blocker)源头的SQL语句”,此处不做重复赘述。
我们用一个简单的例子来模拟这个真实的案例,如需所示,首先创建一个测试表:
CREATE TABLE TEST (id INT);
GO
INSERT INTO TEST VALUES(1);
然后再通过2个会话,模拟这样的阻塞案例,如下所示:
会话A:
SET IMPLICIT_TRANSACTIONS ON;
GO
INSERT INTO TEST VALUES(2)
GO
SELECT * FROM TEST WHERE ID =1;
注意:先设置开启隐式事务,第一次执行插入数据语句,然后执行SELECT查询。
会话B:
SELECT * FROM TEST WHERE id=1;
会话C:
SELECT wt.blocking_session_id AS BlockingSessesionId
,sp.program_name AS Blocking_ProgramName
,COALESCE(sp.LOGINAME, sp.nt_username) AS Blocking_HostName
,ec1.client_net_address AS ClientIpAddress
,db.name AS DatabaseName
,wt.wait_type AS WaitType
,ec1.connect_time AS BlockingStartTime
,wt.WAIT_DURATION_MS/1000 AS WaitDuration
,ec1.session_id AS BlockedSessionId
,h1.TEXT AS BlockedSQLText
,h2.TEXT AS BlockingSQLText
FROM sys.dm_tran_locks AS tl WITH(NOLOCK)
INNER JOIN sys.databases AS db WITH(NOLOCK)
ON db.database_id = tl.resource_database_id
INNER JOIN sys.dm_os_waiting_tasks AS wt WITH(NOLOCK)
ON tl.lock_owner_address = wt.resource_address
INNER JOIN sys.dm_exec_connections ec1 WITH(NOLOCK)
ON ec1.session_id = tl.request_session_id
INNER JOIN sys.dm_exec_connections ec2 WITH(NOLOCK)
ON ec2.session_id = wt.blocking_session_id
LEFT OUTER JOIN master.dbo.sysprocesses AS sp WITH(NOLOCK)
ON SP.spid = wt.blocking_session_id
CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2
在会话C中查看SQL阻塞情况,如下截图所示,我们看到是SELECT查询阻塞了SELECT查询。
如上测试所示,因为是构造模拟案例,开启了“上帝视角”,所以你不会觉得有什么问题,实际情况是:应用程序是一个Java应用程序,而且是O/R Mapping框架(com.j256.ormlite),我将上面情况反馈给开发、Support人员,明确告诉他们阻塞的会话肯定有一个DML操作。让他们查找定位代码。但是诸多原因、因素叠加在一起(外包项目;沟通问题;对数据库的阻塞的的理解),沟通的效果让人很是无语。只能拿出确切的证据。由于那个框架开启了隐性事务(事后跟踪、分析发现的),而且UPDATE语句非常快,你使用DMV视图定位到的阻塞源头都是SELECT语句。显然这个不是我想要的。
于是,我打算使用SQL Server Profiler里面的“Blocked process report”事件来定位阻塞的源头,在跟踪之前,修改'blocked process threshold (s)'的值。如下所示,
exec sp_configure 'show advanced options',1;
reconfigure with override
exec sp_configure 'blocked process threshold (s)',4
reconfigure with override
然后设置SQL Server Profiler的相关选项和过滤条件。就像我下面的测试的一样,Blocked process report依然无法定位到阻塞的源头SQL语句,如下所示:
<blocked-process-report monitorLoop="3262026">
<blocked-process>
<process id="process1f9b22ca8" taskpriority="0" logused="0" waitresource="RID: 1:1:574:1" waittime="10174" ownerId="2680347313" transactionname="SELECT" lasttranstarted="2018-11-26T14:09:55.130" XDES="0x123391a20" lockMode="S" schedulerid="2" kpid="8604" status="suspended" spid="104" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2018-11-26T14:09:55.120" lastbatchcompleted="2018-11-26T14:09:37.887" lastattention="1900-01-01T00:00:00.887" clientapp="Microsoft SQL Server Management Studio - Query" hostname="GETNB00021" hostpid="10560" loginname="xxxx" isolationlevel="read committed (2)" xactid="2680347313" currentdb="1" lockTimeout="4294967295" clientoption1="671091040" clientoption2="390200">
<executionStack>
<frame line="1" stmtstart="24" stmtend="90" sqlhandle="0x02000000d8cd0821e4e62d2f8f098831e46f98ca20ba31ae0000000000000000000000000000000000000000"/>
<frame line="1" stmtend="60" sqlhandle="0x0200000012eff610783e49a674c5361fd9c8bb38747a966a0000000000000000000000000000000000000000"/>
</executionStack>
<inputbuf>
SELECT * FROM TEST WHERE ID =2; </inputbuf>
</process>
</blocked-process>
<blocking-process>
<process status="sleeping" spid="89" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2018-11-26T14:09:52.927" lastbatchcompleted="2018-11-26T14:09:52.927" lastattention="1900-01-01T00:00:00.927" clientapp="Microsoft SQL Server Management Studio - Query" hostname="GETNB00021" hostpid="10560" loginname="xxxx" isolationlevel="read committed (2)" xactid="2680346553" currentdb="1" lockTimeout="4294967295" clientoption1="671091040" clientoption2="390202">
<executionStack/>
<inputbuf>
SELECT * FROM TEST WHERE ID =1;
</inputbuf>
</process>
</blocking-process>
</blocked-process-report>
最后,只能使用SQL Server Profiler跟踪某个登录名(Login Name)一小段时间,根据会话ID一段时间内执行过的SQL来推理、判断定位阻塞的源头,从而找到具体原因,这个例子里面,ORM框架开启了隐性事务,在SQL Server Profiler里面捕获到开启隐性事务以及UPDATE操作。至此。问题终于解开了谜底。当然本文不是按照当时的逻辑来写的,而是在知道原因后,模拟构造案例重新的。所以总感觉字里行间写不出那种味道。
SET IMPLICIT_TRANSACTIONS ON;
.............
IF @@TRANCOUNT > 0 COMMIT TRAN set implicit_transactions off
一个特殊的SQL Server阻塞案例分析的更多相关文章
- SQL Server 阻塞原因分析
这里通过连接在sysprocesses里字段值的组合来分析阻塞源头,可以把阻塞分为以下5种常见的类型(见表).waittype,open_tran,status,都是sysprocesses里的值,“ ...
- SQL Server一个特殊的阻塞案例分析2
最近发现一个非常奇怪的阻塞问题,如下截图所示(来自监控工具DPA),会话583被会话1036阻塞,而且阻塞发生在tempdb,被阻塞的SQL如下截图所示,会话等待类型为LCK_M_S 因为DPA工具不 ...
- 需要我们了解的SQL Server阻塞原因与解决方法
需要我们了解的SQL Server阻塞原因与解决方法 上篇说SQL Server应用模式之OLTP系统性能分析.五种角度分析sql性能问题.本章依然是SQL性能 五种角度其一“阻塞与死锁” 这里通过连 ...
- (火炬)MS SQL Server数据库案例教程
(火炬)MS SQL Server数据库案例教程 创建数据库: CREATE DATABASE TDB //数据库名称 ON ( NAME=TDB_dat,//逻辑文件名 在创建数据库完成之后语句中引 ...
- SQL Server 在线进程分析处理
SQL Server 在线进程分析处理 前言 数据库在线进程处理在很多时候需要人为干预已达到预期管理目标,下面整理一下常用的在线进程管理方法,便于后续工作使用. 一.查看目标数据库在线进程,并杀死指定 ...
- sql server 阻塞与锁
SQL Server阻塞与锁 在讨论阻塞与加锁之前,需要先理解一些核心概念:并发性.事务.隔离级别.阻塞锁及死锁. 并发性是指多个进程在相同时间访问或者更改共享数据的能力.一般情况而言,一个系统在互不 ...
- 一个有趣的SQL Server 层级汇总数据问题
看SQL Server大V宋大侠的博客文章,发现了一个有趣的sql server层级汇总数据问题. 具体的问题如下: parent_id emp_id emp_nam ...
- VFP 用 SPT 来发布一条 SELECT 到一个新的 SQL Server 表
为了发布一条 SQL SELECT 语句来创建一个新的 SQL Server 表, SQL Server 数据库的 select into/bulkcopy 选项必须是可用的. 在默认情况下, 对于 ...
- SQL Server阻塞blocking案例分析
今天在性能测试过程中发现大量阻塞报警,检查whoisactive(https://github.com/amachanic/sp_whoisactive/)数据发现,阻塞blocking头部sessi ...
随机推荐
- git使用笔记1:结合Github远程仓库管理项目
git是一个十分好用的版本控制工具,我们经常在本地使用git进行项目开发,Git 并不像 SVN 那样有个中心服务器,如果想要通过 Git 分享你的代码或者与其他开发人员合作,就需要将数据放到一台其他 ...
- MongoDB 运维相关的命令
1.在线释放内存 use admindb.runCommand({closeAllDatabases:1}) 注:3.2 版本 已经去掉了这个命令了 2.rs.status() 查询复制集状态 3.d ...
- 将博客搬至CSDN https://blog.csdn.net/Fredric_2014
将博客搬至CSDN https://blog.csdn.net/Fredric_2014
- 图的BFS----迷宫问题
题目描述: ...11111111111111111111111111111 11.111111........1111111111.1111 11.111111..111.11111111..... ...
- iFace Chain [ 爱妃链 ] 或将凭借人脸密钥技术成为安全领域最大的赢家
前段时间iFace Chain [ 中文音译名称: 爱妃链 ] 安全专家揭密了区块链领域,数字资产存放于无信用钱包中的一些风险,并为区块链玩家解密如何安全保护资产私钥,我们再来回顾分析一下目前跑路钱包 ...
- 基于IPV6数据包的分析(GNS3)
一.实验拓扑 二.路由配置 1.路由R1的详细配置(以R1为例,R2与R3相同) R1(config)#interface fastEthernet 0/1 R1(config-if)#ipv6 ad ...
- 史上最全 40 道 Dubbo 面试题及答案,看完碾压面试官!
想往高处走,怎么能不懂 Dubbo? Dubbo是国内最出名的分布式服务框架,也是 Java 程序员必备的必会的框架之一.Dubbo 更是中高级面试过程中经常会问的技术,无论你是否用过,你都必须熟悉. ...
- python之读取配置文件模块configparser(二)参数详解
configparser.ConfigParser参数详解 从configparser的__ini__中可以看到有如下参数: def __init__(self, defaults=None, dic ...
- 细说mysql索引
本文从如何建立mysql索引以及介绍mysql的索引类型,再讲mysql索引的利与弊,以及建立索引时需要注意的地方 首先:先假设有一张表,表的数据有10W条数据,其中有一条数据是nickname='c ...
- k8s集群监控(十一)--技术流ken
Weave Scope 在我之前的docker监控中<Docker容器监控(十)--技术流ken>就已经提到了weave scope. Weave Scope 是 Docker 和 K ...