学习oracle动态性能表--V$BH

v$bh

oralce使用v$bh视图来记录与数据缓冲(data buffer)相关的信息,它详细记录了数据缓冲中每一个数据块(data block)的状态信息。
虽然Oracle最初开发V$BH查看表的时候把它用于Oracle平行服务器(Oracle Parallel Server,OPS),但是你也可以用V$BH查看表来显示数据库里每个对象类型的数据缓冲区里数据块的数量。
这个查询让人尤其兴奋,因为你现在可以知道哪些对象正在消耗数据缓冲区。在Oracle9i里,你可以使用这一信息来隔离表格,以便用不同的块大小来分隔RAM缓冲区。

一、各字段的说明如下:
----------------------------------------------
FILE# NUMBER Datafile identifier number (to find the filename, query DBA_DATA_FILES or V$DBFILE)
BLOCK# NUMBER Block number
CLASS# NUMBER Class number
STATUS VARCHAR2(6) Status of the buffer:
free - Not currently in use,表示这是一个限制的数据块,oracle现在没有使用它;

xcur - Exclusive(exclusive current),表示该数据块处于排外模式;

scur - Shared current,表示该数据库正在和其他实例共享数据。

cr - Consistent read,表示该数据块是一个克隆(clone)的数据库,可以执行共享的只读操作;

read - Being read from disk,表示该数据块正在从磁盘读取数据;

mrec - In media recovery mode,表示数据块处于介质恢复模式;

irec - In instance recovery mode,表示数据块处于实例恢复模式;

XNC NUMBER Number of PCM x to null lock conversions due to contention with another instance. This column is obsolete and maintained for backward compatibility.
LOCK_ELEMENT_ADDR RAW(4 | 8) Address of the lock element that contains the PCM lock that is covering the buffer. If more than one buffer has the same address, then these buffers are covered by the same PCM lock.
LOCK_ELEMENT_NAME NUMBER The address of the lock element that contains the PCM lock that is covering the buffer. If more than one buffer has the same address, then these buffers are covered by the same PCM lock.
LOCK_ELEMENT_CLASS NUMBER The address of the lock element that contains the PCM lock that is covering the buffer. If more than one buffer has the same address, then these buffers are covered by the same PCM lock.
FORCED_READS NUMBER Number of times the block had to be reread from the cache because another instance has forced it out of this instance's cache by requesting the lock on the block in exclusive mode
FORCED_WRITES NUMBER Number of times GCS had to write this block to cache because this instance had used the block and another instance had requested the lock on the block in a conflicting mode
DIRTY VARCHAR2(1) Y - block modified
TEMP VARCHAR2(1) Y - temporary block
PING VARCHAR2(1) Y - block pinged
STALE VARCHAR2(1) Y - block is stale
DIRECT VARCHAR2(1) Y - direct block
NEW VARCHAR2(1) Always set to N. This column is obsolete and maintained for backward compatibility.
OBJD NUMBER Database object number of the block that the buffer represents
TS# NUMBER Tablespace number of block

二、CLASS#的数据来源于如下:
---------------------------
SQL> select distinct class# from v$bh;

    CLASS#
----------
         1
         4
         8
         9
        12
        13
        15
        17
        18
        19
        20

    CLASS#
----------
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31

    CLASS#
----------
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42

33 rows selected.

SQL> select * from v$waitstat;

CLASS                   COUNT       TIME
------------------ ---------- ----------
data block           23369217    5855617
sort block                  0          0
save undo block             0          0
segment header            238        162
save undo header            0          0
free list                   0          0
extent map                  0          0
1st level bmb             323         95
2nd level bmb              79         35
3rd level bmb               0          0
bitmap block                0          0

CLASS                   COUNT       TIME
------------------ ---------- ----------
bitmap index block          0          0
file header block         220       6458
unused                      0          0
system undo header          0          0
system undo block           0          0
undo header             13694       1794
undo block              16828       2699

18 rows selected.

SQL> select  count(*) from v$rollstat;

  COUNT(*)
----------
        14

SQL>




其中 v$bh 里面的 class# 的 1 ---14 分别对应如下类型
data block           23369217    5855617         -------  1
sort block                  0          0         -------  2
save undo block             0          0        -------  3
segment header            238        162
save undo header            0          0
free list                   0          0
extent map                  0          0
1st level bmb             323         95
2nd level bmb              79         35
3rd level bmb               0          0
bitmap block                0          0

CLASS                   COUNT       TIME
------------------ ---------- ----------
bitmap index block          0          0
file header block         220       6458        -------  13
unused                                           ---------  14


system undo header          0          0         --------   15
system undo block           0          0         ----------   16
undo header 1                                  --------------- 17
undo  block  1                                 -------------- 18
undo  header 2                                   -------------- 19
undo  block   2                                 -------------- 20
依次类推

(9i里v$bh里从class 15开始是undo segment header,undo block。class对应着15+2*usn的规则,奇数对应header,偶数对应block,usn号可以从v$rollstat中得到,
比如system undo header对应class15.在rac环境中,则对应着gv$rollstat中的usn.)

我这里的 回滚段(算上系统回滚段)一共是 14  = v$rollstat.count(*) ,v$waitstat.count(*) = 18(但是这里计算了 系统回滚段和非系统回滚段共4条记录)
所以就是 14*2 + (18 - 4) = 42
42也就是 v$bh 中类型编号最大的

而中间有些不存在的编号,也就是如
save undo block             0          0        -------  3
这样暂时不存在的block

三、示例1
----------------------------------------------
SQL> create table a_test(f1 varchar2(30));

Table created.

SQL> insert into a_test values('99999');

1 row created.

SQL> select obj# from sys.obj$ where name = 'A_TEST';

      OBJ#
----------
     11046

SQL> select file#,block#,class#,status  from v$bh where bjd=&1   
  2  ;   
Enter value for 1: 11046
old   1: select file#,block#,class#,status  from v$bh where bjd=&1
new   1: select file#,block#,class#,status  from v$bh where bjd=11046

     FILE#     BLOCK#     CLASS# STATUS
---------- ---------- ---------- -------
         3      16497          8 xcur
         3      16498          9 xcur
         3      16499          4 xcur
         3      16500          1 xcur
         3      16501          1 xcur
         3      16502          1 xcur
         3      16503          1 xcur
         3      16504          1 xcur

8 rows selected.

SQL> commit;

Commit complete.

SQL> select file#,block#,class#,status  from v$bh where bjd=&1;
Enter value for 1: 11046
old   1: select file#,block#,class#,status  from v$bh where bjd=&1
new   1: select file#,block#,class#,status  from v$bh where bjd=11046

     FILE#     BLOCK#     CLASS# STATUS
---------- ---------- ---------- -------
         3      16497          8 xcur
         3      16498          9 xcur
         3      16499          4 xcur
         3      16500          1 xcur
         3      16501          1 xcur
         3      16502          1 xcur
         3      16503          1 xcur
         3      16504          1 xcur

8 rows selected.

SQL> update a_test set f1='11111';

1 row updated.

SQL> select file#,block#,class#,status  from v$bh where bjd=&1;
Enter value for 1: 11046
old   1: select file#,block#,class#,status  from v$bh where bjd=&1
new   1: select file#,block#,class#,status  from v$bh where bjd=11046

     FILE#     BLOCK#     CLASS# STATUS
---------- ---------- ---------- -------
         3      16497          8 xcur
         3      16498          9 xcur
         3      16499          4 xcur
         3      16500          1 xcur
         3      16501          1 xcur
         3      16502          1 xcur
         3      16503          1 xcur
         3      16504          1 cr
         3      16504          1 xcur

9 rows selected.

SQL> commit;

Commit complete.

SQL> select file#,block#,class#,status  from v$bh where bjd=&1;
Enter value for 1: 11046
old   1: select file#,block#,class#,status  from v$bh where bjd=&1
new   1: select file#,block#,class#,status  from v$bh where bjd=11046

     FILE#     BLOCK#     CLASS# STATUS
---------- ---------- ---------- -------
         3      16497          8 xcur
         3      16498          9 xcur
         3      16499          4 xcur
         3      16500          1 xcur
         3      16501          1 xcur
         3      16502          1 xcur
         3      16503          1 xcur
         3      16504          1 cr
         3      16504          1 xcur
9 rows selected.

四、示例2
----------------------------------------------
1,创建一个测试表,test,并且插入10000行数据;
    SQL>  create table test (id int);

    SQL> begin
      2  for i in 1..10000 loop
      3  insert into test values(i)
      4  end loop;
      5  end;
      6  /

    SQL> commit;

2,创建一个存储过程SHOW_SPACE:
create or replace procedure show_space

    ( p_segname in varchar2,

  p_owner   in varchar2 default user,

  p_type    in varchar2 default 'TABLE',

  p_partition in varchar2 default NULL )

as

    l_total_blocks              number;

    l_total_bytes               number;

    l_unused_blocks             number;

    l_unused_bytes              number;

    l_LastUsedExtFileId         number;

    l_LastUsedExtBlockId        number;

    l_last_used_block           number;

    procedure p( p_label in varchar2, p_num in number )

    is

    begin

        dbms_output.put_line( rpad(p_label,40,'.') ||

                              p_num );

    end;

begin

   

    dbms_space.unused_space

    ( segment_owner     => p_owner,

      segment_name      => p_segname,

      segment_type      => p_type,

      partition_name    => p_partition,

      total_blocks      => l_total_blocks,

      total_bytes       => l_total_bytes,

      unused_blocks     => l_unused_blocks,

      unused_bytes      => l_unused_bytes,

      last_used_extent_file_id => l_LastUsedExtFileId,

      last_used_extent_block_id => l_LastUsedExtBlockId,

      last_used_block => l_last_used_block );



    p( 'Total Blocks', l_total_blocks );

    p( 'Total Bytes', l_total_bytes );

    p( 'Unused Blocks', l_unused_blocks );

    p( 'Unused Bytes', l_unused_bytes );

    p( 'Last Used Ext FileId', l_LastUsedExtFileId );

    p( 'Last Used Ext BlockId', l_LastUsedExtBlockId );

    p( 'Last Used Block', l_last_used_block );

end;
/

3,检查表test的空间使用情况:
    SQL> exec show_space('TEST');
    Total Blocks............................24
    Total Bytes.............................196608
    Unused Blocks...........................3
    Unused Bytes............................24576
    Last Used Ext FileId....................1
    Last Used Ext BlockId...................62177
    Last Used Block.........................5
  
    由上可知,该表test共占用了24个数据块,196608字节,文件ID为1

4, 获得表test在数据块中的分布情况:
  SQL> select f,b from (
  2  select dbms_rowid.rowid_relative_fno(rowid) f,
  3         dbms_rowid.rowid_block_number(rowid) b
  4  from test) group by f,b order by b;

         F          B
---------- ----------
         1      62162
         1      62163
         1      62164
         1      62165
         1      62166
         1      62167
         1      62168
         1      62169
         1      62170
         1      62171
         1      62172
         1      62173
         1      62174
         1      62175
         1      62176
         1      62177

16 rows selected.
    由此可见,表test中的数据共占用了16个数据块,但是前面第三步中,发现该表占用了24个数据块。这是正常的,因为oracle本身会使用8个数据库来记录段头、位图块等额外的信息。我们现在只需要了解到,表test共占用了24个数据块,其中16个是数据,8个是表信息。

5,检查x$bh和v$bh的更新:
  SQL> select file#,dbablk,tch from x$bh where bj=
  2  (select data_object_id from dba_objects
  3  where wner='SYS'  and object_name='TEST')
  4  order by dbablk;

     FILE#     DBABLK        TCH
---------- ---------- ----------
         1      62161          6
         1      62162          3
         1      62163          3
         1      62164          3
         1      62165          3
         1      62166          3
         1      62167          3
         1      62168          3
         1      62169          3
         1      62170          3
         1      62171          3
         1      62172          3
         1      62173          3
         1      62174          3
         1      62175          3
         1      62176          3
         1      62177          3
         1      62178          3
         1      62179          3
         1      62180          3
         1      62181          3

21 rows selected.

  SQL> select file#,block#,status from v$bh where bjd=
  2  (select data_object_id from dba_objects
  3  where wner='SYS'  and object_name='TEST')
  4  order by block#;

     FILE#     BLOCK# STATUS
---------- ---------- -------
         1      62161 xcur
         1      62162 xcur
         1      62163 xcur
         1      62164 xcur
         1      62165 xcur
         1      62166 xcur
         1      62167 xcur
         1      62168 xcur
         1      62169 xcur
         1      62170 xcur
         1      62171 xcur
         1      62172 xcur
         1      62173 xcur
         1      62174 xcur
         1      62175 xcur
         1      62176 xcur
         1      62177 xcur
         1      62178 xcur
         1      62179 xcur
         1      62180 xcur
         1      62181 xcur

21 rows selected.

    这里可以看到,在v$bh和x$bh中得到的数据块,是从62161~62181的21条记录,但是在第四步中,我们知道数据是占用了62162~62177的16个数据库,这里,62161数据块里面存放的是段头信息,可以通过如下命令进行验证:
  SQL> select header_file,header_block from dba_segments
  2  where wner='SYS' and segment_name='TEST';

    HEADER_FILE HEADER_BLOCK
    ----------- ------------
          1        62161

    在v$bh视图中,我们可以看到这21个数据块都是xcur状态,表示这些数据块都是排斥状态,正在被使用,该字段还有其他的类型,请参见数据块的状态类型。

6,清空数据缓存:
    SQL> alter system flush buffer_cache;

7,重新检查v$bh和x$bh的内容:
  SQL> select file#,dbablk,tch from x$bh where bj=
  2  (select data_object_id from dba_objects
  3  where wner='SYS'  and object_name='TEST')
  4  order by dbablk;

     FILE#     DBABLK        TCH
---------- ---------- ----------
         1      62161          0
         1      62162          0
         1      62163          0
         1      62164          0
         1      62165          0
         1      62166          0
         1      62167          0
         1      62168          0
         1      62169          0
         1      62170          0
         1      62171          0
         1      62172          0
         1      62173          0
         1      62174          0
         1      62175          0
         1      62176          0
         1      62177          0
         1      62178          0
         1      62179          0
         1      62180          0
         1      62181          0

21 rows selected.

    SQL> select file#,block#,status from v$bh where bjd=
  2  (select data_object_id from dba_objects
  3  where wner='SYS'  and object_name='TEST')
  4  order by block#;

     FILE#     BLOCK# STATUS
---------- ---------- -------
         1      62161 free
         1      62162 free
         1      62163 free
         1      62164 free
         1      62165 free
         1      62166 free
         1      62167 free
         1      62168 free
         1      62169 free
         1      62170 free
         1      62171 free
         1      62172 free
         1      62173 free
         1      62174 free
         1      62175 free
         1      62176 free
         1      62177 free
         1      62178 free
         1      62179 free
         1      62180 free
         1      62181 free

21 rows selected.

    这时候我们可以看到,x$bh中的tch字段,已经由原来的3变成了0,同时v$bh视图的数据块状态也变成了free,但是记录的数据块并没有发生变化,还是在62161~62181这些数据块中,这就是说,虽然数据已经被写到了磁盘中,但是数据库记录的指针并没有清空,仅仅是其状态发生了改变。

8,进阶
     明白是oracle数据库管理数据块的部分工作模式后,我们可以利用v$bh文件统计对象在数据缓冲中被cache的块数了,如:
    SQL> select count(*) from v$bh where bjd=
  2  (select data_object_id from dba_objects
  3  where wner='SYS'  and object_name='TEST')
  4  and status != 'free';

  COUNT(*)
----------
        17
    表示表test中有17个数据块还存在于缓存当中。

五、示例3
------------------------------------------------
下面是一个示例查询,它显示了数据库里每个对象对数据缓冲区的使用情况。要注意,这个脚本使用了一个Oracle9i标量子查询,而它在Oracle9i之前的系统里是无法使用的,除非你注释掉c3这个列。

column c0 heading 'Owner'                     format a15
column c1 heading 'Object|Name'               format a30
column c2 heading 'Number|of|Buffers'         format 999,999 
column c3 heading 'Percentage|ofData|Buffer' format 999,999,999

select
   owner                        c0,
   object_name                  c1,
   count(1)                     c2,
   (count(1)/(select count(*) from v$bh)) *100  c3
from
   dba_objects o,
   v$bh        bh
where
   o.object_id  = bh.objd
and
   o.owner not in ('SYS','SYSTEM','AURORA$JIS$UTILITY$')
group by
   owner,
   object_name
order by
   count(1) desc
;

下面是一个来自Oracle Financials数据库的一个真实列表。我们很容易就可以看到数据缓冲区里最常用的表格,以及它们所消耗的内存量。在规划Oracle9i里的多数据缓冲池的时候,这就是无价的信息。

                                                                                                                      Number
                                        Object                                                                  of
Owner                             Name                                                                   Buffers
---------------                    ------------------------------                                       --------
INV                                 MTL_SYSTEM_ITEMS                                      7,098
WIP                                WIP_TRANSACTION_ACCOUNTS_N1        6,583
PERFSTAT                    STATS$ERROR_LOG                                         5,635
OE                                   SO_LINES_ALL                                                   5,091
OE                                   SO_LINES_ALL                                                   5,091
INV                                 MTL_DEMAND                                                  4,924
INV                                 MTL_ITEM_CATEGORIES                               3,098
MRP                               MRP_FORECAST_DATES                                2,248

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/95233/viewspace-584623/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/95233/viewspace-584623/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值