注册
一次SQL阻塞案例分析
专栏/滴水藏海/ 文章详情 /

一次SQL阻塞案例分析

yuao 2022/06/15 2357 7 2
摘要 举例说明一个SQL阻塞发生的过程和查找源头的方法

某环境发现一个sql语句卡住了,很长时间都没有执行完,具体语句如下:

update xx set statexx= ? where rxxid=?

经过简单分析,发现这个update涉及的表数据量很小并且sql结构很简单,但是我们发现该sql的对应的连接状态为ACTIVE的,如下所示,由此我们初步判断该update操作被阻塞了,我们将这个update操作对应的会话称之为会话1。
image.png
这里说一下猜测会话1被阻塞的根据:
1.这个会话中当前SQL_TEXT中显示的sql是很简单的update,可以简单看看数据量和执行计划就知道不可能执行的慢;
2.这个会话状态为ACTIVE,如果是该操作没有提交那么状态应该是IDLE,综上两点初步判断可能发生了阻塞。

下面为了验证我们的猜测看数据库中是否发生了阻塞,我们可以通过查询v$trxwait或者v$lock中blocked=1,这里我们直接查询v$trxwait发现的确存在阻塞:

select * from v$trxwait

image.png
可以看到update对应的id为20287049662的事务被20287049586事务所阻塞,既然知道了阻塞的源头事务就好办了,我们继续确认一下这个阻塞源:

select * from v$sessions where trx_id=20287049586

image.png
通过查询可以看看阻塞源的对应会话SQL_TEXT显示是一条select语句(我们将这个称之为会话2),并且该会话的状态还是空闲状态(STATE=’IDLE’),这里就比较奇怪了,update为什么会被一个select查询所阻塞呢?这里我们先不解释,带着这个“疑问”我们继续看一下这个源头事务对应的锁的状态:

select * from v$lock where trx_id=20287049586

image.png
可以看到该事物存在表id为24342的IX锁和TID的X锁,表明table_id=24342的表进行了数据修改。分析到这里我们就理清思路了,trx_id=20287049586的事务应该是一个混合操作事务,该事务做了数据修改并且没有提交,然后紧接着做了其他表的查询操作,这也就解释了为什么update(会话1)会“被select(会话2)所阻塞”,真正阻塞的源头是与这个select在同一事务中的其他修改数据操作。我们知道update操作发生阻塞的场景应该如下:
“当 UPDATE 和 DELETE 修改的记录,已经被另外的事务修改过, 将会发生阻塞,直到另一个事务提交或回滚”。
经过上述分析我们可以有理由怀疑与这个select在同一事务中还有一个update操作没有提交。那如何确认这个问题,v$sessions中是看不出来的,我们可以直接通过sql追踪日志去查看,根据会话2对应的last_recv_time,我们在sql追踪日志这个时间附近搜索trx_id=20287049586的事务包含了哪些操作。
image.png
image.png
image.png
image.png
可以看到该事务中包含了混合操作,事务开始后先做了update操作,然后做了查询,并且最终并没有COMMIT,当一个事务中包含多个dml操作时,v$sessions中的SQL_TEXT只会记录最后一个操作的语句,至此真相大白,由于该阻塞源的事务是由应用程序发出的,需要杀掉连接即可解除阻塞。

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服