问题背景:
在日常客户的生产环境,测试的测试环境抑或是开发的开发环境中,经常出现相互传递数据库的情况。然而在备份数据库的过程中,有时会出现一个用户下少导出几张空表,致使后续操作出错而无法继续进行。
原因分析:
首先谈一下segment,中文叫做段,数据库中我们通常见到的表都是逻辑对象,而segment是一种占物理存储空间的的实体对象。通常而言,一张普通表对应一个segment,而对于我们日常开发运营时所使用的oracle11g有一个特性,当表无数据时,不给该表分配segment,以节省空间;也就是说,11g下的空表,是没有权利得到分配的空间。这也就是空表在备份时无法导出的原因。
解决方案:
方案一:设置deferred_segment_creation 参数
命令行下直接敲打
show parameter deferred_segment_creation;
从字面意思也可以看出来,当这个参数设置为true时(橙色警报:下图为修复问题之后截的图所以value是false),若创建表是不会给它分配segment即不分配空间的,当向这个表中插入数据的时候才开始分配segment。因此要改变该bool型变量的话只需一句
alter system set deferred_segment_creation=false;
细心的人会发现,此时deferred_segment_creation参数改变了但是由于之前已经建好的表是在true的类型下建的,已经是没有内存空间的表了,再次导出的话,还是不会导出先前建好的表的。也就是说,设置deferred_segment_creation的这套方案只适用于以后要导出的表。如果要使得之前建好的表也导出,就要用到第二种方案。
方案二:使用extent手工分配空间
名词解释:extent是oracle空间的逻辑单位,前文提到的segment就是由多个extent组成。
如果要导出已经建好的空表,就需要手工给这些表分配extent,但笔者要说的不是最古老的,寻找没有分配空间的表,然后一个个分配,而是有一种很合适也很灵巧快捷的解决方案:
命令行下执行:
select 'alter table '||table_name||' allocate extent;' from user_tables where num_rows=0;
该语句会直接导出所有的空表信息并且拼接成一个我们即将要用到的,赋空间的语句,执行完改语句之后直接选定上述查询结果,在命令行里直接复制粘贴,便可以向已建好的空表赋内存空间,也不需要一个个手工敲入。在赋予内存空间后这些表就有了内存,在备份导出库的时候就加上了这些空表。