Oracle数据库的逻辑结构

日期: 2010-11-03 作者:佚名 来源:TechTarget中国

  这是一张非常基本同时也是非常重要的结构图。物理结构很简单,就是操作系统物理块组成数据文件,对于操作系统来说,数据文件跟其他非数据库文件没有区别。重点是逻辑结构。

  一、表空间

  从9i开始,oracle支持不同块大小的表空间,也就是说同一个数据库中,不同表空间的数据块大小可以不一样。假设默认8k的话,还可以创建比如4k、16k、32k、64k等大小的表空间。不过如果有不同块大小的表空间,请记得为它们设置不同的db_nk_cache_size参数,以为这些表空间的数据访问分配内存。

  从10g开始,oracle支持重命名表空间,语法是alter tablespace rename to ;这个操作在传输表空间时非常有用,当源和目标的表空间名称不一致时,通过此命令可以方便地更名,这是一大进步。

  二、段(segment)

  参考上图,一个段可以跨越多个数据文件,但只能在一个表空间中。一个段由多个区(extent)组成。每一个段都有一个单独的data_object_id对应。这里需要额外说明一下data_object_id和object_id的区别。简单的说,object_id对应的是对象,而data_object_id对应的是段。比如一个procedure有object_id,但没有data_object_id,因为它不是段。因为每一个段都唯一对应一个表空间,而每一个段都拥有自己独一无二的data_object_id,所以通过data_object_id,就能唯一定位这个段所在的表空间,这就是rowid的原理。

  这里做一个实验,来说明data_object_id和object_id的区别以及一些操作对data_object_id的影响。首先创建一张分区表

  SQL>create table part_test(id number,create_time date)

  partition by range (id)

  (partition part1 values less than (100),

  partition part2 values less than (200),

  partition part3 values less than (maxvalue));

  看一下没有数据时的情况

  SQL>select object_name,subobject_name,object_type,object_id,data_object_id from user_objects where object_name = ‘PART_TEST’;

OBJECT_NAME          SUBOBJECT_NAME       OBJECT_TYPE          OBJECT_ID DATA_OBJECT_ID
——————– ——————– ——————- ———- ————–
PART_TEST                                 TABLE                    73205
PART_TEST            PART1                TABLE PARTITION          73206          73206
PART_TEST            PART2                TABLE PARTITION          73207          73207
PART_TEST            PART3                TABLE PARTITION          73208          73208

  可以看出,初始没有数据的时候,data_object_id和object_id一样。考虑到data_object_id是记录了数据存放的位置,我们看一下先插入数据,再将表truncate之后的情况。

  SQL> insert into part_test values(1,sysdate);

  1 row created.

  SQL> insert into part_test values(101,sysdate+1);

  1 row created.

  SQL> commit;

  Commit complete.

  SQL> truncate table part_test;

  Table truncated.

  SQL> select object_name,subobject_name,object_type,object_id,data_object_id from user_objects where object_name = ‘PART_TEST’;

OBJECT_NAME          SUBOBJECT_NAME       OBJECT_TYPE          OBJECT_ID DATA_OBJECT_ID
——————– ——————– ——————- ———- ————–
PART_TEST            PART3                TABLE PARTITION          73208          73208
PART_TEST            PART2                TABLE PARTITION          73207          73211
PART_TEST            PART1                TABLE PARTITION          73206          73210
PART_TEST                                 TABLE                    73205

  可以看出,有数据的段,对应的data_object_id改变了,这是因为truncate之后,oracle重新分配了这些段存储数据的空间,因此改变了data_object_id。而没有数据的段,data_object_id没有改变,因为oracle并没有对这些段重新分配数据存储空间。

  三、区(extent)

  一个区由连续的块组成。这里要强调的就是连续。因此,一个区是不能跨数据文件的(参见上图跟数据文件相连的那条线)

  四、块(block)

  这是oracle存取数据最小的单位,在建立数据库的时候指定,一旦指定则无法修改。(但在9i之后可以创建不同块大小的表空间,一定程度上解决了这个问题。)

  一个块除了了块头、表目录和行目录之外的空间,都可以用来存放数据。按照默认8k大小的块来说,这部分可以真正存放数据的空间是8096字节。然后因为各种其他开销,每行数据的最小长度大约是11个字节,也就是说,每个块最大存放的行数理论值是8096/11=736行。我们可以做个试验来验证一下。

  SQL> create table block_test(a varchar2(1)) pctfree 0 tablespace datatb;

  Table created.

  SQL> select object_id from user_objects where object_name = ‘BLOCK_TEST’;

  OBJECT_ID

  ———-

  73213

  SQL> select spare1 from sys.tab$ where OBJ#=73213;

  SPARE1

  ———-

  736

  可以看到,当我们创建了一个pctfree=0(表示不预留空间,块中所有可以存放数据的空间都用来存放数据)的表时,最大存放行数理论值为736,跟我们的计算一致。那么实际可以存放多少呢?我们继续做下去。

  SQL> begin

  2 for i in 1 .. 10000 loop

  3 insert into block_test values(‘1’);

  4 end loop

  5 commit;

  6 end;

  7 /

  PL/SQL procedure successfully completed.

  使用一个循环,向表中插入10000条数据,每条数据只有一个字节。

  SQL> select file#,block#,count(*)

  2 from (select dbms_rowid.rowid_relative_fno(rowid) file#,

  3 dbms_rowid.rowid_block_number(rowid) block#

  4 from block_test)

  5 group by file#,block#;

  然后我们通过上面的语句来看这些数据的分布

     FILE#     BLOCK#   COUNT(*)
———- ———- ———-
         4        209        733
         4        212        733
         4        203        733
         4        214        733
         4        206        733
         4        215        733
         4        205        733
         4        208        733
         4        210        733
         4        211        733
         4        204        733
         4        207        733
         4        213        733
         4        222        471

  可以看出,每个数据块中最多存放的记录数是733条。

  五、ROWID

  从8i之后,rowid改为10个字节,格式类似于OOOOOOFFFBBBBBBRRR(64进制)这样。其中O是对象id,F是文件id,B是块id,R是行id。因为这个调整,oracle的数据文件限制也从整个库不能超过1023个数据文件变成了一个表空间不能超过1023个数据文件。下面结合一个例子来看:

  SQL> select rowid from block_test where rownum=1;

  ROWID

  ——————

  AAAR39AAEAAAADLAAA

  上面这个例子分解下来就是这样:

  data_object_id = AAAR39

  file = AAE

  block = AAAADL

  row = AAA

  再转化为10进制,data_object_id=17*64^2+55*64+61=73213,file=4,block=203,row=0。我们来验证一下:

  SQL> select dbms_rowid.rowid_object(‘AAAR39AAEAAAADLAAA’) from dual;

  DBMS_ROWID.ROWID_OBJECT(‘AAAR39AAEAAAADLAAA’)

  ———————————————

  73213

  SQL> select dbms_rowid.rowid_relative_fno(‘AAAR39AAEAAAADLAAA’) from dual;

  DBMS_ROWID.ROWID_RELATIVE_FNO(‘AAAR39AAEAAAADLAAA’)

  —————————————————

  4

  SQL> select dbms_rowid.rowid_block_number(‘AAAR39AAEAAAADLAAA’) from dual;

  DBMS_ROWID.ROWID_BLOCK_NUMBER(‘AAAR39AAEAAAADLAAA’)

  —————————————————

  203

  通过这种方式,我们就可以根据rowid定位块所在的具体位置,从而dump这个数据块进行分析。

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

电子邮件地址不会被公开。 必填项已用*标注

敬请读者发表评论,本站保留删除与本文无关和不雅评论的权力。

作者

佚名
佚名

相关推荐