ORACLE中段的HEADER_BLOCK示例详析

前言

段(segment)是一种在数据库中消耗物理存储空间的任何实体(一个段可能存在于多个数据文件中,因为物理的数据文件

是组成逻辑表空间的基本物理存储单位)

最近在学习段(segment)、区间(extent)时,对段的HEADER_BLOCK有一些疑问,本文记录一下探究的实验过程以及相关总结,,如有不对的地方,敬请指出。以SCOTT.EMP表为例(下面测试环境为Oracle Database 10g Release 10.2.0.5.0 - 64bit Production):

SELECT FILE_ID,
  BLOCK_ID,
  BLOCKS
FROM DBA_EXTENTS
WHERE OWNER ='&OWNER'
  AND SEGMENT_NAME = '&TABLE_NAME'; 

SELECT HEADER_FILE
  , HEADER_BLOCK
  , BYTES
  , BLOCKS
  , EXTENTS
FROM DBA_SEGMENTS
WHERE OWNER='&OWNER' AND SEGMENT_NAME='&SEGMENT_NAME';

如上所示,DBA_SEGMENTS 中的HEADER_BLOCK 与DBA_EXTENTS的BLOCK_ID不同(HEADER_BLOCK:文件ID为4的第27个块,区间的第一个块的BLOCK_ID为第25个块),这个的原因如下:

一个segment的第一个区的第一个块是FIRST LEVEL BITMAP BLOCK,第二个块是SECOND LEVEL BITMAP BLOCK,这两个块是用来管理free block的,第三个块是PAGETABLE SEGMENT HEADER,这个块才是segment里的HEADER_BLOCK,再后面的块就是用来记录数据的。所以25+2=27. 详细可以参考《循序渐进ORCLE:数据库管理、优化与备份》这本书的第5章。

下面我们创建一个表,测试一下是否也是这个规律,如下所示:

SQL> CREATE TABLE TEST1.MMM
 2 AS
 3 SELECT * FROM DBA_OBJECTS;

Table created.

SQL> COL SEGMENT_NAME FOR A32;
SQL> SELECT SEGMENT_NAME
 2   ,FILE_ID
 3   ,BLOCK_ID
 4   ,BLOCKS
 5 FROM DBA_EXTENTS
 6 WHERE SEGMENT_NAME='MMM' AND OWNER='TEST1'
 7 ORDER BY BLOCK_ID ASC;

SEGMENT_NAME      FILE_ID BLOCK_ID  BLOCKS
-------------------------------- ---------- ---------- ----------
MMM          76   9   8
MMM          76   17   8
MMM          76   25   8
MMM          76   33   8
MMM          76   41   8
MMM          76   49   8
MMM          76   57   8
MMM          76   65   8
MMM          76   73   8
MMM          76   81   8
MMM          76   89   8

SEGMENT_NAME      FILE_ID BLOCK_ID  BLOCKS
-------------------------------- ---------- ---------- ----------
MMM          76   97   8
MMM          76  105   8
MMM          76  113   8
MMM          76  121   8
MMM          76  129   8
MMM          76  137  128
MMM          76  265  128
MMM          76  393  128
MMM          76  521  128
MMM          76  649  128
MMM          76  777  128

22 rows selected.

SQL> SELECT HEADER_FILE
 2  , HEADER_BLOCK
 3  , BYTES
 4  , BLOCKS
 5  , EXTENTS
 6 FROM DBA_SEGMENTS
 7 WHERE OWNER='TEST1' AND SEGMENT_NAME='MMM';

HEADER_FILE HEADER_BLOCK  BYTES  BLOCKS EXTENTS
----------- ------------ ---------- ---------- ----------
   76   11 7340032  896   22

如上所示,段对象TEST1.MMM的header_block为11 ,而对应的区间的第一个块对象ID为9, 也是9+2=11,确实是如此,那么我们来DUMP数据块看看,如下所示

SQL> alter system dump datafile 76 block 9;

System altered.

SQL> alter system dump datafile 76 block 10;

System altered.

SQL> alter system dump datafile 76 block 11;

System altered.

SQL> select user_dump.value
 2   || '/'
 3   || lower(instance.value)
 4   || '_ora_'
 5   || v$process.spid
 6   || nvl2(v$process.traceid, '_'
 7         || v$process.traceid, null)
 8   || '.trc'"trace file"
 9 from v$parameter user_dump
 10   cross join v$parameter instance
 11   cross join v$process
 12   join v$session
 13   on v$process.addr = v$session.paddr
 14 where user_dump.name = 'user_dump_dest'
 15   and instance.name = 'instance_name'
 16   and v$session.audsid = sys_context('userenv', 'sessionid'); 

trace file
--------------------------------------------------------------------------------
/u01/app/oracle/admin/SCM2/udump/scm2_ora_22642.trc

第一个区的第一个块(block_id=9)是FIRST LEVEL BITMAP BLOCK,第二个块(block_id=10)是SECOND LEVEL BITMAP BLOCK,这两个块是用来管理free block的,第三个块(block_id=11)是PAGETABLE SEGMENT HEADER,这个块才是segment里的HEADER_BLOCK,再后面的块就是用来记录数据的

不过有一个奇怪的现象,对SCOTT.EMP其数据块做dump,发现25、26、27数据块的type都是trans data,0x06表示的Block Type为 Table/cluster/index segment data block 。 不知是否因为SCOTT.EMP对象位于USERS表空间下的缘故。不过USER表空间也是ASSM管理的。具体情况尚不清楚?

SQL> SELECT TABLESPACE_NAME
 2  , SEGMENT_SPACE_MANAGEMENT
 3  , ALLOCATION_TYPE
 4  , EXTENT_MANAGEMENT
 5 FROM DBA_TABLESPACES
 6 WHERE TABLESPACE_NAME='USERS';

TABLESPACE_NAME    SEGMEN ALLOCATIO EXTENT_MAN
------------------------------ ------ --------- ----------
USERS       AUTO SYSTEM LOCAL

那么是否所有的HEADER_BLOCK都是位于段的第三个block呢?是否还跟段空间管理的方式有关呢? 我们用如下实验来探究一下:创建一个手工段空间管理(Manual Segment Space Management)的表空间。

SQL> CREATE TABLESPACE TBS_TEST_DATA
 2 DATAFILE '/u03/oradata/gsp/tbs_test_data_001.dbf'
 3 SIZE 20M
 4 EXTENT MANAGEMENT LOCAL AUTOALLOCATE
 5 SEGMENT SPACE MANAGEMENT MANUAL ONLINE;

Tablespace created.

SQL> create user test identified by test123456
 2 default tablespace tbs_test_data;

User created.

SQL> grant connect, resource to test;

Grant succeeded.

SQL> CREATE TABLE TEST.KKK
 2 AS
 3 SELECT * FROM DBA_OBJECTS;

Table created.

SQL> COL SEGMENT_NAME FOR A32;
SQL> SELECT SEGMENT_NAME
 2  ,FILE_ID
 3  ,BLOCK_ID
 4  ,BLOCKS
 5 FROM DBA_EXTENTS
 6 WHERE SEGMENT_NAME='KKK' AND OWNER='TEST'
 7 ORDER BY BLOCK_ID ASC;

SEGMENT_NAME      FILE_ID BLOCK_ID  BLOCKS
-------------------------------- ---------- ---------- ----------
KKK          39  427785  128
KKK          43  435249   8
KKK          43  435257   8
KKK          43  435265   8
KKK          43  435273   8
KKK          43  435281   8
KKK          43  435289   8
KKK          43  435297   8
KKK          43  435305   8
KKK          43  435313   8
KKK          43  435321   8

SEGMENT_NAME      FILE_ID BLOCK_ID  BLOCKS
-------------------------------- ---------- ---------- ----------
KKK          43  435329   8
KKK          48  436745   8
KKK          48  436753   8
KKK          48  436761   8
KKK          48  436769   8
KKK          48  436777   8
KKK          48  436873  128
KKK          40  444297  128
KKK          43  447241  128
KKK          52  449545  128
KKK          2  458249  128

22 rows selected.

SQL> SELECT HEADER_FILE
 2  , HEADER_BLOCK
 3  , BYTES
 4  , BLOCKS
 5  , EXTENTS
 6 FROM DBA_SEGMENTS
 7 WHERE OWNER='TEST' AND SEGMENT_NAME='KKK';

HEADER_FILE HEADER_BLOCK  BYTES  BLOCKS EXTENTS
----------- ------------ ---------- ---------- ----------
   43  435249 7340032  896   22

SQL> 

SQL> alter system dump datafile 43 block 435249;

System altered.

SQL> select user_dump.value
 2   || '/'
 3   || lower(instance.value)
 4   || '_ora_'
 5   || v$process.spid
 6   || nvl2(v$process.traceid, '_'
 7         || v$process.traceid, null)
 8   || '.trc'"trace file"
 9 from v$parameter user_dump
 10   cross join v$parameter instance
 11   cross join v$process
 12   join v$session
 13   on v$process.addr = v$session.paddr
 14 where user_dump.name = 'user_dump_dest'
 15   and instance.name = 'instance_name'
 16   and v$session.audsid = sys_context('userenv', 'sessionid'); 

trace file
--------------------------------------------------------------------
/u01/app/oracle/admin/SCM2/udump/scm2_ora_27792.trc

如下所示,块类型为DATA SEGEMENT HEADER -UNLIMITED , rdba:( segment header的块地址为)为 0x0ac6a431 .其实这是第一个块(不是以block_id大小来看),因为手工段空间管理,这种技术的具体实现方式是通过在段头(Segment Header)分配自由列表(freelist)来管理Block的使用。简单一点,你可以把自由列表想象成一个数据结构中的链表一样的数据结构,ORACLE通过一系列算法向自由列表(freelist)中加入或移出Block来实现段管理。

Segment Header是一个Segment的第一个extent的头块(第一个块)。在FLM管理的Segment中,header block始终是segment 的第一个块。 如下所示,在Extent Map中,第一个区间的地址为0x0ac6a432, 恰恰跟segment header的块地址 0x0ac6a431 相差为1,这意味着后面的分配是紧挨着segment header的块地址。 所以在手工段空间管理(Manual Segment Space Management)的表空间,不能以block_id的大小顺序来看区间分配顺序。也就是说FILE_ID=39 BLOCK_ID=427785的块并不是第一个区间的第一个块。这也是我在实验当中纠结了好久的地方。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • Oracle 插入超4000字节的CLOB字段的处理方法

    在通过拼组sql语句来实现数据插入的应用中,我们很有可能会遇到需要插入大型数据的情况,例如,在oracle中需要插入字节数超过4000的字段内容时,我们如果通过简单的拼组sql语句来实现插入,显然就会出现问题,而在sql server中却没有这个限制,个人尝试了26w个字符的sql语句在sql server2005中执行,依旧可以插入数据,但是在oracle中插入超过4000个字符的内容则会报异常. 下面就此问题的解决办法,做一下小结: 我们可以通过创建单独的OracleCommand来进行指定

  • Oracle 查询表信息获取表字段及字段注释

    获取表字段: select * from user_tab_columns where Table_Name='用户表' order by column_name 获取表注释: select * from user_tab_comments where Table_Name='用户表' order by Table_Name 获取字段注释: select * from user_col_comments where Table_Name='用户表' order by column_name /*

  • oracle删除表字段和oracle表增加字段

    添加字段的语法:alter table tablename add (column datatype [default value][null/not null],-.); 修改字段的语法:alter table tablename modify (column datatype [default value][null/not null],-.); 删除字段的语法:alter table tablename drop (column); 添加.修改.删除多列的话,用逗号隔开. 使用alter

  • oracle使用sql语句增加字段示例(sql删除字段语句)

    添加字段的语法:alter table tablename add (column datatype [default value][null/not null],-.); 修改字段的语法:alter table tablename modify (column datatype [default value][null/not null],-.); 删除字段的语法:alter table tablename drop (column); 添加.修改.删除多列的话,用逗号隔开. 使用alter

  • 简单三步轻松实现ORACLE字段自增

    第一步:创建一个表. 复制代码 代码如下: create table Test_Table ( ID number(11) primary key, Name varchar(50) not null, Value1 varchar(50) not null ) 第二步:创建一个自增序列以此提供调用函数. 复制代码 代码如下: create sequence AutoID start with 1 //根据需要自己可修改该数值 increment by 1 //步长值 minvalue 1 no

  • oracle关键字作为字段名使用方法

    有时我们在定义字段名及别名时所用名与oracle关键字同名,这时该如何处理呢? 其实很简单,只要在此关键字加上"",如"group" 看下面的例子: 复制代码 代码如下: SQL> DROP TABLE k; Table dropped -- 建立表K,字段名为UID(oracle关键字) SQL> CREATE TABLE k(UID INT); CREATE TABLE k(UID INT) ORA-00904: : invalid IDENTIFI

  • Oracle中判断字段是否为数字

    在我们平常的开发中可能会遇到这样的问题,就是判断某一列是否全部由数字组成,我们都知道oracle并没有给我们提供这样一个现成的函数,那么根据我的经验我总结了两个行之有效的方法(列名:column,表名:table): 1.使用trim+translate函数: 复制代码 代码如下: select * from table where trim(translate(column,'0123456789',' ')) is NULL; 这里要注意的是:translate函数的第三个参数是一个空格,不

  • 深入浅析mybatis oracle BLOB类型字段保存与读取

    一.BLOB字段 BLOB是指二进制大对象也就是英文Binary Large Object的所写,而CLOB是指大字符对象也就是英文Character Large Object的所写.其中BLOB是用来存储大量二进制数据的:CLOB用来存储大量文本数据.BLOB通常用来保存图片.文件等二进制类型的数据. 二.使用mybatis操作blob 1.表结构如下: create table BLOB_FIELD ( ID VARCHAR2(64 BYTE) not null, TAB_NAME VARC

  • java读写oracle的blob字段示例

    复制代码 代码如下: package com.wanmei.meishu; import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.FileReader;import java.io.InputStream;import java.io.OutputStream;import java.sql.Connection;import java.sql.DriverManager;import java

  • oracle数据库中如何处理clob字段方法介绍

    在知识库的建立的时候,用普通VARCHAR2存放文章是显然不够的,只有区区4000的字节,放不了多少字, 而CLOB数据类型,则能最多存放8G的数据.但是这个字段处理起来有比较多的特殊性,记录一下. 插入: 直接写在SQL里面是不行的,一来SQL脚本有字符数限制,而来文章内容包含许多特殊字符,如换行,引号, 之类的东西,很麻烦.网上流行通用做法是先插入一个空CLOB字段,用empty_clob()方法来创建空字段,如: 复制代码 代码如下: INSERT INTO T_TOPIC(TOPIC_I

随机推荐