【Oracle】DBMS_REDEFINITION完全ガイド|オンラインテーブル再定義でゼロダウンタイムのテーブル再構成まで解説

大規模テーブルの圧縮変更・表領域移動・パーティション再編成は、通常の 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 の処理フローは以下のとおりです:

  1. 暫定テーブル(interim table)を作成:再定義後の構造で空のテーブルを作成する
  2. START_REDEF_TABLE:マテリアライズド・ビューのログを使って元テーブルと暫定テーブルを同期開始する
  3. データコピー:元テーブルのデータを暫定テーブルにバルクコピーする(オンラインで進行)
  4. 差分の同期:コピー中に発生した DML の差分を同期する(SYNC_INTERIM_TABLE)
  5. 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完全ガイドも参照してください。