oracle增加欄位帶預設值
在oracle 11gR2版本中,對大表增加帶預設值的欄位,需要拆分成多個步驟,否則會長時間鎖表。如下圖:
對260萬資料的表加帶預設值的欄位,執行超過2分鐘。
我們的規範做法步驟為:
(1)加欄位
alter table T_ORDER add tstatus varchar2(20);
(2)批量更新資料
declare
n_count number;
begin
select ceil(count(1)/100000) into n_count
from T_ORDER where tstatus is null;
for i in 1..n_count loop
update T_ORDER set tstatus='1' where tstatus is null and rownum<=100000;
commit;
end loop;
end;
/
(3)增加預設值屬性
alter table TABLE_NAME modify tstatus default '1' not null;
在19c中不再需要如此繁冗的操作了,新增帶預設值的欄位可以瞬間完成:
實驗準備: | create table test(
owner varchar2(30), object_name varchar2(128), object_type varchar2(30), created date ); insert into test select owner,object_name,object_type ,to_Date('20190101','yyyymmdd')+60*dbms_random.value from all_objects; commit; --重複執行insert操作,插入200萬資料 insert into test select * from test; commit; SQL> select count(1) from test; COUNT(1) ---------- 3461376 |
|
oracle11gR2版本: |
|
|
|
會話1 | 會話2 |
結論1:在oracle11gR2版本中,進行新增列、修改列的預設值操作時,如果其他會話中沒有未提交的ddl、dml操作,則可以瞬間完成。 | SQL> set timing on
SQL> alter table test add col2 varchar2(10) ; Table altered. Elapsed: 00:00:00.00 SQL> SQL> SQL> alter table test modify col2 default '1'; Table altered. Elapsed: 00:00:00.00 SQL> SQL> select count(1) from test where col2='1'; COUNT(1) ---------- 0 Elapsed: 00:00:00.04 |
|
結論2:在oracle11gR2中,直接新增帶預設值的列,執行時間和表的資料量相關 | SQL> alter table test add col3 varchar2(10) default '1';
Table altered. Elapsed: 00:01:49.02 SQL> SQL> SQL> SQL> alter table test add col4 date default sysdate; Table altered. Elapsed: 00:02:04.62 |
|
結論3:當有DML操作未提交時,新增帶預設值的列將報錯(獲取獨佔鎖失敗)。新增列不帶預設值時,會等待dml操作提交(釋放行級鎖)後才可執行完成。 |
|
SQL> set time on
15:17:50 SQL> delete from test where rownum=1; 1 row deleted. |
SQL> set time on
15:18:11 SQL> alter table test add col5 varchar2(10) default '1'; alter table test add col5 varchar2(10) default '1' * ERROR at line 1: ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired Elapsed: 00:00:00.00 15:18:16 SQL> alter table test add col5 varchar2(10); |
| |
|
15:17:54 SQL> commit;
Commit complete. 15:18:43 SQL> | |
Table altered.
Elapsed: 00:00:20.35 15:18:43 > |
| |
結論4:新增預設值帶預設值、非空約束時,如果沒有DML阻塞,可以瞬間完成;如果有DML操作未提交,則需等待直到DML操作提交才可完成 | 15:24:50 SQL> alter table test add col6 varchar2(10) default '1' not null;
Table altered. Elapsed: 00:00:00.01 |
|
|
15:27:55 SQL> delete from test where rownum=1;
1 row deleted. | |
15:28:01 SQL> alter table test add col7 varchar2(10) default '1' not null; |
| |
|
15:28:47 SQL> commit;
Commit complete. 15:29:04 SQL> | |
Table altered.
Elapsed: 00:00:09.27 15:29:04 SQL> |
| |
|
|
|
oracle19c版本 | 實驗準備操作相同,資料量基本一致
SQL> SQL> select count(1) from test; COUNT(1) ---------- 3479400 |
|
|
會話1 | 會話2 |
結論5:在19c版本中,增加帶預設值、無非空約束的列,可以瞬間完成。如果有DML操作未結束,仍需等待該操作完成才可以結束。 | SQL> set timing on
SQL> alter table test add col3 varchar2(10) default '1'; Table altered. Elapsed: 00:00:00.01 SQL> SQL> alter table test add col4 date default sysdate; Table altered. Elapsed: 00:00:00.02 |
|
|
SQL> set time on
15:43:01 SQL> delete from test where rownum=1; 1 row deleted. | |
15:43:07 SQL> alter table test add col5 varchar2(10) default '1';
|
| |
|
15:43:03 SQL> commit;
Commit complete. 15:43:24 SQL> | |
Table altered.
Elapsed: 00:00:05.76 15:43:24 SQL> 15:43:24 SQL> |
|
在19c官方文件中有如下描述:
直譯為
11.2版本中 alter table add column with default value的操作正常不會阻塞,但在使用supplemental log時會降級為阻塞操作。
實際測試該操作,將資料庫開啟最小輔助日誌、表開啟輔助日誌( alter table testu.test2 add supplemental log data(all) columns;),然後對test表使用OGG同步。操作都可以瞬間完成。這裡還沒太明白,後續有進展再補充。
總結:
在11gR2版本中增加帶預設值的列時,需要指定not null屬性,即可瞬間完成;否則鎖表時間較長。
在19c版本中 增加帶預設值的列時,不管是否包含not null屬性,都可瞬間完成。
操作需要在業務低峰期操作,避免操作時有dml操作對其造成阻塞。
感悟:
資料庫中的DML操作,主要需要避免大事務造成的鎖表時間長、佔用redo及undo等資源巨大、資源不足時回滾操作不可控等問題;
DDL操作時除了操作時間,還需要考慮表的獨佔鎖對其他操作的阻塞問題。
隨著資料庫版本的迭代,功能愈加完善,很多經驗已經不再適用了。適用新版本資料庫前,應該對規範、操作手冊進行測試,與時俱進,提高效率。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26451536/viewspace-2698825/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 查詢oracle欄位預設值Oracle
- [20201109]11.2.0.4增加欄位與預設值問題.txt
- [20210421]12c以上版本增加欄位與預設值.txt
- sql設定欄位預設值SQL
- MySQL欄位預設值設定詳解MySql
- SharePoint 多行文字欄位設定預設值
- jpa~為欄位新增insert的預設值
- Django日期欄位預設值default=timezone.nowDjango
- mysqldump 欄位值帶單引號MySql
- mysql datetime增加預設值MySql
- Oracle 增加修改刪除欄位與新增註釋Oracle
- Oracle-批量修改欄位裡面的值Oracle
- Sqlserver的欄位datetime型別預設值設為getdate()時,設值毫秒為000SQLServer型別
- pydantic 欄位的預設值設定獲取當前時間
- EBS:主鍵ID欄位預設值來源於序號
- laravel欄位減少增加Laravel
- 帝國CMS欄目管理增加自定義欄位值的為空判斷
- 小書MybatisPlus第9篇-常用欄位預設值自動填充MyBatis
- [BUG反饋]新建欄位無法使用字元型預設值字元
- sql語句修改欄位型別和增加欄位SQL型別
- 為React Ant-Design Table增加欄位設定React
- [20231020]增加欄位的問題.txt
- [BUG反饋]模型增加欄位BUG模型
- Request 增加自定義欄位的方式
- 建議欄位別名定義定義那裡順便可定義預設值,這預設值還可以是函式函式
- [BUG反饋]模型增加欄位後field_sort欄位未更新模型
- 【Mongo】mongo更新欄位為另一欄位的值Go
- Oracle-欄位的新增Oracle
- Oracle-新增一個欄位並設定日期Oracle
- Oracle表 列欄位的增加、刪除、修改以及重新命名操作sqlOracleSQL
- 在oracle中,select語句查詢欄位中非純數字值Oracle
- ORACLE LOB大欄位維護Oracle
- oracle fga審計(欄位級)Oracle
- Drupal 如何得到欄位的值?
- mongodb 取欄位最大值MongoDB
- mybatisplus欄位值自動填充MyBatis
- [需求建議]建議欄位別名定義定義那裡順便可定義預設值,這預設值還可以是函式函式
- MySQL為欄位新增預設時間(插入時間)MySql