注意通常大家习惯查询的 DBA_OBJECTS 字典视图就是基于 OBJ$ 数据字典表创建的,DBA_OBJECTS 中有两个字段经常使人误解:OBJECT_ID 和 DATA_OBJECT_ID。这两个字段分别来自 OBJ$中的 OBJ#和 DATAOBJ#,
其中 OBJ#(也即 OBJECT_ID)可以被看作是对象的逻辑号(类似序列号一样分配),该序号一旦分配之后就不会发生改变;
而 DATAOBJ#(也即 DATA_OBJECT_ID)则是和物理存储关联的编号,通常被认为是对象的物理号,这个编号会随着对象物理存储结构的改变而发生改变。
注意下面的注释中已经清晰的指出了这一点,Oracle 提示“不要在 DATAOBJ#上创建索引,因为在空间事务如 TRUNCATE 中,DATAOBJ#会发生改变:
obj# number not null, /* object number */
/* DO NOT CREATE INDEX ON DATAOBJ# AS IT WILL BE UPDATED IN A SPACE
* TRANSACTION DURING TRUNCATE */
dataobj# number, /* data layer object number */
通过如下测试就可以发现 TRUNCATE 的这一特点:
SQL> create table test as select * from dba_users;
SQL> select object_id,data_object_id from dba_objects where owner='SYS' and object_name='TEST';
OBJECT_ID DATA_OBJECT_ID
---------- --------------
15036 15036
SQL> truncate table test;
SQL> select object_id,data_object_id from dba_objects where owner='SYS' and object_name='TEST';
OBJECT_ID DATA_OBJECT_ID
---------- --------------
15036 15037
实际上这也暗示了 TRUNCATE 作为 DDL 可以快速回收空间的本质,在执行 TRUNCATE操作时,数据库只是简单的回收空间,将空间标记为可用(并不会去数据块上真正去删除数据),同时将对象的数据对象重新定位,完成空间回收。
那么实际上,虽然 Oracle 并未提供直接的办法,在原对象存储位置被重新写入数据之前,TRUNCATE 数据仍然是有办法恢复的(就如同在 Windows 上误删除的文件,在覆盖之前,是可以通过软件进行恢复的)。




