X$BH

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/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/756652/viewspace-242392/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值