請將 emp.empno=7369 的記錄 ename 字段修改成「ENMOTECH」並提交,你可能會遇到各類故障,請嘗試解決。面試
其實題目的設計很是簡單,一個 RAC 雙節點的實例環境,面試人員使用的是實例2,而咱們在實例1中使用 select for update 將 EMP 表加鎖:sql
SQL> SELECT * FROM emp FOR UPDATE;數據庫
此時在實例2中,若是執行如下 SQL 語句嘗試更新 ename 字段,必然會被行鎖堵塞:session
SQL> UPDATE emp SET ename='ENMOTECH' WHERE empno=7369;.net
這道面試題中包含的知識點有:設計
1.進程
如何在另一個 session 中查找被堵塞的 session 信息;事件
2.事務
3.get
如何找到產生行鎖的 blocker;
4.
5.
在殺掉 blocker 進程以前會不會向面試監考人員詢問,我已經找到了產生堵塞的會話,是否是能夠kill掉;
6.
7.
在得到能夠 kill 掉進程的確認回覆後,正確殺掉另外一個實例上的進程。
8.
這道題咱們期待能夠在5分鐘以內得到解決,實際上大部分應試者在15分鐘之後都徹底沒有頭緒。
注意:其實Oracle的任何複雜問題處理,均可以是由刪繁就簡的步驟逐層推演出來的,保持清醒的思路,對於DBA的工做很是重要。
正確的思路和解法應該以下:
檢查被阻塞會話的等待事件
更新語句回車之後沒有回顯,明顯是被鎖住了,那麼如今這個會話經歷的是什麼等待事件呢?
能夠經過SESSION等待去獲取這些信息:
SQL> SELECT sid,event,username,SQL.sql_text
2 FROM v$session s,v$sql SQL
3 WHERE s.sql_id=SQL.sql_id
4 AND SQL.sql_text LIKE 'update emp set ename%';
SID EVENT USERNAME
---
79 enq: TX - ROW LOCK contention ENMOTECH
SQL_TEXT
UPDATE emp SET ename='ENMOTECH' WHERE empno=7369
以上使用的是關聯 v$sql 的 SQL 語句,實際上經過登陸用戶名等也能夠快速定位被鎖住的會話。
查找 blocker
得知等待事件是 enq: TX – row lock contention,行鎖,接下來就是要找到誰鎖住了這個會話。在10gR2之後,只須要 gv$session 視圖就能夠迅速定位 blocker,經過 BLOCKING_INSTANCE 和 BLOCKING_SESSION 字段便可。
SQL> SELECT SID,INST_ID,BLOCKING_INSTANCE,
BLOCKING_SESSION
FROM gv$session WHERE INST_ID=2 AND SID=79;
SID INST_ID BLOCKING_INSTANCE BLOCKING_SESSION
--- -------
79 2 1 73
上述方法是最簡單的,若是是使用更傳統的方法,實際上也並不難,從 gv$lock 視圖中去查詢便可。
SQL> SELECT TYPE,ID1,ID2,LMODE,REQUEST
FROM v$lock WHERE sid=79;
TY ID1 ID2 LMODE REQUEST
-- ----- -------
TX 589854 26267 0 6
AE 100 0 4 0
TM 79621 0 3 0
SQL> SELECT INST_ID,SID,TYPE,LMODE,REQUEST
FROM gv$Lock WHERE ID1=589854 AND ID2=26267;
INST_ID SID TY LMODE REQUEST
---- --
2 79 TX 0 6
1 73 TX 6 0
乙方DBA需謹慎
第三個知識點是考覈做爲乙方的謹慎,即便你查到了 blocker,是否是應該直接 kill 掉,必需要先徵詢客戶的意見,確認以後才能夠殺掉。
清除blocker
已經確認了能夠 kill 掉 session 以後,須要再找到相應 session的serail#,這是 kill session 時必須輸入的參數。
SQL> SELECT SID,SERIAL# [size=10.5000pt]
FROM gv$session [size=10.5000pt]
WHERE INST_ID=1 AND SID=73;
[size=10.5000pt]
SID SERIAL#[size=10.5000pt]
73 15625
若是是 11gR2 數據庫,那麼直接在實例2中加入@1參數就能夠殺掉實例1中的會話,若是是10g,那麼登入實例1再執行 kill session 的操做。
SQL> ALTER system [size=10.5000pt]
KILL SESSION '73,15625,@1';
[size=10.5000pt]
System altered.
再檢查以前被阻塞的更新會話,能夠看到已經更新成功了。
SQL> UPDATE emp SET ename='ENMOTECH' [size=10.5000pt]
WHERE empno=7369;[size=10.5000pt]
1 ROW updated.
對於熟悉整個故障解決過程的人,或者具有清晰思路的DBA,5分鐘以內就能夠解決問題。
深刻一步
對於 TX 鎖,在 v$lock 視圖中顯示的 ID1 和 ID2 是什麼意思? 解釋能夠從 v$lock_type 視圖中獲取。
SQL> SELECT ID1_TAG,ID2_TAG [size=10.5000pt]
FROM V$LOCK_TYPE WHERE TYPE='TX';
[size=10.5000pt]
ID1_TAG ID2_TAG[size=10.5000pt]
[size=10.5000pt]
usn<<16 | slot SEQUENCE
因此 ID1 是事務的 USN+SLOT,而 ID2 則是事務的 SQN。這些能夠從 v$transaction 視圖中得到驗證。
SQL> SELECT taddr
FROM v$session WHERE sid=73;
TADDR
000000008E3B65C0
SQL> SELECT XIDUSN,XIDSLOT,XIDSQN
FROM v$transaction
WHERE addr='000000008E3B65C0';
XIDUSN XIDSLOT XIDSQN
9 30 26267
如何和 ID1=589854 and ID2=26267 對應呢? XIDSQN=26267 和 ID2=26267 直接就對應了,沒有問題。 那麼 ID1=589854 是如何對應的?將之轉換爲16進制,是 0x9001E,而後分高位和低位分別再轉換爲10進制,高位的16進制9就是十進制的9,也就是 XIDUSN=9,而低位的16進制1E轉換爲10進制是30,也就是 XIDSLOT=30。
文章寫到這裏,突然感受網上那些一鼓作氣的故障診斷腳本其實挺誤人的,只須要給一個參數,運行一下腳本就列出故障緣由。因此不多人願意再去研究這個腳本爲何這麼寫,各個視圖之間的聯繫是如何環環相扣的。因此當你再也不使用本身的筆記本,再也不能迅速找到你賴以生存的那些腳本,你還能一步一步地解決故障嗎?