Oracle v$LOCK
為了實現併發,oracle資料庫使用了鎖機制。要了解鎖,首先要了解檢視v$lock。
v$lock這個檢視列出 Oracle 伺服器當前擁有的鎖以及未完成的鎖請求。如果你覺著 session 處於等待事件隊列當中,那你應該檢查檢視v$lock。
v$lock中的常用列有以下列:
sid:持有鎖的會話SID,通常與v$session關聯。
type:鎖的型別,其中TM表示表鎖或DML鎖,TX表示行鎖或事務鎖,UL表示使用者鎖。我們主要關注TX和TM兩種型的鎖,其它均為系統鎖,會很快自動釋放,不用關注。
當 Oracle執行 DML 語句時,系統自動在所要操作的表上申請 TM 型別的鎖。當 TM鎖獲得後,系統再自動申請 TX 型別的鎖,並將實際鎖定的資料行的鎖標誌位進行置位。
TM 鎖包括了SS 、 SX、 S 、X 等多種模式,在資料庫中用 0 -6 來表示。不同的 SQL 操作產生不同型別的 TM鎖。
lmode:會話保持的鎖的模式。
0=None;
1=Null ;
2=Row-S (SS,行級共享鎖,其他物件只能查詢這些資料行),sql操作有select for update、lock for update、lock row share;
3=Row-X (SX,行級排它鎖,在提交前不允許做DML操作),sql操作有insert、update、delete、lock row share;
4=Share(共享鎖),sql操作有create index、lock share;
5=S/Row-X (SSX,共享行級排它鎖),sql操作有lock share row exclusive;
6=Exclusive(排它鎖),alter table、drop table、drop index、truncate table、look exclusive等DDL
ID1,ID2: ID1,ID2的取值含義根據type的取值而有所不同。
(1)對於TM 鎖ID1表示被鎖定表的object_id 可以和dba_objects檢視關聯取得具體表資訊,ID2 值為0;
(2)對於TX 鎖ID1以十進位制數值表示該事務所佔用的回滾段號和事務槽slot number號,其組形式: 0xRRRRSSSS,RRRR=RBS/UNDO NUMBER,SSSS=SLOT NUMBER,ID2 以十進位制數值表示環繞wrap的次數,即事務槽被重用的次數。實際上這兩個欄位構成了事務在回滾段中的位置。
當鎖產生時,以下圖為例說明v$lock:
1、圖中存在兩個session分別是36和37,session 37的BLOCK=1意味著該session擁有一個鎖,並阻塞了其他session的對該鎖的請求(如果要處理死鎖這是根源)。該鎖的型別由TY定義,模式由LMODE欄位定義;
2、session 36的request=6說明該session正在等待一個lmode為6的鎖,而該鎖的擁有者正是session 37。
3、對於TM鎖,ID1值就是加鎖的段物件,可以是表或者表分割槽,此時ID2一般為0;對於TX鎖,這兩個欄位構成該事務在回滾段中的位置。
對於死鎖的處理流程:(下面過程也適合生產環境)
1,查詢鎖,阻塞的session和被阻塞session的sid:
set linesize 1200
COL USERNAME FOR A15
COL EVENT FOR A15
COL SID FOR 999999
COL INST_ID FOR 99
select inst_id,sid, username, event, blocking_session,
seconds_in_wait, wait_time
from gv$session where state in ('WAITING')
and wait_class != 'Idle';
可以看到sid為37的會話阻塞了sid為36的會話,我們要處理的是37的這個會話,將這個會話殺死。
2,查詢session sid對應的作業系統的spid,並且殺死會話
SQL> select b.spid,a.sid,a.username,a.program,a.machine from v$session a,v$process b where a.paddr=b.addr and a.type='USER';
這個sid為37的會話對應的作業系統的spid是7188,在作業系統使用者下使用root使用kill -9 7188就行了,將阻塞的會話殺掉,這樣阻塞就會消失。
3、批量殺死會話(如果一步到位殺死會話省去上面兩個步驟執行下面SQL語句就行)
殺阻塞的會話釋放鎖
set lines 900 pages 900
col BLOCK for 9
col LMODE for 9
col INST_ID for 9
col REQUEST for 9
col SID for 999999
select /*+ rule */a.INST_ID,
a.SID,
a.TYPE,
LMODE,
REQUEST,
CTIME,
BLOCK,
'ps -ef |grep ' || c.spid,
decode(LMODE, 0, null, 'kill -9 ' || c.spid) kill,
'kill -9 ' || c.spid,
d.sql_id,
ID1,
ID2
from gv$lock a, gv$session b, gv$process c, gv$sqlarea d
where (a.ID1, a.ID2, a.TYPE) in
(select ID1, ID2, TYPE from gv$lock where request > 0)
and a.sid = b.sid
and a.inst_id = b.inst_id
and a.inst_id = c.inst_id
and b.inst_id = d.inst_id(+)
and a.sid=b.sid
and b.paddr = c.addr
and b.sql_id = d.sql_Id(+)
order by inst_id, lmode desc;
這個和也得到最終要殺死阻塞會話的spid,使用kill -9 7188就可以消除阻塞釋放鎖。