如何定位Oracle數據庫被鎖阻塞會話的根源


首先再次明確下,數據庫因為要同時保證數據的並發性和一致性,所以操作有鎖等待是正常的。
只有那些長時間沒有提交或回滾的事物,阻塞了其他業務正常操作,才是需要去定位處理的。

1.單實例環境
2.RAC環境

1. 單實例環境

實驗環境:Oracle 10.2.0.5 單實例

會話1模擬業務操作:

SQL> select sid from v$mystat where rownum=1; 

       SID
----------
       144

SQL> show user
USER is "JINGYU"
SQL> select * from t1 where id=1 for update;

        ID          N CONTENTS
---------- ---------- ----------------------------------------
         1          1 Alfred Zhao

會話2模擬業務操作:

SQL> select sid from v$mystat where rownum=1; 

       SID
----------
       149

SQL> show user
USER is "JINGYU"
SQL> update t1 set contents='Mcdull' where id=1;    


這里update操作會卡住不動。用戶感知就是長時間無法執行成功,很可能還會直接抱怨數據庫性能慢。

會話3模擬DBA查看:

SQL> select sid from v$mystat where rownum=1; 

       SID
----------
       145

SQL> show user     
USER is "SYS"
SQL> select sid, username, blocking_session from v$session where blocking_session is not null;

       SID USERNAME                       BLOCKING_SESSION
---------- ------------------------------ ----------------
       149 JINGYU                                      144

SQL> select sid, serial#, username from v$session where sid=144;

       SID    SERIAL# USERNAME
---------- ---------- ------------------------------
       144        102 JINGYU

這里可以清楚的看到會話149是被會話144阻塞,進一步查看會話144的serial#值。

這時候的處理方式一般有2種方案:
1)殺掉會話144,當然操作之前需要和應用負責人確認溝通好;
2)如果可以定位到144會話相關責任人,由他來提交或者回滾事物;
處理后可以看到會話2的update操作正常執行成功。

2.RAC環境

實驗環境:Oracle 10.2.0.5 RAC 如果是RAC環境,還必須要定位到具體是哪個實例的會話,其實方法非常簡單,查詢時加入blocking_instance字段即可。 實例2模擬業務操作:
select sid from v$mystat where rownum=1; 
select * from t1 where id=1 for update;

實例1模擬業務操作:

select sid from v$mystat where rownum=1; 
update t1 set contents='Mcdull' where id=1;  

會話模擬DBA查看:

SQL> select sid, username, blocking_instance, blocking_session from gv$session where blocking_session is not null;

       SID USERNAME                       BLOCKING_INSTANCE BLOCKING_SESSION
---------- ------------------------------ ----------------- ----------------
       129 JINGYU                                         2              129

SQL> select inst_id, sid, serial#, username from gv$session where sid=129;

   INST_ID        SID    SERIAL# USERNAME
---------- ---------- ---------- ------------------------------
         1        129        617 JINGYU
         2        129        207 JINGYU

查詢阻塞會話也要注意當前連接的實例,千萬別弄錯了,比如上面這個情況,如果確定可以殺掉阻塞會話,那么就需要到實例2去殺掉會話;

SQL> select instance_number from v$instance;

INSTANCE_NUMBER
---------------
              2

SQL> alter system kill session '129,207';

System altered.

再次看被阻塞的會話操作已經恢復正常。

后記:
整理該文主要緣由是在之前的一次面試過程中,發現自己對這樣基本的問題反而太依賴於別人寫好的SQL,比如下面這類的SQL,開始並不知道此SQL的具體適用場景:

select a.sid blocker_sid, a.serial#, a.username as blocker_username, b.type,
decode(b.lmode,0,'None',1,'Null',2,'Row share',3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive') lock_mode,
b.ctime as time_held,c.sid as waiter_sid,
decode(c.request,0,'None',1,'Null',2,'Row share',3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive') request_mode,
c.ctime time_waited  
from   v$lock b, v$enqueue_lock c, v$session a  
where  a.sid = b.sid and    b.id1= c.id1(+) and b.id2 = c.id2(+) and c.type(+) = 'TX' and  b.type = 'TX' and  b.block   = 1
order by time_held, time_waited;

所以對於專業的DBA來說,這樣做是很不可取的。從現在起,自己要更多的研究這些基礎知識,腳踏實地,練好內功,對於別人寫的SQL,一定要徹底搞清楚含義之后再用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM