在11g以前,當表很大的時候,如果往表中新增一個NOT NULL的字段,不光是執行速度慢,而且由於現有數據長度的變化,很容易造成表中大量的行鏈接情況,進而使表佔用的空間大大增加。
在11g中,這種情況得到了徹底的改善,Oracle通過在數據字典中記錄DEFAULT值,避免了繁重的更新操作,增加非空字段的時間和增加一個可空字段的時間完全一樣。
10g中添加一個包含DEFAULT值的非空字段的測試:
Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.4.0
Connected as ppsclient
SQL> select count(1) from yu_test1;
COUNT(1)
----------
31956
SQL>
SQL> Select owner, Segment_Name, Sum(bytes) / 1024 DSIZE
2 From DBA_Extents
3 where Segment_Name = 'YU_TEST1'
4 Group By owner, Segment_Name
5 order by 3 desc;
OWNER SEGMENT_NAME DSIZE
------------------------------ -------------------------------------------------------------------------------- ----------
PPSCLIENT YU_TEST1 3072
SQL>
SQL> ALTER TABLE YU_TEST1 ADD NEW_COL CHAR(1000) DEFAULT 'TEST COLUMN' NOT NULL;
Table altered
耗時:4.12s
SQL>
SQL> Select owner, Segment_Name, Sum(bytes) / 1024 DSIZE
2 From DBA_Extents
3 where Segment_Name = 'YU_TEST1'
4 Group By owner, Segment_Name
5 order by 3 desc;
OWNER SEGMENT_NAME DSIZE
------------------------------ -------------------------------------------------------------------------------- ----------
PPSCLIENT YU_TEST1 44032
11g中添加一個包含DEFAULT值的非空字段的測試:
Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.1.0
Connected as SYS
SQL> select count(1) from yuzh.yu_test1;
COUNT(1)
----------
31956
SQL>
SQL> Select owner, Segment_Name, Sum(bytes) / 1024 DSIZE
2 From DBA_Extents
3 where Segment_Name = 'YU_TEST1'
4 Group By owner, Segment_Name
5 order by 3 desc;
OWNER SEGMENT_NAME DSIZE
------------------------------ -------------------------------------------------------------------------------- ----------
YUZH YU_TEST1 3072
SQL> ALTER TABLE yuzh.YU_TEST1 ADD NEW_COL CHAR(1000) DEFAULT 'TEST COLUMN' NOT NULL;
Table altered
耗時:0.89s
SQL>
SQL> Select owner, Segment_Name, Sum(bytes) / 1024 DSIZE
2 From DBA_Extents
3 where Segment_Name = 'YU_TEST1'
4 Group By owner, Segment_Name
5 order by 3 desc;
OWNER SEGMENT_NAME DSIZE
------------------------------ -------------------------------------------------------------------------------- ----------
YUZH YU_TEST1 3072
SQL>
從上面的測試可以看出,雖然只有3萬的數據,但是10g添加字段用了4秒,而11g只用了不到1s,而且不光是時間上快了很多,空間上夜節省了很多,10新增字段後差不多要44m,而11g增加後還是隻有3m。再來的優點還有就是生成REDO和UNDO的大小,11g也遠小於10g的,這方面的測試不做了。
這裏又出現了個問題,爲什麼11g新增字段後表大小沒有變化呢,說起來也很簡單。Oracle11g中,在添加一個包含DEFAULT值的NOT NULL字段,Oracle不會去更新現有的數據,Oracle需要做的不過是將默認值以及對應的表信息、列信息一起存儲在一個新增數據字典表ecol$中。這張表利用BLOB字段存儲ALTER TABLE添加的DEFAULT值:
SQL> SELECT OBJECT_ID FROM DBA_OBJECTS WHERE OBJECT_NAME = 'YU_TEST1';
OBJECT_ID
----------
73202
SQL> SELECT * FROM SYS.ECOL$ WHERE TABOBJ# = 73202;
TABOBJ# COLNUM BINARYDEFVAL
---------- ---------- ------------
73202 6 <BLOB>
Oracle在讀取數據時,發現COLUMN 6列爲非空,但是在存儲的數據中找不到該列,於是就會從ECOL$中讀取該列的默認值。
這個功能不但提高了添加非空字段的速度,而且節省了大量的磁盤空間。相比之下,在數據字典中查找DEFAULT VALUE的代價小的幾乎可以忽略。