Oracle 12c 能否在2小時內線上完成一張14億條記錄的表結構欄位型別變更
原文連結:
摘要:Oracle 12c 能否在2小時內線上完成一張14億條記錄的表結構欄位型別變更
概述
- 前面分享過Oracle大表線上修改的指令碼(線上重定義),經過幾輪的測試發現,都存在些缺陷,效率始終不是很滿意。這次把索引和統計資訊拆出來後發現效率相對算是最高的。
- 線上重定義的目標,是對線上業務影響最小,透過最短的鎖表時間來實現表結構的變更,鎖表只發生在finish_redef_table過程中,正式切換前先執行sync_interim_table過程非同步同步資料,以儘可能減少業務影響。
- 由於是要對客戶的核心業務變更,按管理要求沒辦法提前執行finish_redef_table前的過程,且維護視窗時間有限,業務又不能完全停掉,才有了這次的測試。
- 主要測試常見的2種場景,如下:
-
場景1:
複製全部依賴 - COPY_TABLE_DEPENDENTS(索引 + 約束 + 統計資訊),觸發器和許可權這種基本沒有,就沒有複製。 -
優點:操作方便,指令碼直接把原表所有依賴全部複製過去,改後的表直接使用,不需要額外處理,適合百萬或千萬的表,且對效率沒要求可用。
-
缺點:上億的表測試發現效率非常低。
-
場景2:
有主鍵的表只複製約束 - COPY_TABLE_DEPENDENTS(會複製主鍵和唯一索引),其它索引和統計資訊等重定義完成後再開並行重建和收集,這裡要補充說明一下為什麼要複製約束,因為建立主鍵不能並行操作,等重定義完成資料轉換後,相當於在普通大表上建立主鍵,效率非常低。 -
優點:目前針對10億以上的表測試發現效率是最高的,14億的表全部弄完約2小時左右。
-
缺點:操作過程稍微麻煩一點,別的還好。
-
複製規則,如下:
copy_indexes => 0, copy_triggers => FALSE, copy_constraints => TRUE, copy_privileges => FALSE, ignore_errors => FALSE, num_errors => num_errors, copy_statistics => FALSE);
由於場景1的效率比較差,我這裡就只列舉場景2的測試過程,後續實際業務變更也是在場景2中進行,以下是整個變更過程:
- 硬軟配置一般,如下:
- CPU:Intel® Xeon® CPU E7-4820 v3 @ 1.90GHz(物理4個,10核心,80個邏輯cpu)
- 記憶體:500 GB
- 儲存:華為某型號
- 資料庫軟體:Oracle 12.2 Nocdb RAC,未打補丁。
- 我們先看一下原表資料行數,接近14億條,人工造的,表實際大小和生產相差1倍以上。
SQL> select /*+ parallel(40) */ count(*) from OM_OFFERING_INST_TEST; COUNT(*)----------1399999996 Elapsed: 00:00:17.39
- 建立臨時表,有35個分割槽,部份省略了,主鍵、索引等都不要建。
CREATE TABLE "CUSTINFO"."INT_OM_OFFERING_INST_TEST" ( "BUSINESS_SEQ" VARCHAR2(20), "PROD_ID" NUMBER(20, 0), "OFFERING_INST_ID" NUMBER(20, 0), "OFFERING_ID" NUMBER(20, 0), "OFFERING_NAME" VARCHAR2(256), "OFFERING_CODE" VARCHAR2(50), "CUST_TYPE" VARCHAR2(20), "CUST_ID" NUMBER(20, 0), "BRAND" VARCHAR2(50), ...... "RECORD_STATUS" NUMBER(3, 0) DEFAULT 1) PARTITION BY LIST ( "BE_ID" ) ( PARTITION "P_000" VALUES ( '000' ), PARTITION "P_001" VALUES ( '001' ), PARTITION "P_002" VALUES ( '002' ) , PARTITION "P_100" VALUES ( '100' ) , PARTITION "P_200" VALUES ( '200' ) , ..........
- 定義引數,設定並行和行遷移
define USERNAME = 'CUSTINFO'; --使用者名稱define SOURCE_TAB = 'OM_OFFERING_INST_TEST';-- 原表名define INT_TAB = 'INT_OM_OFFERING_INST_TEST';-- 臨時表名,需要手工提前建立define PARALLELS = 35; --並行數,這裡設的分割槽數alter session enable parallel dml ;alter session force parallel dml parallel &PARALLELS;alter session force parallel query parallel &PARALLELS;alter table &INT_TAB enable row movement; --臨時表開啟行遷移
- 檢查原表是否支援線上重定義,比較快,僅用了1秒不到。
SQL> begin 2 dbms_redefinition.can_redef_table(uname => '&USERNAME', 3 tname => '&SOURCE_TAB', 4 options_flag => DBMS_REDEFINITION.CONS_USE_PK); 5 end; 6 / PL/SQL procedure successfully completed Executed in 0.027 seconds
- 對映欄位型別,啟動重定義程式,用了近10分鐘,稍微有點慢。從這裡開始到結束, 如果中途有錯誤,想要重來,需要調abort_redef_table過程取消任務。
SQL> set timing on; SQL> begin 2 DBMS_REDEFINITION.START_REDEF_TABLE(uname => '&USERNAME', 3 orig_table => '&SOURCE_TAB', 4 int_table => '&INT_TAB', 5 col_mapping => 'to_number(owner_party_role_id) owner_party_role_id, 7 to_number(offering_inst_id) offering_inst_id, 8 to_number(subs_id) subs_id, 9 to_number(group_id) group_id, 10 to_number(apply_obj_id) apply_obj_id', --這裡只列舉了需要變更的欄位型別 11 options_flag => DBMS_REDEFINITION.CONS_USE_PK); 12 end; 13 / PL/SQL procedure successfully completed Executed in 576.565 seconds
- 複製依賴物件,這裡只複製了主鍵約束,耗時54分鐘,如果全部複製,我在測試跑了3個小時沒有結果,只接Kill了。
SQL> DECLARE 2 num_errors PLS_INTEGER; 3 BEGIN 4 DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(uname => '&USERNAME', 5 orig_table => '&SOURCE_TAB', 6 int_table => '&INT_TAB', 7 copy_indexes => 0, 8 copy_triggers => FALSE, 9 copy_constraints => TRUE, 10 copy_privileges => FALSE, 11 ignore_errors => FALSE, 12 num_errors => num_errors, 13 copy_statistics => FALSE); 14 END; 15 / PL/SQL procedure successfully completed Executed in 3230.441 seconds
- 非同步同步資料,耗時28秒,比較快。
SQL> begin 2 dbms_redefinition.sync_interim_table(uname => '&USERNAME', 3 orig_table => '&SOURCE_TAB', 4 int_table => '&INT_TAB'); 5 end; 6 / PL/SQL procedure successfully completed Executed in 27.908 seconds
- 完成線上重定義,結束任務,耗時73秒,也是比較快。
SQL> begin 2 dbms_redefinition.finish_redef_table(uname => '&USERNAME', 3 orig_table => '&SOURCE_TAB', 4 int_table => '&INT_TAB'); 5 end; 6 / PL/SQL procedure successfully completed Executed in 72.302 seconds
- 建立索引,這個分割槽表上的索引不多,就3個普通索引,開53個並行,平均每個耗時4分鐘左右,累計13分鐘。
SQL> CREATE INDEX "CUSTINFO"."INX_OM_OFFERING_INST_TEST_CUSTID" ON "CUSTINFO"."OM_OFFERING_INST_TEST" ("CUST_ID") online parallel 35; Index created Executed in 257.138 seconds SQL> CREATE INDEX "CUSTINFO"."INX_OM_OFFERING_INST_TEST_GROUPID" ON "CUSTINFO"."OM_OFFERING_INST_TEST" ("GROUP_ID") online parallel 35; Index created Executed in 244.853 seconds SQL> CREATE INDEX "CUSTINFO"."INX_OM_OFFERING_INST_TEST_SUBSID" ON"CUSTINFO"."OM_OFFERING_INST_TEST" ("SUBS_ID") online parallel 35; Index created Executed in 261.665 seconds
- 收集統計資訊,同樣也是開35個並行,耗時4分鐘左右。CASCADE => true表示收集表、列、索引等。
SQL> exec dbms_stats.gather_table_stats(ownname => 'CUSTINFO',tabname => 'OM_OFFERING_INST_TEST',CASCADE => true,degree => 35); PL/SQL procedure successfully completed. Elapsed: 00:04:18.35
- 取消表、索引上的並行度,檢查欄位是否修改成功,刪除臨時表,至此整個修改過程結束,這裡耗時約10分鐘左右。
--取消表上的並行alter table &SOURCE_TAB noparallel;--取消索引上的並行alter index INX_OM_OFFERING_INST_TEST_CUSTID noparallel;alter index INX_OM_OFFERING_INST_TEST_GROUPID noparallel;alter index INX_OM_OFFERING_INST_TEST_SUBSID noparallel; --刪除臨時表drop table &INT_TAB;
總結
- 總計執行耗時:95分鐘,不到2小時,效率上暫時能接受,如果有更好的辦法,求拍磚,謝謝。
- 檢查表定義 1秒
- 啟動重定義程式 10分鐘
- 複製依賴 54分鐘
- 非同步同步資料 28秒
- 執行結束任務 73秒
- 建立索引 13分鐘
- 收集統計資訊 4分鐘
- 取消並行檢查刪除臨時表 10分鐘
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31556440/viewspace-2681929/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 14億條記錄,12c 做不到2小時內變更表結構欄位型別?型別
- 更新一張與另一張表關聯的連線欄位記錄
- Sqlserver修改線上表的表欄位型別SQLServer型別
- MySQL欄位型別小記MySql型別
- Oracle查詢資料表結構(欄位,型別,大小,備註)Oracle型別
- 改變表中非空欄位的型別型別
- oracle的欄位型別Oracle型別
- MySQL千萬級大表線上變更表結構MySql
- 修改表的欄位型別型別
- 查詢mysql某張表中的所有資料(欄位)型別MySql型別
- [提問交流]建立模型,新增屬性,欄位型別如何設定2位小數的欄位型別模型型別
- 保留兩位小數:資料庫欄位型別NUMBER,Java欄位型別Double型別資料庫型別Java
- 怎樣Oracle把多條記錄的相同欄位拼成一個字串Oracle字串
- 幾千萬記錄,資料庫表結構如何平滑變更?資料庫
- oracle 修改欄位型別的方法Oracle型別
- MySQL欄位新增註釋,但不改變欄位的型別MySql型別
- sqlserver查詢一個庫所有表的欄位名及欄位型別SQLServer型別
- (轉) JAVA,Mybatis,Oracle變數型別與欄位型別不一致,分割槽表全掃的優化JavaMyBatisOracle變數型別優化
- Oracle-不刪表資料,修改欄位型別Oracle型別
- Oracle中如何更新一張大表記錄Oracle
- oracle如何變更varchar2型別的列為clobOracle型別
- awk 中的欄位、記錄和變數變數
- varchar or blob:欄位型別的儲存和溢位條件型別
- oracle檢視該使用者的所有表名字、表註釋、欄位名、欄位註釋、是否為空、欄位型別Oracle型別
- MSSql得到表的結構和欄位SQL
- mysql表操作(alter)/mysql欄位型別MySql型別
- sql小筆記(增刪改查——新增列、修改表名、列的欄位型別等)SQL筆記型別
- oracle 線上重新定義,普通表改變分割槽表,分割槽表可以更改型別、分割槽欄位等Oracle型別
- oracle建立一張與其他表相同表結構的空表Oracle
- 含LONG型別欄位的表無法MOVE型別
- Oracle 修改欄位型別和長度Oracle型別
- 獲取表的結構、欄位描述等
- WHRER條件裡的資料型別必須和欄位資料型別一致資料型別
- oracle刪除表欄位和oracle表增加欄位Oracle
- JSON欄位型別在ORM中的使用JSON型別ORM
- 【轉】修改表的欄位資料型別的方法資料型別
- oracle中判斷欄位是否存在和新增表結構Oracle
- MSSQL資料庫的欄位型別總結SQL資料庫型別