数据库导出备份的时候部分表不能导出
今天在做数据迁移的过程中,本想把服务器上原有的oracle数据库备份到本地,但是在导出数据的同时,却发现的一个奇怪的问题,有部分的表没有被导出来。对于数据库备份,数据库导入来说早已操作过N便了,从来没有遇到过这样的情况。
纳闷,奇怪的同时,决定探寻究竟,为什么这部分表不能够正常的被导出。于是将注意力放到系统视图 user_tables 上,查询后比较了那些可以导出的和不能导出的表的差异,发现那些不能导出的表的字段next_extent都为空的。
google搜索了一下才恍然大悟,原来服务器上面装的oracle版本是11g的(之前测试服务器装的是10g,所以导出导入数据都没有问题),问题就在于版本是11g的,因为11G中有个新特性,当表无数据时,不分配segment,以节省空间,所以导不出如果重来没有使用过的空表默认情况下是导不出来的。如果想导出已经存在的表必须对空表进行数据的插入然后rollback。如果以后新建的空表也要自动导出,必须修改一个参数
deferred_segment_creation 查。发现原来这个11g的一个特性:deferred_segment_creation,即建立表的时候,一开始并没有直接分配存储空间。直接在字典中记录了数据结构。而只有当真正有数据的时候才分配空间。这种方法对于象SAP这样大的系统需要部署成千上万张表是非常有效的。默认是开启的,需要关闭alter system set deferred_segment_creation=false;
但是最后我采取的方式,没有用改变系统设置的这种方法(据说上述设置后,只对以后增加的表有效,我也没有测试),采用了另一种可行的方法,那就是move操作。alter table move命令可以释放空间(当然这语句最根本的作用还是移动表到不同的表空间去,这里只是借用它可以释放空间的一个特性),还要了解该动作会锁表直到命令结束,而且会导致索引失效, ...
大家可能知道deltete不会释放表空间,但是可以重用,也就是插入可以填补空洞,当然现实应用中确实是存在经常删除很少插入的情况,这样就存在了释放表空间优化数据库的可行性了,truncate有不能带条件的缺陷,自然就想到用alter table move重移表空间的方法。这里要注意三个要素
1、 alter table move 省略了tablespace XXX, 表示用户移到自己默认的表空间,因此当前表空间至少要是该表两倍大,这很好理解,由于易错所以提出,就不再细说了。
2、 alter table move过程中会导致索引失效,必须要考虑重新索引
3、 alter table move过程中会产生锁,应该避免在业务高峰期操作!
回到之前的话题,目的将11g所有的表备份下来(包括空数据表),可以通过查询
--将所有不能正常导出的表查询出来
select t.* from user_tables t where t.next_extent is null;
--构造move语句,然后批量执行
select 'alter table '||t.table_name||' move;' from user_tables t where t.next_extent is null;
这样再次进行exp导出操作,就会发现所有的表都会导出来了。。。