做了一个块相关的实验,记录如下:
C:\>set ORACLE_SID=irmdb
C:\>sqlplus /nolog
SQL*Plus: Release 10.2.0.3.0 - Production on 星期四 2月 14 14:26:52 2008
Copyright (c) 1982, 2006, Oracle. All Rights Reserved.
SQL> conn / as sysdba;
已连接。
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Prod
PL/SQL Release 10.2.0.3.0 - Production
CORE 10.2.0.3.0 Production
TNS for 32-bit Windows: Version 10.2.0.3.0 - Production
NLSRTL Version 10.2.0.3.0 - Production
SQL> create table test (a int);
表已创建。
SQL> begin
2 for i in 1..5000
3 loop
4 insert into test values(i);
5 end loop;
6 end;
7 /
PL/SQL 过程已成功完成。
SQL> commit;
提交完成。
SQL> show user;
USER 为 "SYS"
SQL> set serveroutput on
SQL> exec show_space('TEST');
Total Blocks ........................... 16
Total Bytes ........................... 131,072
Total MBytes ........................... 0
Unused Blocks........................... 3
Unused Bytes ........................... 24,576
Last Used Ext FileId.................... 1
Last Used Ext BlockId................... 64,257
Last Used Block......................... 5
PL/SQL 过程已成功完成。
SQL> select file_id,block_number from
2 (select dbms_rowid.rowid_relative_fno(rowid) file_id,
3 dbms_rowid.rowid_block_number(rowid) block_number
4 from test)
5 group by file_id,block_number;
FILE_ID BLOCK_NUMBER
---------- ------------
1 64254
1 64251
1 64255
1 64250
1 64252
1 64256
1 64253
1 64257
已选择8行。
我们可以看到实际上这个表只占用了8个blocks,那么通过show_space我们看到的却是16,其实剩下的那8个块就是段头,位图块等等,是一种额外的开销。因此我们可以得到一个结论就是,表中有16个block,而data block只有8个。
SQL> select file#,dbablk,tch from x$bh where bj=
2 (select data_object_id from dba_objects where wner='SYS' and object_name='TEST')
3 order by dbablk;
FILE# DBABLK TCH
---------- ---------- ----------
1 64249 7
1 64250 6
1 64251 5
1 64252 6
1 64253 6
1 64254 6
1 64255 6
1 64256 5
1 64257 7
1 64258 7
1 64259 7
1 64260 7
1 64261 7
已选择13行。( 这里的块为什么是13而不是16?那位朋友能给一下答案呢?)
SQL> select file#,block#,status from v$bh where bjd=
2 (select data_object_id from dba_objects where wner='SYS' and object_name='TEST')
3 order by block#;
FILE# BLOCK# STATUS
---------- ---------- -------
1 64249 xcur
1 64250 xcur
1 64251 xcur
1 64252 xcur
1 64253 xcur
1 64254 xcur
1 64255 xcur
1 64256 xcur
1 64257 xcur
1 64258 xcur
1 64259 xcur
1 64260 xcur
1 64261 xcur
已选择13行。
这里从v$bh中我们可以进一步来查看block的状态,其实这个值是通过x$bh的state字段通过decode函数得来的:
简单描述一下:
xcur 表示这个块是排斥状态正在被当前的instance独占。
scur 表示这个块正在被当前的instance共享
cr 表示一致读
free 表示块处在空闲状态
read 表示正在从磁盘上读取块
write 表示块正在被写出
我们再来验证一下段头信息:
SQL> desc dba_segments;
名称 是否为空? 类型
----------------------------------------- -------- ---------------------------
OWNER VARCHAR2(30)
SEGMENT_NAME VARCHAR2(81)
PARTITION_NAME VARCHAR2(30)
SEGMENT_TYPE VARCHAR2(18)
TABLESPACE_NAME VARCHAR2(30)
HEADER_FILE NUMBER
HEADER_BLOCK NUMBER
BYTES NUMBER
BLOCKS NUMBER
EXTENTS NUMBER
INITIAL_EXTENT NUMBER
NEXT_EXTENT NUMBER
MIN_EXTENTS NUMBER
MAX_EXTENTS NUMBER
PCT_INCREASE NUMBER
FREELISTS NUMBER
FREELIST_GROUPS NUMBER
RELATIVE_FNO NUMBER
BUFFER_POOL VARCHAR2(7)
SQL> select header_file,header_block from dba_segments
2 where wner='SYS' and segment_name='TEST';
HEADER_FILE HEADER_BLOCK
----------- ------------
1 64249
进一步实验,首先flush一下buffer cache:
SQL> alter system flush buffer_cache;
系统已更改。
SQL> select file#,dbablk,tch from x$bh where bj=
2 (select data_object_id from dba_objects where wner='SYS' and object_name='TEST')
3 order by dbablk;
FILE# DBABLK TCH
---------- ---------- ----------
1 64249 0
1 64250 0
1 64251 0
1 64252 0
1 64253 0
1 64254 0
1 64255 0
1 64256 0
1 64257 0
1 64258 0
1 64259 0
1 64260 0
1 64261 0
已选择13行。
SQL> select file#,block#,status from v$bh where bjd=
2 (select data_object_id from dba_objects where wner='SYS' and object_name='TEST')
3 order by block#;
FILE# BLOCK# STATUS
---------- ---------- -------
1 64249 free
1 64250 free
1 64251 free
1 64252 free
1 64253 free
1 64254 free
1 64255 free
1 64256 free
1 64257 free
1 64258 free
1 64259 free
1 64260 free
1 64261 free
已选择13行。
这里可以看到所有test段相关的block的tch都已经归0了,而且v$bh中的status也都变成了free,说明了当前的块是空闲的。需要主要的是block虽然被flush到disk上去,但是block的记录还存在。
为了再进一步证明这一点:
SQL> select count(*) from test;
COUNT(*)
----------
5000
SQL> select file#,block#,status from v$bh where bjd=
2 (select data_object_id from dba_objects where wner='SYS' and object_name='TEST')
3 order by block#;
FILE# BLOCK# STATUS
---------- ---------- -------
1 64249 free
1 64249 xcur
1 64250 free
1 64250 xcur
1 64251 free
1 64251 xcur
1 64252 xcur
1 64252 free
1 64253 xcur
1 64253 free
1 64254 xcur
1 64254 free
1 64255 free
1 64255 xcur
1 64256 free
1 64256 xcur
1 64257 free
1 64257 xcur
1 64258 free
1 64258 xcur
1 64259 free
1 64259 xcur
1 64260 xcur
1 64260 free
1 64261 free
1 64261 xcur
已选择26行。
注意到x$bh字典表中的tch字段表示的就是block的touch count,一般来说这个值越高那么这个块就越热,我们称这样的块就叫做热点块。
一般我们通过x$bh就可以找出系统的热点块以及相关的信息:
需要注意的是user/all/dba_objects中的data_object_id关联x$bh中的obj或者是v$bh中的objd是关键:
下面的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);