这是一张非常基本同时也是非常重要的结构图。物理结构很简单,就是操作系统物理块组成数据文件,对于操作系统来说,数据文件跟其他非数据库文件没有区别。重点是逻辑结构。
一、表空间
从9i开始,oracle支持不同块大小的表空间,也就是说同一个数据库中,不同表空间的数据块大小可以不一样。假设默认8k的话,还可以创建比如4k、16k、32k、64k等大小的表空间。不过如果有不同块大小的表空间,请记得为它们设置不同的db_nk_cache_size参数,以为这些表空间的数据访问分配内存。
从10g开始,oracle支持重命名表空间,语法是alter tablespace
二、段(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中国
作者
相关推荐
-
Collaborate 18大会:了解甲骨文云数据库和应用的进展
在Collaborate 18大会即将举行时,我们会发现,甲骨文用户社区的技术变化会略高于平常水平。 由独立甲 […]
-
甲骨文自治数据库亮相 带来云计算新希望
早前甲骨文还不在云计算公司之列,而现在该公司正在迅速弥补其失去的时间。甲骨文的云计算核心是甲骨文自治数据库(O […]
-
Oracle TNS 错误:管理员旷日持久的战斗
TNS经常给IT管理员带来麻烦,而且很难定位。尤其是在Oracle数据库中。本文将介绍如何避免这些常见错误。
-
DBA支招:如何实现Oracle EBS 12.2.5升级
那些对于是否要将EBS进行升级持观望态度的Oracle数据库管理员们可以从一家研究公司获得一些启示。