X$BH

zhouwf0726發表於2019-06-05

X$BH裡的幾個欄位的含義:

state:

0, FREE, no valid block image
1, XCUR, a current mode block, exclusive to this instance
2, SCUR, a current mode block, shared with other instances
3, CR, a consistent read (stale) block image
4, READ, buffer is reserved for a block being read from disk
5, MREC, a block in media recovery mode
6, IREC, a block in instance (crash) recovery mode


SQL> select

2 o.object_name,
3 decode(state,0,'free',1,'xcur',2,'scur',3,'cr', 4,'read',5,'mrec',
4 6,'irec',7,'write',8,'pi') state,
5 count(*) blocks
6 from x$bh b, dba_objects o
7 where b.obj = o.data_object_id
8 and o.object_name = 'WWF_TEST'
9 group by o.object_name, state
10 order by blocks desc;

OBJECT_NAME STATE BLOCKS
-------------------- ----- ----------
WWF_TEST xcur 19

FREE: not currently in use
XCUR: exclusive
SCUR: shared current
CR: CR block
READ: being read from disk
MREC: in media recovery mode
IREC: in instance recovery mode
WRITE: writing to disk
PI: past image block involved in cache fusion block transfer

lru_flag
LRU_FLAG=2,表示塊在LRU list的冷端,
LRU_FLAG=8,表示塊在LRU list的熱端
LRU_FLAG=0,表示沒有標識。

隱含引數_db_aging_hot_criteria表示瞭如果tch大於這個數,那麼
該塊將被移到LRU list的熱端。預設為2.
隱含引數_db_percent_hot_default表示熱端佔整個buffer的比例,
預設為50%.
SQL> select i.ksppinm parameter, v.ksppstvl VAL
2 from x$ksppi i, x$ksppcv v
3 where i.indx = v.indx
4 and i. ksppinm in ('_db_percent_hot_default',
5 '_db_aging_hot_criteria');

PARAMETER VAL
---------------------------------------
_db_percent_hot_default 50
_db_aging_hot_criteria 2

在對一個有著接近四十萬條記錄的表執行完全表掃描後,

執行如下命令:
alter session set events 'immediate trace name buffers level 4';

節選匯出的檔案:
CHAIN: 1112 LOC: 0x6A66685C HEAD: [657ddef0,657ddef0]
BH (0x657DDEF0) file#: 11 rdba: 0x02c04087 (11/16519) class 1 ba: 0x65208000
set: 3 dbwrid: 0 obj: 30908 objn: 30908
hash: [6a66685c,6a66685c] lru: [657dde7c,657ddff4]
LRU flags: moved_to_tail
ckptq: [NULL] fileq: [NULL]
st: XCURRENT md: NULL rsop: 0x00000000 tch: 0
flags: only_sequential_access
LRBA: [0x0.0.0] HSCN: [0xffff.ffffffff] HSUB: [255] RRBA: [0x0.0.0]
buffer tsn: 12 rdba: 0x02c04087 (11/16519)
scn: 0x0000.000af5f5 seq: 0x02 flg: 0x04 tail: 0xf5f50602
frmt: 0x02 chkval: 0x6af6 type: 0x06=trans data
Block header dump: 0x02c04087
Object id on Block? Y
seg/obj: 0x78bc csc: 0x00.af5ee itc: 3 flg: - typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01

可以看到,state為XCURRENT,
flags為only_sequential_access
LRU flags為: moved_to_tail
表示該資料塊經歷了依次全表掃描,它被移到LRU的冷端,隨時都可能被age out。

查詢快(11,16519)塊的flag,得到:
SQL> select class, flag, state, lru_flag from x$bh
2 where dbarfil = 11 and dbablk = 16519;

CLASS FLAG STATE LRU_FLAG
---------- ---------- ---------- ----------
1 524288 1 3

flag為524288,也就是第20位被置為1,因為執行了“only_sequential_access”。
flag中,每位代表如下含義:
bit bit
0 buffer_dirty 14 stale
1 notify_after_change 15 deferred_ping
2 mod_started 16 direct_access
3 block_has_been_logged 17 hash_chain_dump
4 temp_data 18 ignore_redo
5 being_written 19 only_sequential_access
6 waiting_for_write 20 prefetched_block
7 multiple_waiters 21 block_written_once
8 recovery_reading 22 logically_flushed
9 unlink_from_lock 23 resilvered_already
10 down_grade_lock 25 redo_since_read
11 clone_being_written 29 plugged_from_foreign_db
12 reading_as_CR 30 flush_after_writing
13 gotten_in_current_mode


/**********************************/

SQL> show user
User is "SYS"

SQL> select owner,object_id from dba_objects where object_name='A';

OWNER OBJECT_ID
------------------------------ ----------
ROME 60026

SQL> select count(*) from x$bh where obj=60026;

COUNT(*)
----------
0

SQL> select * from rome.a;

ID
--------------------
10.100
10.110
10.111

SQL> select count(*) from x$bh where obj=60026;

COUNT(*)
----------
6

SQL> select count(*) from x$bh where obj=60026 and state=1;

COUNT(*)
----------
6

SQL> alter system flush buffer_cache;

System altered

SQL> select count(*) from x$bh where obj=60026 and state=1;

COUNT(*)
----------
0

SQL> select * from rome.a;

ID
--------------------
10.100
10.110
10.111

SQL> select count(*) from x$bh where obj=60026 and state=1;

COUNT(*)
----------
6

SQL>


如果有興趣可以看一下執行計劃在cache和no cache情況下物理讀的變化。

SQL> ALTER TABLE ROME.A STORAGE (BUFFER_POOL KEEP);

Table altered

SQL> select decode(wbpd.bp_id,
2 1,'keep',
3 2,'recycle',
4 3,'default',
5 4,'2k pool',
6 5,'4k pool',
7 6,'8k pool',
8 7,'16k pool',
9 8,'32k pool',
10 'unknown') pool,
11 bh.owner,
12 bh.object_name object_name,
13 count(1) numOfBuffers
14 from x$kcbwds wds,
15 x$kcbwbpd wbpd,
16 (select set_ds, x.addr, o.name object_name, u.name owner
17 from sys.obj$ o, sys.user$ u, x$bh x
18 where o.owner# = u.user#
19 and o.dataobj# = x.obj
20 and x.state != 0
21 and o.owner# != 0
22 ) bh
23 where wds.set_id >= wbpd.bp_lo_sid
24 and wds.set_id <= wbpd.bp_hi_sid
25 and wbpd.bp_size != 0
26 and wds.addr = bh.set_ds
27 and object_name='A'
28 group by decode(wbpd.bp_id,
29 1,'keep',
30 2,'recycle',
31 3,'default',
32 4,'2k pool',
33 5,'4k pool',
34 6,'8k pool',
35 7,'16k pool',
36 8,'32k pool',
37 'unknown'),
38 bh.owner,
39 bh.object_name
40 order by 1, 4, 3, 2;

POOL OWNER OBJECT_NAME NUMOFBUFFERS
-------- ------------------------------ ------------------------------ ------------
default ROME A 2

SQL> select * from rome.a;

ID
--------------------
10.100
10.110
10.111

SQL>
SQL> select decode(wbpd.bp_id,
2 1,'keep',
3 2,'recycle',
4 3,'default',
5 4,'2k pool',
6 5,'4k pool',
7 6,'8k pool',
8 7,'16k pool',
9 8,'32k pool',
10 'unknown') pool,
11 bh.owner,
12 bh.object_name object_name,
13 count(1) numOfBuffers
14 from x$kcbwds wds,
15 x$kcbwbpd wbpd,
16 (select set_ds, x.addr, o.name object_name, u.name owner
17 from sys.obj$ o, sys.user$ u, x$bh x
18 where o.owner# = u.user#
19 and o.dataobj# = x.obj
20 and x.state != 0
21 and o.owner# != 0
22 ) bh
23 where wds.set_id >= wbpd.bp_lo_sid
24 and wds.set_id <= wbpd.bp_hi_sid
25 and wbpd.bp_size != 0
26 and wds.addr = bh.set_ds
27 and object_name='A'
28 group by decode(wbpd.bp_id,
29 1,'keep',
30 2,'recycle',
31 3,'default',
32 4,'2k pool',
33 5,'4k pool',
34 6,'8k pool',
35 7,'16k pool',
36 8,'32k pool',
37 'unknown'),
38 bh.owner,
39 bh.object_name
40 order by 1, 4, 3, 2;

POOL OWNER OBJECT_NAME NUMOFBUFFERS
-------- ------------------------------ ------------------------------ ------------
default ROME A 2
keep ROME A 4

更多cache table資訊參看:
http://zhouwf0726.itpub.net/post/9689/243151

/*************相關資料****************/

在本篇Oracle高階教程裡,我會探討Oracle資料緩衝區的內部機制——Oracle用這一記憶體來防止不必要的資料塊從磁碟重讀。理解Oracle資料緩衝區如何操作,是成功地運用它們調整資料庫效能的關鍵。

在Oracle 8i以前的版本里,當資料塊被從磁碟送進資料緩衝區的時候,資料塊會被自動地放置到最近使用過的資料列表的前部。但是,這種行為從Oracle 8i開始就變了:新資料緩衝區被放置在緩衝區鏈的中部。在調節資料庫的時候,你的目標就是為資料緩衝區分配儘量多的記憶體,而不會導致資料庫伺服器在記憶體裡分頁。資料緩衝區每小時的命中率一旦低於90%,你就應該為資料塊緩衝區增加緩衝區。

資料塊的存活時間

在調入資料塊之後,Oracle會不停地跟蹤資料塊的使用計數(touch count,也就是說,這個資料塊被使用者執行緒所訪問的次數)。如果一個資料塊被多次使用,它就被移動到最近使用過的資料列表的最前面,這樣就能確保它會在記憶體裡儲存一段較長的時間。這種新的中點插入技術會確保最常使用的資料塊被保留在最近使用過的資料列表的最前面,因為新的資料塊只有在它們被重複使用的時候才會被移動到緩衝區鏈的最前面。

總而言之,Oracle 8i資料緩衝池的管理要比先前的版本更加有效。通過將新的資料塊插入緩衝區的中部,並根據訪問活動(頻率)調整緩衝區鏈,每個資料緩衝區就被分割成兩個部分:熱區(hot section),代表資料緩衝區的最近使用的一半;冷區(cold section),代表資料緩衝區的最早使用的一半。只有那些被反覆請求的資料塊才會被移進每個緩衝池的熱區,這就讓每個資料緩衝區在緩衝常用資料塊的時候效率更高。

熱區的大小要用下面的隱藏引數來配置:

_db_percent_hot_default 
_db_percent_hot_keep 
_db_percent_hot_recycle

Oracle公司作為官方沒有推薦更改這些隱藏引數。只有懂得內部機制和希望調節其資料緩衝區行為的有經驗人員才應該使用這些引數。

找到熱資料塊

Oracle 8i保留著一個X$BH內部檢視錶,用來顯示資料緩衝池的相對效能。X$BH檢視錶有下列資料列:

Tim:兩次使用之間的時間差,和_db_aging_touch_time引數相關。

Tch:使用計數,它和被使用過_db_aging_hot_criteria次之後從冷區移入熱區直接相關。

由於Tch資料列用來追蹤特定資料塊的使用次數,所以你就能夠編寫一個字典查詢來顯示緩衝區裡的熱資料塊——使用計數大於10的資料塊,就像下面這樣:

SELECT
   obj      object,
   dbarfil  file#,
   dbablk   block#,
   tch      touches
FROM
   x$bh
WHERE
   tch > 10
ORDER BY
   tch desc;

這項高階查詢技術在用於追蹤DEFAULT緩衝池裡的物件時尤其有用。一旦定位了熱資料塊,你就能夠把它們從DEFAULT緩衝池移動到KEEP緩衝池。

完全緩衝資料庫

從Oracle 8i開始,隨著64位定址的出現,你就能夠建立一個完全在資料緩衝區裡緩衝的資料庫。現今,任何資料庫通常只用不到20G的記憶體就能夠被完全緩衝,而更大的資料庫仍然需要部分資料緩衝區。

要利用完全資料緩衝的優勢,就要記住從記憶體取回資料塊和從磁碟取回資料塊的時間差。對磁碟的訪問時間是以毫秒或者說千分之一秒來計算的,而記憶體的速度是以納秒或者說十億分之一秒來計算的。因此記憶體的訪問速度要快三個數量級,即通常要比磁碟的訪問速度塊將近14,000倍。

在完全緩衝Oracle資料庫的時候,你需要仔細制定緩衝的規劃,並在需要的時候增加db_block_ buffers引數的值。在緩衝整個資料庫的時候,多資料緩衝池就不再需要了,所以你可以在DEFAULT資料池裡緩衝所有的資料塊。

如果要計算已分配資料塊的數量,就要用下面的命令:

select
   sum(blocks)
from
   dba_data_files;

SUM(BLOCKS)
-----------
     243260

select
   sum(blocks)
from
   dba_extents;

SUM(BLOCKS)
-----------
     321723

已使用資料塊的真實數量要通過檢視DBMS_ROWID以獲得真實的資料庫地址來確定,就像下面這樣:

select
   sum(blocks)
from
   dba_data_files;

隨著資料庫的擴充套件,你必須不忘增加引數的值。在資料庫的啟動階段,你需要呼叫一個指令碼載入緩衝區,這一步很簡單,就像執行select count(*) from xxx;這樣的命令,因為資料庫裡所有表格都會起作用。這就確保所有的資料塊都被緩衝,從而大幅提高讀取操作的效能。但是,寫操作仍然會需要磁碟I/O。由於記憶體條的價格在持續下跌,現在只需要較小的或者不需要硬體投資就能夠通過完全緩衝一個較小的資料庫從而顯著地提高效能。

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

相關文章