Cache Buffer Chain Latch等待事件

pxbibm發表於2015-10-29
  

Cache Buffer Chain Latch等待事件
產生的背景:

    Oracle為了將物理IO最小化,把最近使用過的資料塊保持在記憶體中。為了管理這些記憶體,oracle 使用如圖的結構,

Hash Chain的結構,Hash Chain位於共享池中,使用典型記憶體結構Bucket->Chain->Header結構進行管理。

Hash Chain結構的起點是Hash表,Hash表由多個hash bucket組成,塊地址 是由file#+block#組成的,當掃描塊時使用Hash函式

進行hash運算,使用hash值查詢hash bucket,具有相同hash值的buffer haederhash bucket上以chain形式連結。

Buffer header有指向實際緩衝區的指標。注意:Hash Chain結構是在共享池中,而實際緩衝區資訊儲存在高速緩衝區中。

Hash Chain結構利用cache buffers chain Latch來保護。

當程式掃描特定的資料塊時,必須獲得相應資料塊所在Hash Chain管理的cache buffers chain Latch。基本上

一個程式獲得僅有的一個cache buffers chain Latch,一個cache buffers chain Latch管理多個Hash Chain

當多個程式同時檢索Buffer Cache時,獲得cache buffers chain Latch的過程中發生爭用,就會產生

cache buffers chain Latch等待事件。
程式掃描特定的資料塊整個過程。
  1、Oracle以每個塊的檔案號、塊號和型別做HASH運算,得到HASH值。根據HASH值,到HASH表中取出指定塊的記憶體地址 
  2、獲取CBC Latch
  3、根據HASH值,搜尋CBC連結串列
  4、根據DBA找到BH(Buffer Header)加Buffer Pin
  5、加完Buffer Pin馬上釋放CBC Latch
  6、訪問Buffer開始fetch資料
  7、獲取CBC Latch
  8、釋放Buffer Pin
  9、釋放CBC Latch

使用SQL語句可以獲得hash_latcheshash_buckets數量,因此一個鎖存器保護Bucket數量是1048576/32768=32個。

SQL> select x.ksppinm name,

  2         y.ksppstvl value,

  3         y.ksppstdf isdefault,

  4         decode(bitand(y.ksppstvf, 7),

  5                1,

  6                'MODIFIED',

  7                4,

              'SYSTEM_MOD',  8 

  9                'FALSE') ismod,

 10         decode(bitand(y.ksppstvf, 2), 2, 'TRUE', 'FALSE') isadj

 11    from sys.x$ksppi x, sys.x$ksppcv y

 12   where x.inst_id = userenv('Instance')

 13     and y.inst_id = userenv('Instance')

 14     and x.indx = y.indx

 15     and x.ksppinm like '%db_block_hash%'

 16   order by translate(x.ksppinm, ' _', ' ');


NAME        VALUE        ISDEFAUL ISMOD  ISADJ

--------------------------------------------- --------------- -------- -------- --------

_db_block_hash_buckets        1048576        TRUE     FALSE  FALSE

_db_block_hash_latches        32768        TRUE     FALSE  FALSE


產生的原因:

    1.執行效率低下的SQL,低效的SQL語句是發生Latch:cache buffers chains 爭用的主要原因。發生在多個程式同時掃描大範圍的表或索引時。

    2.出現熱塊hot block時,由於編寫SQL語句時,SQL持續掃描少數特定塊(between and ,in,not in, exists),多個會話同時執行SQL語句時,發生Latch:cache buffers chains 爭用。
【案例1 Latch:cache buffers chains爭用

--1.建立測試表
create table t1(id int,name varchar2(10));
insert into values(1,'xiaobo');
commit;
--2.獲取t1表的第一行資料及ROWID,根據dbms_rowid包查出這行資料的檔案號、塊號

SQL> select rowid,
       dbms_rowid.rowid_relative_fno(rowid) file#,
       dbms_rowid.rowid_block_number(rowid) block#,
       id,
       name
  from emm.t1
 where rownum = 1;  2    3    4    5    6    7 

ROWID   FILE#   BLOCK#  ID NAME
------------------ ---------- ---------- ---------- --------------------
AAADfaAAFAAAACDAAA     5      131   1 xiaobo
注意:這裡的DBA(Data Block Address)就是由5號檔案和131號塊組成

--3.根據DBA獲取CBC Latch的地址

SQL> select hladdr from x$bh where file#=5 and dbablk=131;

HLADDR
----------------
00000001D1C266D8

--4.根據CBC Latch的地址可以查出這個CBC Latch被獲得的次數

SQL> select addr,name,gets from v$latch_children  where addr='00000001D1C266D8';

ADDR                                        NAME                           GETS
----------------                          --------------------------------     -----------------------------------------------
00000001D1C266D8              cache buffers chains           46

--5.再次讀取t1表的第一行資料,再次產生一次邏輯讀
SQL>select id,name from emm.t1 where rowid='AAADfaAAFAAAACDAAA';
   ID      NAME
   --------            ------------
    1   xiaobo
--6.CBC Latch的次數變為48,說明一次邏輯讀產生兩次CBC Latch
SQL> select addr,name,gets from v$latch_children  where addr='00000001D1C266D8';
ADDR                                        NAME                           GETS
----------------                          --------------------------------     -----------------------------------------------
00000001D1C266D8              cache buffers chains           48

這裡說明一次邏輯讀要加兩次CBC Latch,一次為了加Buffer Pin,一次為了釋放Buffer Pin!
但是我不知道這裡如何通過實驗來證明,大家如果有好的建議,可以聯絡我。

使用oradebug跟蹤CBC Latch爭用事件

SQL> oradebug setmypid
Statement processed.
SQL> oradebug peek 0x1D1C266D8 4      -- 觀察CBC Latch地址為0x1D1C266D8開始之後的4位元組資訊的值為0
[1D1C266D8, 1D1C266DC) = 00000000
SQL> oradebug poke 0x1D1C266D8 4 1   --修改CBC Latch地址為0x1D1C266D8開始的4位元組資訊的值為1,相當於獲取了Latch
BEFORE: [1D1C266D8, 1D1C266DC) = 00000000 --修改前的值
AFTER: [1D1C266D8, 1D1C266DC) = 00000001   --修改後的值

--7. 再開一個新的會話,會話號為768

SQL> conn / as sysdba
Connected.
SQL> select sid from v$mystat where rownum=1;

       SID
----------
       768

 
--8.在新會話768T1的第一行,我觀察到不會堵塞。但是我看網上有些網友寫的部落格說這裡會產生堵塞。
這樣的說法是不正確的。原因我會做完下個實驗給大家解釋,這裡多說一句,大家看到網上的一些技術文章,一定
要自己動手做實驗。如果發現和文章說明的不一樣,一定要查閱資料。一直到搞清楚。
SQL>select id,name from emm.t1 where rowid='AAADfaAAFAAAACDAAA';
   ID      NAME
   --------            ------------
    1   xiaobo
 
--9.我們回到oradebug的會話,這次我們不是使用select語句,而使用update語句來獲取latch

SQL> update emm.t1 set id=2 where rowid='AAADfaAAFAAAACDAAA';

1 row updated.

--10.再次使用oradebug模擬獲取latch
SQL> oradebug setmypid
Statement processed.
SQL> oradebug poke 0x1D1C266D8 4 1
BEFORE: [1D1C266D8, 1D1C266DC) = 00000000
AFTER: [1D1C266D8, 1D1C266DC) = 00000001


--11.回到剛才768會話下,T1的第一行,這時我觀察到產生了堵塞
SQL>select id,name from emm.t1 where rowid='AAADfaAAFAAAACDAAA';


--12.我們再開第三個會話,檢視會話號768的等待事件,我們看到產生了CBC Latch的等待事件

SQL> select sid,event,p1raw,p2raw,p3raw from v$session where sid=768;

       SID        EVENT                               P1RAW                      P2RAW                   P3RAW
----------------   -------------------------------------  -------------------------        ---------------------------     -------
       768      latch: cache buffers chains    00000001D1C266D8    00000000000000B1    00

最後在第一個會話中釋放lacth
SQL> oradebug poke 0x1D1C266D8 4 0
BEFORE: [1D1C266D8, 1D1C266DC) = 00000001
AFTER: [1D1C266D8, 1D1C266DC) = 00000000
總結:
在獲取保護hash bucket的cache buffers chains latch時,如果是讀取工作(select),就以shared模式獲
得(這也是我們剛才在實驗中select時沒有產生爭用的原因)。如果是修改工作(update),就以exclusive模式
獲得。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12798004/viewspace-1818231/,如需轉載,請註明出處,否則將追究法律責任。

相關文章