ORACLE11g“空表”无法导出的深入分析

    我觉得将空表无法导出描述为没有使用过的表无法导出应该更确切一些。oralce11g为了节省存储空间,新建表的时候默认是不分配segment的。既然segment都没有,就不用谈exp了。但是oracle还是预留了系统参数DEFERRED_SEGMENT_CREATION(延迟创建segment)。这个参数,默认是true。我们可以将他改成false。这样的话,再创建表的时候就会立即分配segment了。但是修改参数之前创建的没使用过的表还是不会立即分配segment的。如果想分配segment,可以在表中插入一条数据,再删除。也可以使用alter table XXX allocate extent。这样就会创建segment了。再使用exp就会导出没使用过的表。

    理解了oracle11g无法导出的不是空表而是没使用过的表之后,我们就不难看出,网络上很多人给出的查询批量修改无法导出的表的语句是错的。

    比较常见的有:

select 'alter table '||table_name||' allocate extent;' from user_tables where num_rows=0;

select 'alter table '||table_name||' allocate extent;' from user_tables where num_rows=0 or num_rows is null;

    我们来分析一下这两个select语句。num_rows = 0表示表里的记录数为0,但是这个数值是通过数据库执行analyze table之后写入的,而数据库执行analyze table是有条件的,所以num_rows并不能实时的表示表里面的记录数。num_rows = 0, 对应表里的记录数可能会大于0。新创建的从未使用过的表在数据库没有执行analyze table之前,num_rows是NULL,只有执行了analyze table之后num_rows才会变成0。而且如果执行analyze table  tablename delete statistics把表的统计信息删除,该表在user_tables中对应的num_rows会变成NULL。

    也就是说num_rows =0 并不能说明这个表没有被使用过,也并不能说明这个表里没有记录。num_rows is null也不能说明这个表没有被使用过。

    理解了表无法导出是因为没有分配segment之后,我们就可以写出真正的查询批量修改无法导出的表的语句了

select 'alter table '||table_name||' allocate extent;' from user_tables where tablespace_name = 'PORTAL_HIS' and not exists(select 1 from dba_segments where segment_type ='TABLE' and tablespace_name =user_tables.tablespace_name and dba_segments.segment_name = user_tables.table_name);

    错误理解了“空表”无法导出,才写出了错误的select语句。只有真正弄明白了问题的原因,才能写出正确的应对方法。

上一篇:oracle编译存储过程提示表或视图不存在的问题分析


下一篇:Windows下多个JDK版本的切换方法