Oracle大表添加字段
在添加字段時,如果表數據量特別大。給添加的字段設置默認值,會消耗特別長的時間,而且所有行都要被鎖住。
在生產系統上,如果沒有安排足夠長的變更時間,可能會對業務帶來嚴重的影響。
對於這種情況,可以使用下面的語句:
alter table table_name add new_column data_type(precision) default 'value_string' not null;
也就是default + not null 這兩個關鍵詞組合的方式。
使用這種方法添加的字段,並不會真的修改每行的值,而是在sys.ecol$ 里添加一行數據,記錄下該字段的默認值。
雖然沒有進行物理存儲,但是對查詢、數據泵等操作都沒有影響 。
可以看下面示例:
SQL> col tabobj# for 999999999
SQL> col column for a20
SQL> col binarydefval for 99999999999999999999
SQL> select * from sys.ecol$;
未選定行
SQL> alter table test_object add create_user varchar2(30) default 'halberd' not null;
表已更改。
SQL> col tabobj# for 999999999
SQL> col column for a20
SQL> col defval for a15
SQL> select tabobj#,COLNUM, utl_raw.cast_to_varchar2(binarydefval) as defval from sys.ecol$;
TABOBJ# COLNUM DEFVAL
---------- ---------- ---------------
247703 27 halberd
SQL> select object_id,object_name from dba_objects where object_name='TEST_OBJECT';
OBJECT_ID OBJECT_NAME
---------- ------------------------------
247703 TEST_OBJECT
SQL> select column_id from dba_tab_cols where owner='SYSTEM' and table_name='TEST_OBJECT' AND COLUMN_NAME='CREATE_USER';
COLUMN_ID
----------
27
這里我們驗證了,該方式添加字段后,在sys.ecol$ 里插入了一行數據 。
下面驗證,數據並沒有存儲到物理行中。
SQL> select max(column_id) from dba_tab_cols where table_name='TEST_OBJECT' AND OWNER='SYSTEM';
MAX(COLUMN_ID)
--------------
27
SQL> update test_object set create_user='halberd' where rownum=1;
已更新 1 行。
SQL> commit;
提交完成。
SQL> select rowid,dbms_rowid.rowid_object(rowid) object_id,
dbms_rowid.rowid_relative_fno(rowid) rfno,
2 3 dbms_rowid.rowid_block_number(rowid) rdbno,
4 dbms_rowid.rowid_row_number(rowid) rno from test_object WHERE ROWNUM<=2;
ROWID OBJECT_ID RFNO RDBNO RNO
------------------ ---------- ---------- ---------- ----------
AAA8eXAABAADz9BAAA 247703 1 999233 0
AAA8eXAABAADz9BAAB 247703 1 999233 1
SQL> select file_id,relative_fno from cdb_data_files where relative_fno=1;
FILE_ID RELATIVE_FNO
---------- ------------
199 1
SQL> alter system dump datafile 199 block 999233;
system altered.
從上面的查詢結果來看,表test_object 有27個字段。我添加的新字段,就是第27個字段。如果是dump數據塊出來,顯示的就是row 26, 因為dump 結果是從row 0 開始的。
下面是dump的數據塊中前兩行的的內容:
block_row_dump: tab 0, row 0, @0x3f5 tl: 114 fb: --H-FL-- lb: 0x3 cc: 27 col 0: [ 3] 53 59 53 col 1: [14] 49 5f 46 49 4c 45 23 5f 42 4c 4f 43 4b 23 col 2: *NULL* col 3: [ 2] c1 0a col 4: [ 2] c1 0a col 5: [ 5] 49 4e 44 45 58 col 6: [ 7] 78 77 04 11 01 39 0f col 7: [ 7] 78 77 04 11 01 39 0f col 8: [19] 32 30 31 39 2d 30 34 2d 31 37 3a 30 30 3a 35 36 3a 31 34 col 9: [ 5] 56 41 4c 49 44 col 10: [ 1] 4e col 11: [ 1] 4e col 12: [ 1] 4e col 13: [ 2] c1 05 col 14: *NULL* col 15: [ 4] 4e 4f 4e 45 col 16: *NULL* col 17: [ 1] 59 col 18: [ 1] 4e col 19: *NULL* col 20: [ 1] 4e col 21: [ 1] 4e col 22: *NULL* col 23: *NULL* col 24: *NULL* col 25: *NULL* col 26: [ 7] 68 61 6c 62 65 72 64 tab 0, row 1, @0x1ec4 tl: 94 fb: --H-FL-- lb: 0x0 cc: 22 col 0: [ 3] 53 59 53 col 1: [ 6] 49 5f 4f 42 4a 33 col 2: *NULL* col 3: [ 2] c1 27 col 4: [ 2] c1 27 col 5: [ 5] 49 4e 44 45 58 col 6: [ 7] 78 77 04 11 01 39 0f col 7: [ 7] 78 77 04 11 01 39 0f col 8: [19] 32 30 31 39 2d 30 34 2d 31 37 3a 30 30 3a 35 36 3a 31 34 col 9: [ 5] 56 41 4c 49 44 col 10: [ 1] 4e col 11: [ 1] 4e col 12: [ 1] 4e col 13: [ 2] c1 05 col 14: *NULL* col 15: [ 4] 4e 4f 4e 45 col 16: *NULL* col 17: [ 1] 59 col 18: [ 1] 4e col 19: *NULL* col 20: [ 1] 4e col 21: [ 1] 4e tab 0, row 2, @0x1e67
第一行, tab 0, row 0, @0x3f5 , 最后一個字段是第27個字段(dump 出來的字段數行數據都是從0 開始的)。
SQL> select utl_raw.cast_to_varchar2(replace('68 61 6c 62 65 72 64',' ')) as val from dual;
VAL
--------------------------------------------------------------------------------
halberd
而第二行, tab 0, row 1, @0x1ec4 ,則僅僅dump 出22個字段。說明22個字段之后的內容根本沒有存儲在數據塊中,所以dump的結果沒有這些字段的內容。
Created: 2020-09-16 Wed 10:38
