はじめに
Oracle 12.1では、非パーティション表をパーティション表に変更する場合に以下の方法がありました。
- CTAS(CREATE TABLE AS SELECT)で新しいパーティション表を作成し、テーブル名をリネームする
- EXCHANGE PARTITIONを使用する
- DBMS_REDEFINITIONを使用する
いずれの方法も操作が複雑であり、操作ミスや作業漏れが発生しやすい方法です。
Oracle 12.2ではALTER TABLE文にて1コマンドで簡単に非パーティション表をパーティション表に変更することができるようになっています。しかもオンラインでも実行できるため、変換中でもDML操作が可能です。
ただし、表領域を変えたいなど他にも要件がある場合は、別の方法を利用するか、組み合わせることになります。
パーティション表に変換した場合、元々作成していたインデックスは以下のように変換されます。
テーブルばかりに気をとられて、インデックスはグローバル非パーティションインデックスのままでしたなんてことがないように注意が必要です(意図しているなら別ですが)
- 非同一キーインデックスは、グローバル非パーティションインデックスになります。
- 同一キーインデックスは、ローカルパーティションインデックスに変換されます。
- ビットマップインデックスは、ローカルパーティションインデックスになります。
変換例
非パーティション表をパーティション表に変換する例を以降に示します。
まずテストの事前準備として、テスト用のテーブルとインデックスを以下のように作成しました。
なお、例のためテーブル、インデックス、パーティションは適当です(良い構成ではない)。
drop table p_test purge;
create table p_test (
id number,
pref_id number,
pref varchar(10),
customer_id number,
created_at timestamp,
constraint pk_id primary key(id)
);
insert into p_test values(1, 1, 'HOKKAIDO', 100, '2019-12-07');
insert into p_test values(2, 20, 'NAGANO', 200, '2019-12-07');
insert into p_test values(3, 20, 'NAGANO', 201, '2019-11-07');
insert into p_test values(4, 40, 'FUKUOKA', 300, '2019-12-07');
commit;
create index idx_pref_id on p_test(pref_id);
create index idx_created_dt on p_test(created_at);
create index idx_pref on p_test(pref);
レンジパーティションへ変換
online句をつけることで、変換中もDMLを実行できます。
update indexesはなくても変換できますが、インデックスの種類を指定したい場合は記載します。
alter table p_test modify
partition by range(created_at) (
partition r_part_2019_11 values less than (to_date('2019-12-01', 'yyyy-mm-dd')),
partition r_part_2019_12 values less than (to_date('2020-01-01', 'yyyy-mm-dd'))
) online
update indexes
(
pk_id global,
idx_pref_id local
);
インデックスを確認すると以下のようになります。
idx_pref_idはlocalを指定したのでローカルパーティションインデックス、created_atはパーティションキーなのでローカルパーティションインデックスになっています。
SQL> select index_name, table_name, partitioning_type, subpartitioning_type, partition_count, locality from user_part_indexes where table_name = 'P_TEST';
INDEX_NAME TABLE_NAME PARTITIONING_TYPE SUBPARTITIONING_TYPE PARTITION_COUNT LOCALI
-------------------- -------------------- -------------------- -------------------- --------------- ------
IDX_PREF_ID P_TEST RANGE NONE 2 LOCAL
IDX_CREATED_DT P_TEST RANGE NONE 2 LOCAL
なお、「pk_id local」と指定するとエラーになります。
ORA-14039: パーティション化列はUNIQUE索引のキー列のサブセットを構成する必要があります
これは一意性を担保できないからで、「constraint pk_id primary key(id, created_at)」のように主キーにパーティションキーを含むようにすればエラーとなりません。
リストパーティションへ変換
alter table p_test modify
partition by list(pref) (
partition l_part_hokkaido values ('HOKKAIDO'),
partition l_part_nagano values ('NAGANO'),
partition l_part_fukuoka values ('FUKUOKA')
) online
update indexes
(
pk_id global,
idx_pref_id local
);
インデックスを確認すると以下のようになります。
idx_pref_idはlocalを指定したのでローカルパーティションインデックス、prefはパーティションキーなのでローカルパーティションインデックスになっています。
SQL> select index_name, table_name, partitioning_type, subpartitioning_type, partition_count, locality from user_part_indexes where table_name = 'P_TEST';
INDEX_NAME TABLE_NAME PARTITIONING_TYPE SUBPARTITIONING_TYPE PARTITION_COUNT LOCALI
-------------------- -------------------- -------------------- -------------------- --------------- ------
IDX_PREF_ID P_TEST LIST NONE 3 LOCAL
IDX_PREF P_TEST LIST NONE 3 LOCAL
ハッシュパーティションへ変換
alter table p_test modify
partition by hash(id) (
partition h_part1,
partition h_part2,
partition h_part3,
partition h_part4
) online;
インデックスを確認すると以下のようになります。
idx_idはパーティションキーなのでローカルパーティションインデックスになっています。
SQL> select index_name, table_name, partitioning_type, subpartitioning_type, partition_count, locality from user_part_indexes where table_name = 'P_TEST';
INDEX_NAME TABLE_NAME PARTITIONING_TYPE SUBPARTITIONING_TYPE PARTITION_COUNT LOCALI
-------------------- -------------------- -------------------- -------------------- --------------- ------
PK_ID P_TEST HASH NONE 4 LOCAL
インターバルパーティションへ変換
インターバルパーティションは事前に指定したインターバルに応じて、レコード挿入時に自動でパーティションを作成します。
alter table p_test modify
partition by range(created_at)
interval(numtoyminterval(1, 'MONTH'))
(
partition p1 values less than (to_date('2019-10-1', 'yyyy-mm-dd'))
) online
update indexes
(
pk_id global,
idx_pref_id local
);
インデックスを確認すると以下のようになります。
レンジパーティションと同様に、idx_pref_idとcreated_atはローカルパーティションインデックスになっています。
SQL> select index_name, table_name, partitioning_type, subpartitioning_type, partition_count, locality from user_part_indexes where table_name = 'P_TEST';
INDEX_NAME TABLE_NAME PARTITIONING_TYPE SUBPARTITIONING_TYPE PARTITION_COUNT LOCALI
-------------------- -------------------- -------------------- -------------------- --------------- ------
IDX_PREF_ID P_TEST RANGE NONE 2 LOCAL
IDX_CREATED_DT P_TEST RANGE NONE 2 LOCAL
コンポジットパーティション(レンジ+ハッシュ)へ変換
alter table p_test modify
partition by range(created_at) subpartition by hash(customer_id) (
partition r_part_2019_11 values less than (to_date('2019-12-01', 'yyyy-mm-dd')) (
subpartition h_part1_2019_11,
subpartition h_part2_2019_11,
subpartition h_part3_2019_11,
subpartition h_part4_2019_11
),
partition r_part_2019_12 values less than (to_date('2020-01-01', 'yyyy-mm-dd')) (
subpartition h_part1_2019_12,
subpartition h_part2_2019_12,
subpartition h_part3_2019_12,
subpartition h_part4_2019_12
)
) online
update indexes
(
pk_id global,
idx_pref_id local
);