環境:oracle 12.1.0.2 rac ,4節點 一、概述 通常來說,如果是oltp應用,那麼部署在rac上,是不錯的註意。 但實現情況中,往往是混合類型,既有OLTP也有OLAP。 如果沒有很好地進行資源管理和系統設計,那麼系統的性能往往不如人意。 造成系統慢的原因很多,其中一個就是orac ...
環境:oracle 12.1.0.2 rac ,4節點
一、概述
通常來說,如果是oltp應用,那麼部署在rac上,是不錯的註意。
但實現情況中,往往是混合類型,既有OLTP也有OLAP。
如果沒有很好地進行資源管理和系統設計,那麼系統的性能往往不如人意。
造成系統慢的原因很多,其中一個就是oracle rac特有結構的負面作用。
--
例如如果一個過程或者包正在執行,且是一個長會話,需要很久才會釋放,這個時候企圖編譯包,造成的一個大問題就是系統變慢,登錄變慢。
這是因為,編譯會話企圖獲得執行包的排它鎖,所以它需要不停地輪詢各個實例,看這個對象是否被鎖,結果毫無疑問,是被鎖住,過了一會又會去查詢。
而我們知道,在多個實例之間查詢對象的鎖狀態還是比較費時的,尤其是系統中有巨量鎖的情況下,這個會耗費許多的CPU。
最終就是系統變慢。
二、方法
那麼是否有可以解決的辦法了?
oracle本身並不提供這樣的工具,但作為dba只能取監測這樣的監測過程。
那麼應該監視什麼字典表呢?
監視v$db_cache_object
關鍵的問題是,這個視圖不知道是哪個會話,所以即使知道了,也難於執行kill session的操作。
監視dba_ddl_locks
註:在這個視圖中,不表明這個對象無法被編譯,除非是排它的鎖。
dba_ddl_lock$的定義
create or replace view sys.dba_ddl_locks as select s.sid session_id, substr(ob.kglnaown,1,30) owner, substr(ob.kglnaobj,1,30) name, decode(ob.kglhdnsp, 0, 'Cursor', 1, 'Table/Procedure/Type', 2, 'Body', 3, 'Trigger', 4, 'Index', 5, 'Cluster', 13, 'Java Source', 14, 'Java Resource', 32, 'Java Data', to_char(ob.kglhdnsp)) type, decode(lk.kgllkmod, 0, 'None', 1, 'Null', 2, 'Share', 3, 'Exclusive', 'Unknown') mode_held, decode(lk.kgllkreq, 0, 'None', 1, 'Null', 2, 'Share', 3, 'Exclusive', 'Unknown') mode_requested from v$session s, x$kglob ob, x$kgllk lk where lk.kgllkhdl = ob.kglhdadr and lk.kgllkuse = s.saddr and ob.kglhdnsp != 0;
其中
x$kgllk ---[K]ernel [G]eneric [L]ibrary Cache Manager object [L]oc[K]s --核心庫緩存管理對象鎖
x$kglob---[K]ernel [G]eneric [L]ibrary Cache Manager [OB]ject --核心庫緩存管理對象
前者是後者的明細,雙方通過
--關於x$kgllk的定義
http://blog.itpub.net/69265/viewspace-442931/
SQL> desc x$kgllk;
名稱 類型
---------- -----------
ADDR RAW(4)
INDX NUMBER
INST_ID NUMBER
KGLLKADR RAW(4) --
KGLLKUSE RAW(4) ---會話地址(對應v$session的saddr)
KGLLKSES RAW(4) ---owner地址
KGLLKSNM NUMBER ---SID
KGLLKHDL RAW(4) ---library cache object 句柄
KGLLKPNC RAW(4) ---the address of the call pin
KGLLKPNS RAW(4) ---對應跟蹤文件中的session pin值
KGLLKCNT NUMBER
KGLLKMOD NUMBER ---持有鎖的模式(0為no lock/pin held﹐1為null,2為share﹐3為exclusive)
KGLLKREQ NUMBER ---請求鎖的模式(0為no lock/pin held﹐1為null,2為share﹐3為exclusive)
KGLLKFLG NUMBER ---cursor的狀態﹐8(10g前)或2048(10g)表示這個sql正在運行﹐
KGLLKSPN NUMBER ---對應跟蹤文件的savepoint的值
KGLLKHTB RAW(4)
KGLNAHSH NUMBER ---sql的hash值(對應v$session的sql_hash_value)
KGLLKSQLID VARCHAR2(13) ---sql ID,sql標識符
KGLHDPAR RAW(4) ---sql地址(對應v$session的sql_address)
KGLHDNSP NUMBER
USER_NAME VARCHAR2(30) ---會話的用戶名
KGLNAOBJ VARCHAR2(60) ---對象名稱或者已分析並打開cursor的sql的前60個字元
--關於x$kglob的定義
參考:http://blog.itpub.net/11134237/viewspace-686353/
具體略。
在cdb-rac根中監視被鎖定過程和會話
原有的dba_ddl_locks視圖只是適用於單實例,為了方便cdb-rac的監視,必須進行調整。
create or replace view gv_ddl_locks as select s.con_id, p."PDB_NAME", s.inst_id, s.sid session_id, s.serial#, substr(ob.kglnaown,1,128) owner, substr(ob.kglnaobj,1,1000) name, decode(ob.kglhdnsp, 0, 'Cursor', 1, 'Table/Procedure/Type', 2, 'Body', 3, 'Trigger', 4, 'Index', 5, 'Cluster', 13, 'Java Source', 14, 'Java Resource', 32, 'Java Data', to_char(ob.kglhdnsp)) type, decode(lk.kgllkmod, 0, 'None', 1, 'Null', 2, 'Share', 3, 'Exclusive', 'Unknown') mode_held,lk.kgllkmod, decode(lk.kgllkreq, 0, 'None', 1, 'Null', 2, 'Share', 3, 'Exclusive', 'Unknown') mode_requested from gv$session s, x$kglob ob, x$kgllk lk,cdb_pdbs p,GV$DB_OBJECT_CACHE GCO where lk.kgllkhdl = ob.kglhdadr and lk.con_id=ob.con_id and lk.inst_id=ob.inst_id and lk.kgllkuse = s.saddr and lk.con_id=s.con_id and lk.inst_id=s.inst_id AND GCO.INST_ID=OB.INST_ID AND GCO.CON_ID=OB.CON_ID AND GCO.ADDR=OB.KGLHDADR AND GCO.LOCKS<>0 and p."CON_ID"=s.con_id and ob.kglhdnsp != 0;
以上語句在cdb$root創建。
這個視圖有幾個局限性:
- 由於需要使用動態視圖,所以有些運行時間短的糊化根本無法查詢到
- 由於動態視圖的特性,判斷對象是否被鎖定並不是非常適合--尤其是那些運行時間短的
- 在大的cdb-rac中執行,會變更比較慢
三、總結
1.如果僅僅是想簡單地知道什麼對象被鎖住,可以直接查詢:
select * from sys.gv_$db_object_cache x where x.owner='C##LUZHIFEI';
2.如果還想知道是什麼會話,需要執行前文的視圖(以sys執行)