タイトルが長いですが、表のオンライン再定義はDMLによるデータ更新を
制限せずに、表定義(論理構造や物理構造)を変更する機能です。
Oracle Database管理者ガイド 12cリリース1 (12.1)
20.7 表のオンライン再定義
https://docs.oracle.com/cd/E57425_01/121/ADMIN/tables.htm#GUID-92361F74-4796-407D-A3B9-569C6E544E34
今回は下記のパーティション構造とグローバル索引⇒ローカル索引への
変更を検証してみますやで彡(゚)(゚) バージョンは訳あって 12cR1(12.1.0.2) です。
RANGE PARTITION&グローバル索引の表 ⇒ HASH PARTITION&ローカル索引の表
1. テスト表の作成とテストデータのINSERT
テスト表(対象表/仮表)を作成して、対象表にテストデータをINSERTします。
1000件を初期セットした後、1秒に1件ずつINSERTしていくやで彡(゚)(゚)
#最終的には対象表に1180件をINSERTしていきます。
-- Old Table
CREATE TABLE TBL_A (
C1 NUMBER
, C2 NUMBER
)
PARTITION BY RANGE (C1) (
PARTITION P1 VALUES LESS THAN (100),
PARTITION P2 VALUES LESS THAN (200),
PARTITION PMAX VALUES LESS THAN (MAXVALUE)
);
ALTER TABLE TBL_A ADD CONSTRAINT TBL_A_PK PRIMARY KEY (C1) USING INDEX GLOBAL;
CREATE INDEX TBL_A_I1 on TBL_A (C2) GLOBAL;
-- New Table
CREATE TABLE NEW_TBL_A (
C1 NUMBER
, C2 NUMBER
)
PARTITION BY HASH (C1) (
PARTITION P1
, PARTITION P2
, PARTITION P3
, PARTITION P4
);
--※仮表の索引と主キーは後で作成
BEGIN
-- Test Data
INSERT INTO TBL_A SELECT LEVEL, LEVEL FROM DUAL CONNECT BY LEVEL <= 1000;
COMMIT;
FOR i IN 1001..1180
LOOP
INSERT INTO TBL_A VALUES(i, i);
COMMIT;
DBMS_LOCK.SLEEP(1);
END LOOP;
END;
/
Table created.
Table altered.
Index created.
Table created.
:
(PL/SQLはしばらく動作する)
(※ここから別セッション)この時点でのディクショナリ情報は下記の通りです。
10:26:24 SQL> -- Part_tables
10:26:24 SQL> SELECT TABLE_NAME, PARTITIONING_TYPE, STATUS
10:26:24 2 FROM USER_PART_TABLES WHERE TABLE_NAME LIKE '%TBL_A%';
TABLE_NAME PARTITION STATUS
--------------- --------- --------
NEW_TBL_A HASH VALID ★仮表はHASHパーティション
TBL_A RANGE VALID ★対象表はRANGEパーティション
10:26:24 SQL> -- Indexes
10:26:24 SQL> SELECT TABLE_OWNER, TABLE_NAME, INDEX_NAME, UNIQUENESS, STATUS, GLOBAL_STATS
10:26:24 2 FROM USER_INDEXES WHERE TABLE_NAME LIKE '%TBL_A%';
TABLE_OWNER TABLE_NAME INDEX_NAME UNIQUENES STATUS GLO
--------------- --------------- --------------- --------- -------- ---
AYSHIBAT TBL_A TBL_A_PK UNIQUE VALID YES ★対象表のグローバル索引(主キー)
AYSHIBAT TBL_A TBL_A_I1 NONUNIQUE VALID YES ★対象表のグローバル索引
10:26:24 SQL> -- Constraints
10:26:24 SQL> SELECT OWNER, TABLE_NAME, CONSTRAINT_NAME, CONSTRAINT_TYPE
10:26:24 2 FROM USER_CONSTRAINTS WHERE TABLE_NAME LIKE '%TBL_A%';
OWNER TABLE_NAME CONSTRAINT_NAME C
--------------- --------------- --------------- -
AYSHIBAT TBL_A TBL_A_PK P
10:26:26 SQL>
10:26:26 SQL> -- Data Check
10:26:26 SQL> SELECT COUNT(*) FROM TBL_A;
COUNT(*)
----------
1021
10:26:27 SQL> SELECT COUNT(*) FROM NEW_TBL_A;
COUNT(*)
----------
0
2. DBMS_REDEFINITION.CAN_REDEF_TABLEによる事前チェック
DBMS_REDEFINITION.CAN_REDEF_TABLEプロシージャで表がオンライン再定義可能かチェックします。
-- Check redefinition possibility.
EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE(USER, 'TBL_A', DBMS_REDEFINITION.CONS_USE_PK);
PL/SQL procedure successfully completed.
オンライン表再定義が不可能な場合は、下記のようなエラーが出力されます彡(゚)(゚)
EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE(USER, 'TBL_B', DBMS_REDEFINITION.CONS_USE_PK);
BEGIN DBMS_REDEFINITION.CAN_REDEF_TABLE(USER, 'TBL_B', DBMS_REDEFINITION.CONS_USE_PK); END;
*
ERROR at line 1:
ORA-12088: cannot online redefine table "AYSHIBAT"."TBL_B" with unsupported datatype
ORA-06512: at "SYS.DBMS_REDEFINITION", line 173
ORA-06512: at "SYS.DBMS_REDEFINITION", line 3664
ORA-06512: at line 1
3. DBMS_REDEFINITION.START_REDEF_TABLEプロシージャでオンライン再定義を開始
DBMS_REDEFINITION.START_REDEF_TABLEプロシージャでオンライン再定義を開始します。
対象表⇒仮表への初期データ移行が、この時点でのデータ断面で実行されます。
EXEC DBMS_REDEFINITION.START_REDEF_TABLE(USER, 'TBL_A', 'NEW_TBL_A');
SELECT COUNT(*) FROM TBL_A;
SELECT COUNT(*) FROM NEW_TBL_A;
10:26:27 SQL> EXEC DBMS_REDEFINITION.START_REDEF_TABLE(USER, 'TBL_A', 'NEW_TBL_A');
PL/SQL procedure successfully completed.
10:26:29 SQL> SELECT COUNT(*) FROM TBL_A;
COUNT(*)
----------
1023
10:26:29 SQL> SELECT COUNT(*) FROM NEW_TBL_A;
COUNT(*)
----------
1022 ★仮表にデータが挿入、件数差異は裏で対象表のデータINSERTを実行しているため。
4. 仮表にローカル索引(主キー、非ユニーク索引)を作成
仮表に主キーと非ユニークのローカル索引を作成します。
CREATE TABLE時に作らないのは、上記 3. の初期データ移行の
負荷(処理量)を減らすため。索引無い方がINSERTは速いんで彡(゚)(゚)
ALTER TABLE NEW_TBL_A ADD CONSTRAINT NEW_TBL_A_PK PRIMARY KEY (C1) USING INDEX LOCAL;
CREATE INDEX NEW_TBL_A_I1 on NEW_TBL_A (C2) LOCAL;
Table altered.
Index created.
この時点でのディクショナリ情報は下記の通りです。
10:26:29 SQL> -- Part_tables
10:26:29 SQL> SELECT TABLE_NAME, PARTITIONING_TYPE, STATUS
10:26:29 2 FROM USER_PART_TABLES WHERE TABLE_NAME LIKE '%TBL_A%';
TABLE_NAME PARTITION STATUS
--------------- --------- --------
NEW_TBL_A HASH VALID
TBL_A RANGE VALID
10:26:29 SQL> -- Indexes
10:26:29 SQL> SELECT TABLE_OWNER, TABLE_NAME, INDEX_NAME, UNIQUENESS, STATUS, GLOBAL_STATS
10:26:29 2 FROM USER_INDEXES WHERE TABLE_NAME LIKE '%TBL_A%';
TABLE_OWNER TABLE_NAME INDEX_NAME UNIQUENES STATUS GLO
--------------- --------------- --------------- --------- -------- ---
AYSHIBAT NEW_TBL_A NEW_TBL_A_I1 NONUNIQUE N/A NO ★仮表のローカル索引
AYSHIBAT NEW_TBL_A NEW_TBL_A_PK UNIQUE N/A NO ★仮表のローカル索引
AYSHIBAT TBL_A TBL_A_I1 NONUNIQUE VALID YES
AYSHIBAT TBL_A TBL_A_PK UNIQUE VALID YES
AYSHIBAT MLOG$_TBL_A I_MLOG$_TBL_A NONUNIQUE VALID YES
10:26:29 SQL> -- Constraints
10:26:29 SQL> SELECT OWNER, TABLE_NAME, CONSTRAINT_NAME, CONSTRAINT_TYPE
10:26:29 2 FROM USER_CONSTRAINTS WHERE TABLE_NAME LIKE '%TBL_A%';
OWNER TABLE_NAME CONSTRAINT_NAME C
--------------- --------------- --------------- -
AYSHIBAT NEW_TBL_A NEW_TBL_A_PK P ★仮表の主キー制約
AYSHIBAT TBL_A TBL_A_PK P
5. DBMS_REDEFINITION.REGISTER_DEPENDENT_OBJECTプロシージャによる索引&主キー制約の関連付け
DBMS_REDEFINITION.REGISTER_DEPENDENT_OBJECTプロシージャで
対象表と仮表の索引と主キーを関連付けます。
BEGIN
DBMS_REDEFINITION.REGISTER_DEPENDENT_OBJECT(
USER -- uname
, 'TBL_A' -- orig_table
, 'NEW_TBL_A' -- int_table
, DBMS_REDEFINITION.CONS_INDEX -- dep_type
, USER -- dep_owner
, 'TBL_A_PK' -- dep_orig_name
, 'NEW_TBL_A_PK' -- dep_int_name
);
END;
/
BEGIN
DBMS_REDEFINITION.REGISTER_DEPENDENT_OBJECT(
USER -- uname
, 'TBL_A' -- orig_table
, 'NEW_TBL_A' -- int_table
, DBMS_REDEFINITION.CONS_CONSTRAINT -- dep_type
, USER -- dep_owner
, 'TBL_A_PK' -- dep_orig_name
, 'NEW_TBL_A_PK' -- dep_int_name
);
END;
/
BEGIN
DBMS_REDEFINITION.REGISTER_DEPENDENT_OBJECT(
USER -- uname
, 'TBL_A' -- orig_table
, 'NEW_TBL_A' -- int_table
, DBMS_REDEFINITION.CONS_INDEX -- dep_type
, USER -- dep_owner
, 'TBL_A_I1' -- dep_orig_name
, 'NEW_TBL_A_I1' -- dep_int_name
);
END;
/
PL/SQL procedure successfully completed.
PL/SQL procedure successfully completed.
PL/SQL procedure successfully completed.
DBMS_REDEFINITION.COPY_TABLE_DEPENDENTSプロシージャで
対象表の関連オブジェクトも仮表にコピーします。
ただし今回のように、REGISTER_DEPENDENT_OBJECT で明示的に
関連付けを行うケースだと、この手順は不要かも……彡(-)(-)
SET SERVEROUTPU ON SIZE 1000000;
DECLARE
error_count pls_integer := 0;
BEGIN
DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(
USER -- uname
, 'TBL_A' -- orig_table
, 'NEW_TBL_A' -- int_table
, 0 -- copy_indexes 0...NO_COPY
, FALSE -- copy_triggers
, FALSE -- copy_constraints
, FALSE -- copy_privileges
, FALSE -- ignore_errors
, error_count -- num_errors
, FALSE -- copy_statistics
, FALSE -- copy_mlogs
);
DBMS_OUTPUT.PUT_LINE('errors := ' || TO_CHAR(error_count));
END;
/
errors := 0
PL/SQL procedure successfully completed.
6. DBMS_REDEFINITION.FINISH_REDEF_TABLEプロシージャでオンライン再定義を完了する。
DBMS_REDEFINITION.FINISH_REDEF_TABLEプロシージャでオンライン再定義を完了します。
EXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE(USER, 'TBL_A', 'NEW_TBL_A');
PL/SQL procedure successfully completed.
完了後のディクショナリとデータ件数は以下の通りです。
10:26:34 SQL> -- Part_tables
10:26:34 SQL> SELECT TABLE_NAME, PARTITIONING_TYPE, STATUS
10:26:34 2 FROM USER_PART_TABLES WHERE TABLE_NAME LIKE '%TBL_A%';
TABLE_NAME PARTITION STATUS
--------------- --------- --------
NEW_TBL_A RANGE VALID
TBL_A HASH VALID ★HASHパーティションに変わっている。
10:26:34 SQL> -- Indexes
10:26:34 SQL> SELECT TABLE_OWNER, TABLE_NAME, INDEX_NAME, UNIQUENESS, STATUS, GLOBAL_STATS
10:26:34 2 FROM USER_INDEXES WHERE TABLE_NAME LIKE '%TBL_A%';
TABLE_OWNER TABLE_NAME INDEX_NAME UNIQUENES STATUS GLO
--------------- --------------- --------------- --------- -------- ---
AYSHIBAT NEW_TBL_A NEW_TBL_A_PK UNIQUE VALID YES
AYSHIBAT NEW_TBL_A NEW_TBL_A_I1 NONUNIQUE VALID YES
AYSHIBAT TBL_A TBL_A_PK UNIQUE N/A NO ★ローカル索引に変わっている。
AYSHIBAT TBL_A TBL_A_I1 NONUNIQUE N/A NO ★ローカル索引に変わっている。
10:26:35 SQL> -- Constraints
10:26:35 SQL> SELECT OWNER, TABLE_NAME, CONSTRAINT_NAME, CONSTRAINT_TYPE
10:26:35 2 FROM USER_CONSTRAINTS WHERE TABLE_NAME LIKE '%TBL_A%';
OWNER TABLE_NAME CONSTRAINT_NAME C
--------------- --------------- --------------- -
AYSHIBAT TBL_A TBL_A_PK P
AYSHIBAT NEW_TBL_A NEW_TBL_A_PK P
10:26:38 SQL>
10:26:38 SQL> -- Redifiniitoned Table Data Check
10:26:38 SQL> SELECT COUNT(*) FROM NEW_TBL_A;
COUNT(*)
----------
1028
10:26:38 SQL> SELECT COUNT(*) FROM TBL_A;
COUNT(*)
----------
1032 ★件数が増えていってるのは裏でINSERTしているため
10:26:38 SQL> SELECT COUNT(*) FROM TBL_A;
COUNT(*)
----------
1038 ★件数が増えていってるのは裏でINSERTしているため
:
:
10:32:43 SQL> SELECT COUNT(*) FROM TBL_A;
COUNT(*)
----------
1180 ★最終的なデータ件数
10:32:36 SQL> SELECT COUNT(*) FROM TBL_A PARTITION (P1);
COUNT(*)
----------
285 ★HASHパーティションP1の件数
10:32:36 SQL> SELECT COUNT(*) FROM TBL_A PARTITION (P2);
COUNT(*)
----------
282 ★HASHパーティションP2の件数
10:32:36 SQL> SELECT COUNT(*) FROM TBL_A PARTITION (P3);
COUNT(*)
----------
305 ★HASHパーティションP3の件数
10:32:36 SQL> SELECT COUNT(*) FROM TBL_A PARTITION (P4);
COUNT(*)
----------
308 ★HASHパーティションP4の件数
10:32:36 SQL>
7. まとめ
HASHパーティション化とローカル索引への表定義変更を、
データの更新を止めずに実行できたで!彡(^)(^)
12cR1からのDBMS_REDEFINITIONには、上記で説明した一連のプロシージャを
一まとめにしたREDEF_TABLEプロシージャが提供されています。こちらは別の機会に彡(゚)(゚)
Oracle Database PL/SQLパッケージおよびタイプ・リファレンス
12c リリース1 (12.1)
122 DBMS_REDEFINITION
REDEF_TABLEプロシージャ
https://docs.oracle.com/cd/E57425_01/121/ARPLS/d_redefi.htm#CHDDDDFG
8. 参考情報
マニュアルやサポートドキュメントも読んでおくんやで彡(゚)(゚)
Oracle Database管理者ガイド 12cリリース1 (12.1)
20.7 表のオンライン再定義
https://docs.oracle.com/cd/E57425_01/121/ADMIN/tables.htm#GUID-92361F74-4796-407D-A3B9-569C6E544E34Oracle Database PL/SQLパッケージおよびタイプ・リファレンス
12c リリース1 (12.1)
122 DBMS_REDEFINITION
https://docs.oracle.com/cd/E57425_01/121/ARPLS/d_redefi.htm#CBBJJAIFMOSドキュメント:How To Partition Existing Table Using DBMS_REDEFINITION (ドキュメントID 472449.1)
https://support.oracle.com/epmos/faces/DocumentDisplay?id=472449.1
※ログインが必要です。