1. 程式人生 > 其它 >查殺根鎖會話

查殺根鎖會話

場景:

在業務場景複雜的情況下,特別是行鎖表鎖並行等很多會話的時候,查出來的阻塞鏈條是很長的(級聯鎖)。並且,由於會話多,所以查出來的鎖的源頭也不一定是同一個,那麼這就導致在很緊急的情況下,有殺錯會話的可能,發現gv$session檢視中存在FINAL_BLOCKING_SESSION和BLOCKING_SESSION的欄位,充分理解並加以利用即可理清楚思路。
特提供個sql

其一:查出阻塞鏈條

col INST_ID for 99
col TREE for a30
select *
from (select a.inst_id, a.sid, a.serial#,
a.sql_id,
a.event,
a.status,
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;



其二:直接查殺根鎖sql(為了防止查錯dba的會話,多了一個過濾sqlplus的程序的條件)

col ksql for a40
set lines 199
set pages 9999
SELECT distinct
'alter system kill session '''||A.sid||','||A.serial#||',@'||A.inst_id||''' immediate;'
FROM GV$SESSION A,GV$SESSION B
WHERE A.SID=B.FINAL_BLOCKING_SESSION
AND A.USERNAME IS NOT NULL
AND A.INST_ID=B.INST_ID
AND A.AUDSID<>B.AUDSID
--and a.program not like '%sqlplus%' and
;


su - oracle
sqlplus / as sysdba
select * from v$mystat where rownum = 1;
conn SCOTT/SCOTT


17:27:35 SCOTT@zytrac2>SELECT * FROM EMP;

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- -------------------- ------------------ ---------- ------------------- ---------- ---------- ----------
7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20
7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 1600 300 30
7521 WARD SALESMAN 7698 1981-02-22 00:00:00 1250 500 30
7566 JONES MANAGER 7839 1981-04-02 00:00:00 2975 20
7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250 1400 30
7698 BLAKE MANAGER 7839 1981-05-01 00:00:00 2850 30
7782 CLARK MANAGER 7839 1981-06-09 00:00:00 2450 10
7788 SCOTT ANALYST 7566 1987-04-19 00:00:00 3000 20
7839 KING PRESIDENT 1981-11-17 00:00:00 5000 10
7844 TURNER SALESMAN 7698 1981-09-08 00:00:00 1500 0 30
7876 ADAMS CLERK 7788 1987-05-23 00:00:00 1100 20
7900 JAMES CLERK 7698 1981-12-03 00:00:00 950 30
7902 FORD ANALYST 7566 1981-12-03 00:00:00 3000 20
7934 MILLER CLERK 7782 1982-01-23 00:00:00 1300 10

14 rows selected.

Elapsed: 00:00:00.09

思路:

第一個會話先更新7788,然後第二個會話更新7839,然後再更新7788,這樣第一個會話就阻塞了第二個會話;如果後面會話一直更新7788,就會是第一個會話阻塞後面所有會話;所以應該更新7839,這樣,第二個會話就會阻塞後面的會話。即如下:

時間點1:61
select * from v$mystat where rownum = 1;
update emp set sal = 8000 where empno = 7788;

時間點2:29
select * from v$mystat where rownum = 1;
delete from emp where empno = 7839;
update emp set job = 'MANAGER' where empno = 7788;
rollback;

時間點3:43
select * from v$mystat where rownum = 1;
update emp set sal = 15000 where empno = 7839;
rollback;

時間點4:58
select * from v$mystat where rownum = 1;
update emp set job = 'CEO' where empno = 7839;
rollback;

--查出阻塞鏈條
col INST_ID for 99
col TREE for a30
select *
from (select a.inst_id, a.sid, a.serial#,
a.sql_id,
a.event,
a.status,
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;

INST_ID SID SERIAL# SQL_ID EVENT STATUS ISLEAF TREE TREE_LEVEL
------- -------- ------- -------------------- ------------------------------ ---------- ---------- ------------------------------ ----------
2 61 65 SQL*Net message from client INACTIVE 1 <- 29@2 <- 61@2 2
2 61 65 SQL*Net message from client INACTIVE 1 <- 58@2 <- 29@2 <- 61@2 3
2 61 65 SQL*Net message from client INACTIVE 1 <- 43@2 <- 29@2 <- 61@2 3

Elapsed: 00:00:00.05

可以看出,第一個會話61,阻塞了第二個會話29,第二個會話29,阻塞了第三四個會話58和43,即產生級聯鎖。

17:32:22 SYS@zytrac2>select inst_id, sid, FINAL_BLOCKING_SESSION,BLOCKING_SESSION from gv$session where SID=61;
INST_ID SID FINAL_BLOCKING_SESSION BLOCKING_SESSION
------- -------- ---------------------- ----------------
2 61

Elapsed: 00:00:00.60
17:33:11 SYS@zytrac2>17:33:11 SYS@zytrac2>select inst_id, sid, FINAL_BLOCKING_SESSION,BLOCKING_SESSION from gv$session where SID=29;
INST_ID SID FINAL_BLOCKING_SESSION BLOCKING_SESSION
------- -------- ---------------------- ----------------
2 29 61 61

Elapsed: 00:00:00.03
17:33:21 SYS@zytrac2>select inst_id, sid, FINAL_BLOCKING_SESSION,BLOCKING_SESSION from gv$session where SID=58;
INST_ID SID FINAL_BLOCKING_SESSION BLOCKING_SESSION
------- -------- ---------------------- ----------------
2 58 61 29

Elapsed: 00:00:00.01
17:33:35 SYS@zytrac2>select inst_id, sid, FINAL_BLOCKING_SESSION,BLOCKING_SESSION from gv$session where SID=43;
INST_ID SID FINAL_BLOCKING_SESSION BLOCKING_SESSION
------- -------- ---------------------- ----------------
2 43 61 29

進一步檢視,第三四個會話43和58,根據gv$session檢視中存在FINAL_BLOCKING_SESSION和BLOCKING_SESSION的欄位可知,阻塞第三個的會話(58)是29,阻塞第三個的會話(58)的根鎖是61;
第四個會話也是這樣。

--直接查殺根鎖sql(為了防止查錯dba的會話,多了一個過濾sqlplus的程序的條件)
col ksql for a40
set lines 199
set pages 9999
SELECT distinct
'alter system kill session '''||A.sid||','||A.serial#||',@'||A.inst_id||''' immediate;'
FROM GV$SESSION A,GV$SESSION B
WHERE A.SID=B.FINAL_BLOCKING_SESSION
AND A.USERNAME IS NOT NULL
AND A.INST_ID=B.INST_ID
AND A.AUDSID<>B.AUDSID
--and a.program not like '%sqlplus%' and
;

'ALTERSYSTEMKILLSESSION'''||A.SID||','||A.SERIAL#||',@'||A.INST_ID||'''IMMEDIATE;'
----------------------------------------------------------------------------------------------------------------------------------------
alter system kill session '61,65,@2' immediate;

參考:
https://www.cnblogs.com/jyzhao/p/8716546.html