You are on page 1of 8

Oracle 的数据字典表 dba_objects 包含了两个字段,object_id, data_object_id,官方文档上的

解释是:
object_id: Dictionary object number of the object.
Data_object_id: Dictionary object number of the segment that contains the object.

首先,区别一下段(segment)和数据字典对象(dictionary object)的概念,段(segment)
是指实实在在的分配了一个或者多个区(extents)来存储数据。而数据字典对象(dictionary
object)有可能有存储区域,也有可能没有。比如 sequence,package,type 这些对象并没有
存储空间,所以并不存在段与之相关联。所以这些对象的 data_object_id 都是空值。

select object_id, data_object_id from dba_objects where object_ name='SEQ_TEST';


OBJECT_ID DATA_OBJECT_ID
--------------- --------------
36385
下面看一个实际的例子,就能够很好的理解这两个概念了:

1. move 操作:
select object_id, data_object_id from dba_objects where object_name='TEST1';
OBJECT_ID DATA_OBJECT_ID
---------- --------------
36386 36386

1 row selected.
alter table test1 move;

Table altered.
select object_id, data_object_id from dba_objects where object_name='TEST1';

OBJECT_ID DATA_OBJECT_ID
---------- --------------
36386 36387

可以看到,test1 在创建的时候,object_id, data_object_id 都是 36386.这是因为在创建的时候


数据字典分配的机制是相同的。使用 move 操作,而本身 move 操作只是重新分配了空间来
重组原来的数据,所以对象本身没有发生变化,而是重新分配了段来存储数据。

2. partition 分区表
CREATE TABLE test2 (id number, status char(1)) PARTITION BY list(status) (PARTITION p_t
VALUES ('t'), PARTITION p_f VALUES ('f'));
Table created.

select object_name, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID from dba_objects


where object_name='TEST2';
OBJECT_NAM SUBOBJECT_NAME OBJECT_ID DATA_OBJECT_ID
---------- ------------------------------ ---------- --------------
TEST2 P_F 36390 36390
TEST2 P_T 36389 36389
TEST2 36388
3 rows selected

这个地方可以看出,test2 对象只有 object_id,而真正只有分区才会有 data_object_id, 因为


每一个分区分配了一个段。

接着再创建一个普通表:
CREATE TABLE test3 ( id number, status char(1) );

select object_name, object_id, data_object_id from dba_objects where object_name='TEST3';


OBJECT_NAM OBJECT_ID DATA_OBJECT_ID
---------- ---------- ------------------
TEST3 36391 36391
然后进行分区交换:

alter table test2 exchange partition p_t with table test3 including indexes;
Table altered.
最后再看一下相关的 object_id 和 data_object_id:

select object_name, SUBOBJECT_NAME, object_id, data_object_id from dba_objects where


object_name in ('TEST2','TEST3');

OBJECT_NAM SUBOBJECT_NAME OBJECT_ID DATA_OBJECT_ID


---------- ------------------------------ ---------- --------------
TEST2 P_F 36390 36390
TEST2 P_T 36389 36391
TEST2 36388
TEST3 36391 36389

所以这个地方显而易见,在交换过后,对象的 object_id 都不会发生变变化,因为 exchange


操作并不会迁移数据,而仅仅是更改了对象的数据存储即段得指向,也就是更改了对象的
指针,这个指针指向的是数据存储区域,即所谓的段。

3. 最后再看一下 rowid
rowid 是指数据块中行的物理地址。看一下 rowid 的组成:
select rowid, substr(rowid,1,6) "OBJECT", substr(rowid,7,3) "FILE",
substr(rowid,10,6) "BLOCK”, substr(rowid,16,3) "ROW",
dbms_rowid.rowid_object(rowid) object_id, id from test3 t;

ROWID OBJECT FILE BLOCK ROW OBJECT_ID ID


------------------ ------------ ------ ------------ ------ ---------- ----------
AAAI4lAAMAAAhssAAA AAAI4l AAM AAAhss AAA 36389 1
1 row selected.

alter table test3 move;


Table altered.

select rowid , substr(rowid,1,6) "OBJECT", substr(rowid,7,3) "FILE",


substr(rowid,10,6) "BLOCK", substr(rowid,16,3) "ROW",
dbms_rowid.rowid_object(rowid) object_id, id from test3 t;

ROWID OBJECT FILE BLOCK ROW OBJECT_ID ID


------------------ ------------ ------ ------------ ------ ---------- ----------
AAAI4oAAMAAAhtMAAA AAAI4o AAM AAAhtM AAA 36392 1

1 row selected.

  可以看到,rowid 表示的是数据的在块中的地址,所以在 rowid 的组成中,object_id 是所


谓的段的数据字典 id,即 data_object_id,如上所示,对表进行 move 操作,object_id 发生
了变化,即验证了这个猜想。

object_id 是数据库里的对象的唯一标识。数据库中每个对象都会被分配一个唯一的好号码作
为区别的标志。同样地,每 1 个数据库 object 都会 link 住 1 个 segment(数据段), 而 Data_obj
ect_id 就是分配给那个对应的 segment。
(译者注:上面那句不保证正确性,因为 1 个数据库对象是可以对应不同表空间内多个
segm ent 的)。当那个 segment 发生了任何物理变动,都会令这个数值改变。这两个 ID 的值
在一开始是相等的,但是当对应 segment 发生变动时,Data_object_id 会改变。这两个 ID 都
是 Oracle 用来表示存放在数据字典的元数据(数据目录)。

其实 object_id 和 data_object_id 同样是表示数据库对象的一个唯一标志,但是 object_id 表示


的是逻辑 id,data_object_id 表示的是物理 id。如果一些 object 没有物理属性的话那它就不存
在 data_object_id,例如 procedure,function,package,data type,db link,mv 定义,view 定义,临时
表,分区表定义等等这些 object 都是没有对应着某个 segment,因此它们的 data_object_id 都
为空。
当表刚创建的时候它的 object_id 和 data_object_id 都是相等的,但是如果表经过 move 或
trun cate 等,涉及到 segment 发生改变后 data_object_id 将会有变化。

DATA_OBJECT_ID was introduced in 8.0 to track versions of the same segment (certain operati
ons change the version). It is used to discover stale ROWIDs and stale undo records.

1) 创建新表
SQL> create table sdxj.xiaoxu_objectid as select * from dba_objects;
表已创建。
2) 查看该表的 object_id 和 data_object_id,
注:表 tab$OBJ#存放的就是对象的 object_id,dataobj#存放的就是对象的 data_object_id。
SQL> select owner,object_name,object_id,data_object_id from dba_objects where object_nam
e='XIAOXU_OBJECTID';
OWNER OBJECT_NAME OBJECT_ID DATA_OBJECT_ID
---------- -------------------------------------------------- ---------- --------------
SDXJ XIAOXU_OBJECTID 77782 77782 ----初始大小相等。

3) 通过 move,create ,alter,truncate 操作观察 id 变化


3.1 move 操作
SQL> alter table sdxj.xiaoxu_objectid move; ---表已更改。
SQL> select owner,object_name,object_id,data_object_id from dba_objects where object_nam
e='XIAOXU_OBJECTID';
OWNER OBJECT_NAME OBJECT_ID DATA_OBJECT_ID
---------- -------------------------------------------------- ---------- --------------
SDXJ XIAOXU_OBJECTID 77782 77783
---此时 object_id 不变,data_object_id 发生变化,值增加。

3.2 create index 操作


SQL > create index sdxj.idx_objectid on sdxj.xiaoxu_objectid (object_id) tablespace d_data_01;
SQL> select owner,object_name,object_id,data_object_id from dba_objects where object_nam
e='XIAOXU_OBJECTID';
OWNER OBJECT_NAME OBJECT_ID DATA_OBJECT_ID
---------- -------------------------------------------------- ---------- --------------
SDXJ XIAOXU_OBJECTID 77782 77783
---创建索引两个值未变。

3.3 alter index 操作


SQL> alter index sdxj.idx_objectid rebuild tablespace users; ---- 索引已更改。
SQL> select owner,object_name,object_id,data_object_id from dba_objects where object_nam
e='XIAOXU_OBJECTID';
OWNER OBJECT_NAME OBJECT_ID DATA_OBJECT_ID
---------- -------------------------------------------------- ---------- --------------
SDXJ XIAOXU_OBJECTID 77782 77783
--经测试 alter index ,create indexes,insert into 均未发生变化。

3.4 truncate 操作
SQL> truncate table sdxj.XIAOXU_OBJECTID; ----表被截断。
SQL> select owner,object_name,object_id,data_object_id from dba_objects where object_na
me='XIAOXU_OBJECTID';
OWNER OBJECT_NAME OBJECT_ID DATA_OBJECT_ID
---------- -------------------------------------------------- ---------- --------------
SDXJ XIAOXU_OBJECTID 77782 77790 ---值发生变化。
4) 新增对象 OBJECT_ID 为 max(data_object_id)+1
数据库最大 data_object_id 查询:
select max(data_object_id ) from dba_objects; 得到 3251768
新建对象 index
create index sdxj.idx_xiao3 on sdxj.XIAOXU_OBJECTID2 (table_name);
---对应 object_id 和 data_object_id 为 3251769

据说,data_object_id 到大 2^32 次方,会导致数据库 HAND 住。

执行 alter table xxx move, 这个语句一般用来移动表到另 1 个表空间(move 后面要加表空间


参数),或者用来整理碎片(消除行移植和行链接), 但是会导致索引失效,所以要重建索
引。
alter index xxx rebuild online

data_object_id 用的相比来说会少一些,主要是和 seg$对应,用来表示 object 的物理存储段


的实际位置。即只有表、索引、undo 这些有实际物理存储位置的对象才有 data_object_id,而
像一些函数、存储过程、以及 view 等等是没有 data_object_id 的,也就是说仅有 object_id。

另外,当创建一个新的对象的时候 object_id 和 data_object_id 应该分别取


max(select max(object_id) from dba_objects)+1,
max(select max(hwmincr) from seg$)+1

1.关于这两者的取值的实验如下:
select a.max_object_id,b.max_hwmincr from (select max(object_id) max_object_id from dba_
objects) a,(select max(hwmincr) max_hwmincr from seg$) b;
MAX_OBJECT_ID MAX_HWMINCR
------------- -----------
89219 89219

create table pc(id number);


Table created.

select object_id,data_object_id from dba_objects where owner='SYS' and object_name='PC';


OBJECT_ID DATA_OBJECT_ID
---------- --------------
89220 89220 --符合前文所说的创建新对象时候的取值规则

drop table pc purge;


Table dropped.

select a.max_object_id,b.max_hwmincr from (select max(object_id) max_object_id from dba_


objects) a,(select max(hwmincr) max_hwmincr from seg$) b;
MAX_OBJECT_ID MAX_HWMINCR
------------- -----------
89219 89219

create table pc(id number);


Table created.

select object_id,data_object_id from dba_objects where owner='SYS' and object_name='PC';


OBJECT_ID DATA_OBJECT_ID
---------- --------------
89221 89221 --不符合前文所说的创建新对象时候的取值规则

根据大量实验发现,创建的对象的 object_id 和 data_object_id 取值会取 MAX_OBJECT_ID


和 MAX_HWMINCR 曾经达到的最大值+1,也就是上述实验中一开始 pc 表的 object_id,
data_object_id 均为 89220,但是 drop 表 pc 之后,89220 数值并不能重用,新创建的对象只
能取 89220+1 的数值。具体原因还不知道,这是接下去可以探究的问题之一。

从其他实验结果来看,尤其当上述实验中的 MAX_OBJECT_ID 和 MAX_HWMINCR 不等


的 时 候 , 新 创 建 对 象 的 object_id,data_object_id 值 为 MAX_OBJECT_ID 和
MAX_HWMINCR,其中比较大一个的曾经最大值+1。具体原因还不知道,这是接下去可以
探究的问题之一。

2.看不明白可以直接看如下实验:
create table aa (id number);
Table created.

select object_id,data_object_id from dba_objects where owner='SYS' and object_name='AA';


OBJECT_ID DATA_OBJECT_ID
---------- --------------
89224 89224

alter table aa move tablespace test;


Table altered.

select object_id,data_object_id from dba_objects where owner='SYS' and object_name='AA';


OBJECT_ID DATA_OBJECT_ID
---------- --------------
89224 89225

select a.max_object_id,b.max_hwmincr from (select max(object_id) max_object_id from dba_


objects) a,(select max(hwmincr) max_hwmincr from seg$) b;
MAX_OBJECT_ID MAX_HWMINCR
------------- -----------
89224 89225

create table yy(id number);


Table created.

select object_id,data_object_id from dba_objects where owner='SYS' and object_name='YY';


OBJECT_ID DATA_OBJECT_ID
---------- --------------
89226 89226

从这里也可以看出,对表 move 操作会增加 DATA_OBJECT_ID 的值,具体原因还不知道,


这是接下去可以探究的问题之一。

3.从网上资料看,truncate 操作也有同样的效果。
不过自己实验发现,对非空表做截断才会。具体原因未知,这是接下去可以探究的问题之
一。
select object_id,data_object_id from dba_objects where owner='SYS' and object_name='YY';
OBJECT_ID DATA_OBJECT_ID
---------- --------------
89226 89226

select count(*) from yy;


COUNT(*)
----------
0

truncate table yy;


Table truncated.

select object_id,data_object_id from dba_objects where owner='SYS' and object_name='YY';


OBJECT_ID DATA_OBJECT_ID
---------- --------------
89226 89226

insert into yy values(1);


1 row created.

commit;
Commit complete.

truncate table yy;


Table truncated.

select object_id,data_object_id from dba_objects where owner='SYS' and object_name='YY';


OBJECT_ID DATA_OBJECT_ID
---------- --------------
89226 89227

You might also like