样例:
第一步,查询阻塞的事务ID
select * from v$trxwait order by wait_time desc; --单机
select * from v$dsc_trxwait order by wait_time desc;–DSC集群
第二步,查询阻塞事务的会话信息
select sf_get_session_sql(sess_id),* from v$sessions where trx_id=69667; --单机
select sf_get_session_sql(sess_id),* from gv$sessions where trx_id=69667; --DSC集群
第三步,查询问题SQL
cat dmsql_xxxxxx.log | grep “trxid:69967”
–查找问题DML SQL,保留
注:需要开启SVR_LOG参数
第四步,杀掉会话
sp_close_session(139926142266440);
注:对于DSC,需要在相应的节点执行。
其他SQL,
select * from v$lock where trx_id=69667;
–查询阻塞事务的相关锁信息
当进行日常巡检、用户反馈执行SQL语句卡住或应用运行缓慢时,需要查询数据库中有没有阻塞的会话SQL在执行,找到它,记录它,杀掉它,最后再分析SQL的合理性,优化它。
用户报告:执行某条DML语句,发现卡住,很长时间都没有执行完成,比如如下SQL,
update test set c1=3; --会话1
猜测可能是某个事务未提交导致相关表锁住,阻塞了本事务的执行,导致等待。就算是SQL执行慢也需要先查下有没有阻塞。
一般运维人员都是从这步开始的,发现事务69666被事务69667阻塞了,已经阻塞了312秒。
根据WAIT_FOR_ID,事务号69667查询哪个会话导致的阻塞问题。
通过查询可以看到对应会话的SQL_TEXT显示是一条select语句(会话2),并且该会话的状态还是空闲状态(STATE=‘IDLE’),是不是比较疑惑,update为什么会被一个select语句阻塞呢?带着疑问我们可以查询下相关事务锁的信息。
select * from v$lock where trx_id=69667;
可以看到该事务存在表id为1100的IX锁和TID的X锁,表明table_id=1100的表进行了数据修改。查询对应ID号的表信息。
select * from sysobjects where id=1100 ;
可以看到被上锁的表为TEST。分析到这里我们可以确认trx_id=69667的事务应该是一个混合操作事务,该事务做了数据修改后没有提交,然后又执行了其他的操作(一个事务中可以执行多条SQL),这也就解释了为什么update(会话1)会被select(会话2)SQL语句阻塞,真正阻塞的罪魁祸首应该是与这个select语句在同一事务中的其他修改数据操作。
cat dmsql_DMSERVER_20230110_145721.log | grep “trxid:69667”
注:根据会话2对应的last_recv_time时间,查询事务69667在此时间前执行了哪些SQL。使用日志查询需要开启日志记录。
如果日志刷新很快,有很多日志都包含这个事务,
cat dmsql_DMSERVER_20230110_14*.log | grep “trxid:69667” > /tmp/sql.log
sp_close_session(139926142266440); --sid在2.2步查询会话时获得
注:杀掉会话前记得记录问题SQL以及会话的相关信息。
vi dm.ini --修改如下
SVR_LOG=1
SP_REFRESH_SVR_LOG_CONFIG(); --刷新生效
或者执行
SP_SET_PARA_VALUE(1,‘SVR_LOG’,1);
开启svr_log后,默认会在dm.ini的存放目录下生成一个sqllog.ini文件
vi sqllog.ini --具体配置请参考官方文档,包含日志文件存放目录、大小、个数等
当用户发生执行某条DML语句长时间异常等待时,可以查询是否发生阻塞。类似场景如下,
当进行UPDATE或DELETE时,相关对象如果已经被其他的事务修改过,将会发生阻塞直到其他的事务提交或回滚。经过上述分析,我们可以怀疑与这个select语句在同一事务中还有一个update或delete等操作没有提交。如何查找这个问题SQL,v$sessions中可能看不出来,我们可以通过sql日志去查看(需要开启日志记录功能),根据会话2对应的last_recv_time,我们在sql日志这个时间往前搜索trx_id=69667的事务包含了哪些操作。从而可以告知客户发生问题的根本原因。
最后,查出问题SQL语句并记录相关会话信息后,需要杀掉问题会话,即可解除阻塞。如果是DSC集群,杀会话时需要在相应的问题SQL执行的节点执行sp_close_session(sid)语句。
文章
阅读量
获赞