日常运维之TX锁处理(一)

来源:这里教程网 时间:2026-03-03 18:11:35 作者:

有经验的DBA  在遇到TX  锁时,第一反应就是查询v$lock  v$session  视图,定位LMODE  REQUEST  类型互斥的会话并进行查杀。然而,随着数据库版本不断地迭代更新,v$session  视图的内容越来越丰富,可以直接使用blocking_session  blocking_instance    final_blocking_instance    final_blocking_session  字段进行定位。对于锁层次的排查可以重复查询v$session  来确定,但如果锁层次有100  层,我们就不可能通过人工遍历100  次,显然这种方式过于低效,不适用于生产环境。

下面就来介绍本节的主角:Oracle  SYS_CONNECT_BY_PATH  函数。自Oracle 9i  开始,DBA  可以使用SYS_CONNECT_BY_PATH  函数,将父节点到当前行的内容以“路径”或层次的形式显示出来。该功能刚好符合我们递归查找锁层次的需求,在这里  笔者模拟了锁环境,使用如下语句查询锁信息:

SQL> select a.inst_id  ,

       a.process  ,

       a.sid  ,

       a.serial#  ,

       a.sql_id  ,

       a.event  ,

       a.status  ,

       a.program  ,

       a.machine  ,

       connect_by_isleaf  as isleaf  ,

       sys_connect_by_path  (a.SID  ||  '@'  || a.inst_id  ,  ' <- '  ) tree  ,

        level  as tree_level

   from gv$session a

   start  with a.blocking_session  is  not  null

connect  by  (a.sid  ||  '@'  || a.inst_id  )  =  prior

            (a.blocking_session  ||  '@'  || a.blocking_instance  );

<!--  省略部分列  -->

INST_ID PROCESS   SID    SERIAL#  EVENT                          STATUS     ISLEAF TREE              TREE_LEVEL

------- -------- ---- ----------  ------------------------------ ---------- ------ -----------------  ----------

      1 7663       17       6749  enq: TX - row lock contention  ACTIVE          0  <- 17@1                   1

      1 6198       25       9989  SQL*Net message from client    INACTIVE        1  <- 17@1 <- 25@1           2

      1 6310       28      23199  enq: TX - row lock contention  ACTIVE          0  <- 28@1                   1

      1 6198       25       9989  SQL*Net message from client    INACTIVE        1  <- 28@1 <- 25@1           2

代码段中,部分参数说明如下。

  INST_ID  :会话所在的节点号。

  PROCESS  :客户端进程号,与v$process  中的spid  不是同一个。

  SID  SERIAL#  SQL_ID  STATUS  PROGRAM  MACHINE  :会话信息。

  ISLEAF  :是否为源头,代表否,代表是。

TREE  :树形结构,锁的层次,例如,<- 152@2 <- 153@2 <- 161@1  ,从左到右表示为节点的会话152  节点的会话153  堵塞,而节点的会话153  又被节点的会话161  堵塞。所以节点的会话161  是锁的源头。

  TREE_LEVEL  :树形层次。

锁源头的查杀方法有两种,说明如下。

   通过ISLEAF  进行筛选,直接查杀锁源头,语句如下:

SQL> select 'alter system kill session '''  ||  sid  || ''  || ','  ||  serial#  || ',@'  ||

       inst_id  || ''' immediate;' db_kill_session

   from  (  select a.inst_id  ,

               a.process  ,

               a.sid  ,

               a.serial#  ,

               a.sql_id  ,

               a.event  ,

               a.status  ,

               a.program  ,

               a.machine  ,

               connect_by_isleaf  as isleaf  ,

               sys_connect_by_path  (a.SID  || '@'  || a.inst_id  , ' <- '  ) tree  ,

                level  as tree_level

           from gv$session a

          start  with a.blocking_session  is  not  null

         connect  by  (a.sid  || '@'  || a.inst_id  )  =  prior

                    (a.blocking_session  || '@'  || a.blocking_instance  ))

   where isleaf  = 1

   order  by tree_level  asc  ;

KILL_SESSION

---------------------------------------------------

alter system kill session '161,5579,@1' immediate;

alter system kill session '161,5579,@1' immediate;

 

SQL> select inst_id  , 'kill -9 '  || spid os_kill_session

   from  (  select p.inst_id  ,

               p.spid  ,

               a.sid  ,

               a.serial#  ,

               a.sql_id  ,

               a.event  ,

               a.status  ,

               a.program  ,

               a.machine  ,

               connect_by_isleaf  as isleaf  ,

               sys_connect_by_path  (a.SID  || '@'  || a.inst_id  , ' <- '  ) tree  ,

                level  as tree_level

           from gv$session a  , gv$process p

          where a.inst_id  = p.inst_id

            and a.paddr  = p.addr

          start  with a.blocking_session  is  not  null

         connect  by  (a.sid  || '@'  || a.inst_id  )  =  prior

                    (a.blocking_session  || '@'  || a.blocking_instance  ))

   where isleaf  = 1

   order  by tree_level  asc  ;

   INST_ID OS_KILL_SESSION

---------- --------------------------------

         1 kill -9 30049

   借助v$session  中的final_blocking_instance  final_blocking_session  定位锁源头,语句如下:

SQL> select 'alter system kill session '''  ||  ss.sid  || ''  || ','  ||  ss.serial#  || ',@'  ||

       ss.inst_id  || ''' immediate;' db_kill_session

   from gv$session s  , gv$session  ss

   where s.final_blocking_session  is  not  null

    and s.final_blocking_instance  = ss.inst_id

    and s.final_blocking_session  = ss.sid

    and s.sid  <> ss.sid

DB_KILL_SESSION

--------------------------------------------------

alter system kill session '161,5579,@1' immediate;

alter system kill session '161,5579,@1' immediate;

 

SQL> select p.inst_id  , 'kill -9 '  || p.spid os_kill_session

   from gv$session s  , gv$session  ss  , gv$process p

   where s.final_blocking_session  is  not  null

    and s.final_blocking_instance  = ss.inst_id

    and s.final_blocking_session  = ss.sid

    and ss.paddr  = p.addr

    and ss.inst_id  = p.inst_id

    and s.sid  <> ss.sid

   INST_ID OS_KILL_SESSION

---------- --------------------------------

         1 kill -9 30049

执行拼接生成的语句,即可杀掉锁的源头。

相关推荐