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. 其实这里也可以直接查询 dba_segments看到这些信息.   

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 obj=

  2  (select data_object_id from dba_objects

  3  where owner='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 objd=

  2  (select data_object_id from dba_objects

  3  where owner='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 owner='SYS' and segment_name='TEST';


    HEADER_FILE HEADER_BLOCK

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

          1        62161


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

oracle缓冲块(data block)状态类型



 

6,清空数据缓存:

    SQL> alter system flush buffer_cache;

(在Oracle9i里,Oracle提供了一个内部事件,用以强制刷新Buffer Cache,其语法为:


alter session set events 'immediate trace name flush_cache level 1';


或者:


alter session set events = 'immediate trace name flush_cache';


类似的也可以使用alter system系统级设置:


alter system set events = 'immediate trace name flush_cache';


在Oracle10g中,Oracle提供一个新的特性,可以通过如下命令刷新Buffer Cache:


alter system flush buffer_cache;

 

7,重新检查v$bh和x$bh的内容:

  SQL> select file#,dbablk,tch from x$bh where  obj=

  2  (select data_object_id from dba_objects

  3  where owner='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 objd=

  2  (select data_object_id from dba_objects

  3  where owner='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这些数据块中,这就是说,虽然数据已经被写到了磁盘中,但是数据库记录的指针并没有清空,仅仅是其状态发生了改变。

我们读取到了x$bh中的tch字段,该字段表示的该字段被读取/写入的次数,这个值在oracle的LRU算法中,是一个重要的参数,如果这个字段被访问,则该值就会增加:

tch(touch count) 是通过touch标记的方式在追踪热块.

1,第一次查看TCH的值:

    1.1 获得表ID:

    SQL> select data_object_id from dba_objects

    2     where wner='SYS' and object_name='TEST';


    DATA_OBJECT_ID

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

             60629

    

    1.2 获得表所占用的数据库ID:

    SQL> select unique dbablk from x$bh where bj=60629;

    

    1.3 获得该表中,62191数据库的tch值:

    SQL> select tch from x$bh where bj=60629 and dbablk=62191;


           TCH

    ----------

             2


2,再次读入表test;

    SQL> select count(*) from test;


      COUNT(*)

    ----------

         20000


3,重复1.3操作,再次检测tch值:

    SQL> select tch from x$bh where bj=60629 and dbablk=62191;


           TCH

    ----------

             3


    用户可以继续试验,TCH会继续增长。由此可见,用户可以通过x$bh,获得系统中访问量比较大的字段以及其所在数据库,进一步优化存储的安排,提高系统性能。


下面的script可以列出top 10的热点块对象

select /*+rule*/ owner,object_name from dba_objects
where data_object_id in
(select obj from (select obj from x$bh order by tch desc) where rownum < 11);

 


小小菜鸟一枚