大表添加一個字段需求


測試目標:

   客戶需求,一套11.2.0.4環境下,4G大表,添加一個字段。

   本次測試從,時間消耗,鎖申請級別,以及字段是否添加默認值,數據真實存儲進行測試;

 

測試流程:

  一.創建測試表

SQL> drop table a purge;

Table dropped.

SQL> create table a as select * from dba_objects;

Table created.

SQL> set timing on
多次循環插入
 
         

SQL> insert into a select * from a;
22291968 rows created.
SQL> commit;
SQL> select sum(Bytes)/1024/1024 from user_segments where segment_name='A' ;
SUM(BYTES)/1024/1024
--------------------
4990

二.添加字段,並且附加default

1)申請鎖資源
Session 1

SQL> delete a where rownum=1;

1 row deleted.

Session 2
SQL> alter session set ddl_lock_timeout=600;
SQL>  alter table a add C_LHR VARCHAR2(100) DEFAULT 'LHR';
會話hang住,查詢申請的鎖資源

SQL> select object_id from dba_objects where owner='YZ' and object_name='A';

OBJECT_ID
----------
89526

SQL> select sid,id1,type,lmode,request,ctime,block from v$lock where id1=89526;

SID ID1 TY LMODE REQUEST CTIME BLOCK
---------- ---------- -- ---------- ---------- ---------- ----------
329 89526 TM 3 0 156 1
312 89526 TM 0 6 86 0   申請TM 6!!!

 

2)更新時間

Session 1 回滾,讓添加字段的操作自動執行

SQL> roll;
Rollback complete.

與系統性能有關!  

查詢用戶正在執行的event

SQL> select event,sid from gv$session where status='ACTIVE' and username='YZ';

EVENT SID
----------------------------------------------------------------- ------
log file switch (checkpoint incomplete) 312
SQL*Net message from client 329

 

由於測試環境日志未進行格式化,因此日志文件很小,日志組數量也少,最終導致Session被CKPT進程未完成而造成的等待,大大延誤時間,並且歸檔日志有大量產生。

查詢統計執行alter table 操作的session event統計

Elapsed: 00:40:59.26

 

 

 

可以發現,數據庫等待CKPT進程寫完畢20分鍾,等待日志切換15分鍾,相反看起來數量最多的物理單快讀次數最多40萬次,但是實際消耗的時間才3分鍾。

本次不涉及優化,但是從本次修改的角度看,直接添加字段加default 數值,效率太低,成本太高,鎖表TM6號鎖。

 

三. 添加字段,但是不加default,后續對字段設置default值

      本次對比不太嚴謹,在已添加的字段上,在次添加(但是測試效果能體現就行)

1)相同,觀察申請鎖資源
Session 1

SQL> delete a where rownum=1;

1 row deleted.

Session 2
SQL> alter session set ddl_lock_timeout=600;
SQL>  alter table a add C_LHR_NEW VARCHAR2(100);
會話hang住,查詢申請的鎖資源

SQL> select object_id from dba_objects where owner='YZ' and object_name='A';

OBJECT_ID
----------
89526

SQL> select sid,id1,type,lmode,request,ctime,block from v$lock where id1=89526;

SID ID1 TY LMODE REQUEST CTIME BLOCK
------ ---------- -- ---------- ---------- ---------- ----------
312 89526 OD 6 0 10 0
329 89526 TM 3 0 30 0
312 89526 TM 3 0 10 0

未發現被阻塞的現象,查詢測試環境被阻塞的Session,可以發現申請一個TX鎖資源

SQL> select sid,id1,type,lmode,request,ctime,block from v$lock where REQUEST>0;

SID ID1 TY LMODE REQUEST CTIME BLOCK
------ ---------- -- ---------- ---------- ---------- ----------
312 131075 TX 0 4 74 0

可以發現,並未對表添加TM>3級別鎖,不鎖表,只是業務表有DML操作,無法添加字段。

2)觀察時間
session1 回滾
SQL>rollback;

Session2 秒出結果,也就是說,不修改數據行,只是修改數據字典相關記錄信息。

查詢數據

SQL> set autotrace TRACE
SQL> select * from a where rownum=1;

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter(ROWNUM=1)

 

  3)對表新增加的列,增加default值

SQL> ALTER TABLE a MODIFY C_LHR_NEW VARCHAR2(100) DEFAULT 'LHR';

Table altered.

Elapsed: 00:00:00.04   秒出結果

查詢數據

SQL> select C_LHR_NEW from a where rownum=1;

C_LHR_NEW
----------------------------------------------------------------------------------------------------

Null

SQL>alter table a modify C_LHR_NEW not null
*
ERROR at line 1:
ORA-02296: cannot enable (YZ.) - null values found

4)也就是說,添加字段,修改默認值,修改not null屬性無法操作,因為列存在null值
還一種

SQL> alter table a add C_LHR_NEW2 varchar2(200) default 'LHR' not null;

Table altered.

Elapsed: 00:00:00.04  秒出

SQL> select C_LHR,C_LHR_NEW,C_LHR_NEW2 FROM A where rownum=1;

C_LHR C_LHR_NEW C_LHR_NEW2
---------- ---------- --------------------
LHR                  LHR

 

5)使用上述的方法,進行查詢數據,是否真實存儲數據,還是其它方式存儲的數據方式

創建測試表

SQL> create table b as select * from dba_objects ;

SQL> alter table b add c_name varchar2(100) default 'LHR' not null;        

SQL> select count(*) from b where c_name='CC';

COUNT(*)
----------
0

SQL> select * from table(dbms_xplan.display_cursor);

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
SQL_ID 9qj24brgbnrkg, child number 0
-------------------------------------
select count(*) from b where c_name='CC'

Plan hash value: 749587668

---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 347 (100)| |
| 1 | SORT AGGREGATE | | 1 | 52 | | |

|* 2 | TABLE ACCESS FULL| B | 14 | 728 | 347 (1)| 00:00:05 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter(NVL("C_NAME",'LHR')='CC')    

也就是說,對於這種方式創建的oracle列,實際上並未存儲數據,只是顯示查詢使用nvl參數當無數據時是null值,則顯示LHR數據default值

 

SQL> update b set c_name='DD' where object_id=20;

SQL> commit;

 

SQL> select count(*) from b where c_name='DD';

COUNT(*)
----------
1

   2 - filter(NVL("C_NAME",'LHR')='DD')

補充說明及總結

1.添加字段,不使用default 秒出結果,只是對數據字典進行修改;

2.添加字段,使用default 的值並且不加not null,則會修改數據字典外,對每一行記錄真正的修改數據操作,大表而言代價非常大!

3.添加字段,使用default + not null,則oracle使用另外一種機制,達到不真正修改表的行記錄,但是能滿足查詢需求! 某些場景很適用。

Oracle11g中,在添加一個包含DEFAULT值的NOT NULL字段,Oracle不會去更新現有的數據,Oracle需要做的不過是將默認值以及對應的表信息、列信息一起存儲在一個新增數據字典表ecol$中。這張表利用BLOB字段存儲ALTER TABLE添加的DEFAULT值

   

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM