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