大規模テーブルの圧縮変更・表領域移動・パーティション再編成は、通常の ALTER TABLE MOVE では長時間のロックが発生してサービスが停止します。
DBMS_REDEFINITION を使うと、テーブルをオンラインのまま(サービス稼働中に)再定義できます。再定義中の DML は暫定テーブルに差分として記録され、最終切り替え時にのみ短時間のロックが発生します。
この記事でわかること
- DBMS_REDEFINITION の仕組みと通常の ALTER TABLE MOVE との違い
- CAN_REDEF_TABLE で再定義の可否を事前確認する方法
- START_REDEF_TABLE → SYNC_INTERIM_TABLE → FINISH_REDEF_TABLE の基本手順
- COPY_TABLE_DEPENDENTS でインデックス・制約・トリガーを自動コピーする方法
- 再定義のキャンセル(ABORT_REDEF_TABLE)方法
- 圧縮変更・表領域移動・パーティション追加の具体的な使用例
オンラインテーブル再定義の仕組み
DBMS_REDEFINITION の処理フローは以下のとおりです:
- 暫定テーブル(interim table)を作成:再定義後の構造で空のテーブルを作成する
- START_REDEF_TABLE:マテリアライズド・ビューのログを使って元テーブルと暫定テーブルを同期開始する
- データコピー:元テーブルのデータを暫定テーブルにバルクコピーする(オンラインで進行)
- 差分の同期:コピー中に発生した DML の差分を同期する(SYNC_INTERIM_TABLE)
- FINISH_REDEF_TABLE:テーブル名を交換(短時間ロック)して完了する
| 項目 | ALTER TABLE MOVE | DBMS_REDEFINITION |
|---|---|---|
| サービス停止 | ロック期間中(長時間)停止 | 最終切り替え時のみ(短時間) |
| インデックス | 全インデックスが UNUSABLE になる | COPY_TABLE_DEPENDENTS で自動コピー可能 |
| 用途 | 簡単な表領域移動・緊急対応 | 本番サービスを稼働しながらの大規模再構成 |
| ROWID の変化 | ROWID が変わる | ROWID が変わる |
CAN_REDEF_TABLE で再定義の可否を確認する
再定義が可能かどうかを事前確認する
-- CAN_REDEF_TABLE でエラーが発生しなければ再定義可能
BEGIN
DBMS_REDEFINITION.CAN_REDEF_TABLE(
uname => 'HR', -- テーブル所有者スキーマ
tname => 'EMPLOYEES', -- 再定義対象テーブル名
options_flag => DBMS_REDEFINITION.CONS_USE_ROWID -- ROWID ベースの同期を使用
-- CONS_USE_PK: 主キーベース(推奨)
-- CONS_USE_ROWID: 主キーなしの場合
);
DBMS_OUTPUT.PUT_LINE('再定義可能です');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('再定義不可: ' || SQLERRM);
END;
/
-- エラーが出る主なケース:
-- ・テーブルがマテリアライズドビューのベーステーブルである
-- ・一時テーブル(Global Temporary Table)
-- ・SYS/SYSTEM スキーマのオブジェクト
オンライン再定義の基本手順
以下はテーブルを圧縮して表領域を変更する例です。
ステップ1: 暫定テーブルを作成する(再定義後の構造で)
-- 再定義後の構造・圧縮・表領域を指定して空の暫定テーブルを作成する
CREATE TABLE hr.employees_interim
COMPRESS FOR OLTP -- 圧縮を追加
TABLESPACE users_new -- 別の表領域へ移動
AS
SELECT * FROM hr.employees WHERE 1=0; -- 構造のみコピー(データなし)
-- ※ 列の変更や追加もここで行える(型変換は要注意)
ステップ2: オンライン再定義を開始する(START_REDEF_TABLE)
-- 再定義を開始する(マテリアライズドビューログが自動作成される)
BEGIN
DBMS_REDEFINITION.START_REDEF_TABLE(
uname => 'HR',
orig_table => 'EMPLOYEES', -- 元のテーブル
int_table => 'EMPLOYEES_INTERIM', -- 暫定テーブル
col_mapping => NULL, -- NULL = 同名列を自動マッピング
options_flag => DBMS_REDEFINITION.CONS_USE_PK -- 主キーで同期
);
END;
/
-- この後、バックグラウンドでデータコピーが開始される
-- 元テーブルへの DML は通常通り実行できる(ロックなし)
ステップ3: 依存オブジェクト(インデックス・制約)を暫定テーブルにコピーする
-- COPY_TABLE_DEPENDENTS でインデックス・制約・トリガー・統計を自動コピーする
DECLARE
v_errors NUMBER;
BEGIN
DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(
uname => 'HR',
orig_table => 'EMPLOYEES',
int_table => 'EMPLOYEES_INTERIM',
copy_indexes => DBMS_REDEFINITION.CONS_ORIG_PARAMS, -- インデックスをコピー
copy_triggers => TRUE, -- トリガーをコピー
copy_constraints => TRUE, -- 制約をコピー
copy_privileges => TRUE, -- 権限をコピー
ignore_errors => FALSE, -- エラーを無視しない
num_errors => v_errors
);
IF v_errors > 0 THEN
DBMS_OUTPUT.PUT_LINE('コピー中にエラーが ' || v_errors || ' 件発生しました');
END IF;
END;
/
ステップ4: 差分を同期してから完了する(FINISH_REDEF_TABLE)
-- 最終切り替えの直前に差分を事前同期する(切り替え時間を短縮)
BEGIN
DBMS_REDEFINITION.SYNC_INTERIM_TABLE(
uname => 'HR',
orig_table => 'EMPLOYEES',
int_table => 'EMPLOYEES_INTERIM'
);
END;
/
-- テーブルを切り替えて完了する(短時間のロックが発生)
BEGIN
DBMS_REDEFINITION.FINISH_REDEF_TABLE(
uname => 'HR',
orig_table => 'EMPLOYEES',
int_table => 'EMPLOYEES_INTERIM'
);
END;
/
-- FINISH 後: 元のテーブル名(EMPLOYEES)が新構造になる
-- 暫定テーブル名(EMPLOYEES_INTERIM)が旧構造になる
-- 旧構造の暫定テーブルを削除する
DROP TABLE hr.employees_interim;
再定義をキャンセルする(ABORT_REDEF_TABLE)
再定義プロセスを途中でキャンセルする
-- 何らかの問題で再定義を中断する場合(START 後、FINISH 前ならいつでも可能)
BEGIN
DBMS_REDEFINITION.ABORT_REDEF_TABLE(
uname => 'HR',
orig_table => 'EMPLOYEES',
int_table => 'EMPLOYEES_INTERIM'
);
END;
/
-- ABORT 後に暫定テーブルと MVlog を手動で削除する
DROP TABLE hr.employees_interim;
-- マテリアライズドビューログも削除される(自動または手動)
まとめ
- DBMS_REDEFINITION:サービス稼働中にテーブルの構造・圧縮・表領域を変更できる(最終切り替え時のみ短時間ロック)
- 手順:CAN_REDEF_TABLE → 暫定テーブル作成 → START → COPY_TABLE_DEPENDENTS → SYNC → FINISH
- COPY_TABLE_DEPENDENTS:インデックス・制約・権限を自動コピーするため手動作業が減る
- SYNC_INTERIM_TABLE:FINISH 前に差分を事前同期することで最終切り替え時間を短縮できる
- ABORT_REDEF_TABLE:問題発生時に元テーブルへの影響なく中断できる(安全性が高い)
- 再定義後は暫定テーブルを DROP して統計情報を再収集(GATHER_TABLE_STATS)することを推奨する
パーティション表の管理については パーティション表完全ガイドを参照してください。統計情報の収集は DBMS_STATS完全ガイドも参照してください。