上一篇说了oracle 11g中,add column的时候,其实并没有真正去修改以前的块,Oracle只不过采用了类似nvl(null,default value)的方法来处理这个问题,但是,如果再次去掉这个默认值,那会怎么样呢?
下面将做一个简单的实验,来说明这个问题,这里的实验,完全接着上一篇的实验,所以,具体情况,还是请先参考上一篇:Oracle 11g增加列,并带默认值的新特性
上一篇说到了,新添加的列,如果指定了默认值,并没有修改以前的块,读取以前的行的时候,可能发生一个转换过程。但是,如果对于已经设置过默认值的情况,插入新值的时候,这么默认值是怎么处理的呢:
之前的情况:
- Piner@11gR1> desc test;
- Name Type Nullable Default Comments
- ---- ---------- -------- ------- --------
- A INTEGER Y
- FLAG CHAR(2000) Y 0
- Piner@11gR1>exec show_space('TEST');
- Total Blocks............................8
- Total Bytes.............................65536
- Unused Blocks...........................0
- Unused Bytes............................0
- Last Used Ext FileId....................4
- Last Used Ext BlockId...................83745
- Last Used Block.........................8
- PL/SQL procedure successfully completed.
- Piner@11gR1>select count(*) from test;
- COUNT(*)
- ----------
- 1000
插入新记录:
- Piner@11gR1>begin
- 2 for i in 1..1000 loop
- 3 insert into test(a) values('1');
- 4 end loop;
- 5 commit;
- 6 end;
- 7 /
- PL/SQL procedure successfully completed.
- Piner@11gR1>exec show_space('TEST');
- Total Blocks............................384
- Total Bytes.............................3145728
- Unused Blocks...........................0
- Unused Bytes............................0
- Last Used Ext FileId....................4
- Last Used Ext BlockId...................90889
- Last Used Block.........................128
- PL/SQL procedure successfully completed.
可以看到,新插入的1000条记录,块的个数发生了非常大的变化,证明了在新的记录中,Oracle实际上是真正把默认值添加到块中去了。但是,只有以前的记录依然是没有值的,需要靠转换来完成。
现在有2000条记录,是分2次插入进去的,这个时候,如果去掉默认值,会发生什么情况?是一半有值,一半没有值,还是都有值呢?我们再看:
- Piner@11gR1>alter table test modify flag default null null;
- Table altered.
- Piner@11gR1>select count(*) from test where flag is null;
- COUNT(*)
- ----------
- 0
- Piner@11gR1>exec show_space('TEST');
- Total Blocks............................384
- Total Bytes.............................3145728
- Unused Blocks...........................0
- Unused Bytes............................0
- Last Used Ext FileId....................4
- Last Used Ext BlockId...................90889
- Last Used Block.........................128
- PL/SQL procedure successfully completed.
可以看到,虽然解除了默认值,块的个数也没有任何变化,以前的记录依然是没有真实的写入任何数值到块中的,但是,Oracle 依然能把以前的默认值显示出来,因为is null查不出来任何记录,而且查询记录就可以看到实际的值就是以前的默认值。
最后,再增加1000条记录,这个时候可以发现,因为去掉了默认值,现在在另外一个列上,写入的为null。
- Piner@11gR1>begin
- 2 for i in 1..1000 loop
- 3 insert into test(a) values(1);
- 4 end loop;
- 5 commit;
- 6 end;
- 7 /
- PL/SQL procedure successfully completed.
- Piner@11gR1>exec show_space('TEST');
- Total Blocks............................384
- Total Bytes.............................3145728
- Unused Blocks...........................0
- Unused Bytes............................0
- Last Used Ext FileId....................4
- Last Used Ext BlockId...................90889
- Last Used Block.........................128
- PL/SQL procedure successfully completed.
- Piner@11gR1>select count(*) from test where flag is null;
- COUNT(*)
- ----------
- 1000
所以,对于整个过程分析下来,可以这么认为,oracle在add column default的时候,只是记录了一个标记,标记为这个点之前的所有块,如果是NULL的话,是需要转换的,反之取出实际的值。而这个点之后的块,就是按照实际的值来处理,如果中途反复修改,则以修改为准。
因为add column default,对于一个列,最多发生一次,所以,一个列只记录一个参照点即可。
但是,对于这个特性,有人想问,如果想保持以前的值为null,不要强行转换,但是,又想把新增加的列设置一个默认值,怎么办?其实也很简单,跟以前一样,分2步走即可,这样的话,以前的值还是null,新的值将为默认值。
- Piner@11gR1>alter table table_name add field_name number;
- Piner@11gR1>alter table table_name modify field_name default 0;
上一篇: « Oracle 11g增加列,并带默认值的新特性
- 发表评论


