23.1、说明:

1、

众所周知,在清空表内所有数据时,truncate比delete要快很多,原因是,delete语句每次删除一行,都在事务日志中为所删除的每行记录一项。

truncate通过释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录页的释放。但是如果表存在外键的话,是不能使用truncate的。

在使用的过程中,我发现某个存在外键的表,使用truncate提示成功了。一开始,我在怀疑是不是oracle存在bug,在某个特定条件下,触发了

这个bug,造成truncate成功了。后来,等这张表插入过数据之后,我再使用truncate时,提示失败了。我这才恍然大悟,这个问题跟exp空表

无法导出是一个原因。oralce11g为了节省存储空间,新建表的时候默认是不分配segment的。既然segment都没有,就不用谈exp和truncate了。

但是oracle还是预留了系统参数 DEFERRED_SEGMENT_CREATION(延迟创建segment)。这个参数,默认是true。我们可以将他改成false。这

样的话,再创建表的时候就会立即分配segment了。但是修改参数之前创建的表还是不会立即分配segment的。如果想分配segment,可以在表中

插入一条数据,再删除。也可以使用 alter table XXX allocate extent,这样就会创建segment了,再使用exp就会导出空表,而且存在外键的表

使用truncate清空数据时,也不会提示成功了。如果单表插入数据后被truncate,则会保留segment。


2、DEFERRED_SEGMENT_CREATION 设置为true的优缺点:

(1)优点:

在创建一系列表的时候,若事先已知许多表并没有数据,可以指定这个参数为true,这样可以节省空间,也可以增加建表速度。


(2)缺点:

使用exp导出的时候,不会导出没有segment分配的表。使用expdp可以导出空表。


3、查看该参数当前设置:

show parameter deferred_segment_creation;


4、修改该参数当前设置:

这个参数可以动态修改,使用 alter system/session set deferred_segment_creation=true/false;

更改后,之前延迟分配segment的表并不会受到影响,仍然为空表。


5、查询某schema中所有未分配segment的表可以使用以下语句:

select * from user_tables where segment_created = 'NO';


6、若想为这些未分配segment的表分配空间,可以使用语句:

select 'alter table' || table_name || 'allocate extent;' from user_tables where segment_created = 'NO';

为所有空表分配segment,之后就可以进行exp导出了。


23.2、示例:

1、说明:

用impdp命令将从linux(版本:Oracle Database 11g Enterprise Edition Release 11.2.0.4.0-64bit Production,A库)上面导出的数据库

导入到本地windows系统的数据库(Oracle Database 11g Standard Edition Release 11.2.0.1.0 - 64bit Production,B库)上时,报了以

下错误:

错误描述:

ORA-00439 未启用的功能:DEFERRED_SEGMENT_CREATION

或者叫做

ORA-00439 feature not enabled deferred segment creation


2、解决思路:

(1)查看 DEFERRED_SEGMENT_CREATION 参数设置是否一样:

在A库查询参数被设置为TRUE,在B库查询参数被设置为FALSE,修改B库设置,改成 TRUE,重新导入,还是报一样的错误。


(2)查看数据库版本:

A库是企业版,B库是标准版。

DEFERRED_SEGMENT_CREATION 在标准版中不支持该功能。


(3)解决办法:

在做expdp时,带上参数 version = 10.2.0,同样,在做impdp时,也带上参数 version = 10.2.0。

特别注意:version=11.2.0 是不行的。