D.4 オンライン再定義を使用したJSONデータ型への移行

PL/SQLプロシージャDBMS_REDEFINITION.can_redef_tableによって許可された場合は、オンライン再定義を使用して、表データの可用性に大きな影響を与えることなく、テキストJSON列をJSON型列に移行できます。移行プロセスの大部分で、問合せとDMLの両方に引き続きアクセスできます。

この方法では、元の表のデータを新しい仮表にコピーする一方で、元の表が通常のワークロードを引き続き処理します。

このように移行すると、通常のワークロードに使用可能な表が排他モードでロックされるのはわずかな時間の間だけで、これは表のサイズや再定義の複雑さには関係ありません。オンライン再定義には、再定義の対象となる表が使用している領域とほぼ同じ空き領域が必要です。

オンライン再定義を実行するには、パッケージDBMS_REDEFINITIONに対する実行権限が必要であり、マテリアライズド・ビューCREATE MVIEWを作成する権限が必要です。

ここでは、table_ownerは表を所有するデータベース・スキーマです。

  1. DBMS_REDEFINITION.can_redef_tableを起動して、オンライン再定義によって表を変更できるかどうかをチェックします。エラーが発生しなければ、ステップ2に進みます。

    EXEC DBMS_REDEFINITION.can_redef_table('table_owner', 'j_purchaseorder');
  2. 例4-1に似たコードを使用して、つまり元の表j_purchaseorderと同じ形状の、テキストJSON列ではなくJSON型列が含まれる、仮表j_purchaseorder_newを作成します。

    
    CREATE TABLE j_purchaseorder_new (id VARCHAR2(32),
                                      date_loaded TIMESTAMP(6) WITH TIME ZONE,
                                      data JSON);
  3. 元の表(j_purchaseorder)に仮想列がある場合は、仮表に同一の列を定義します。たとえば、このコードでは、最上位フィールドUserおよびCostCenterに基づいて、それぞれ仮想列vc_userおよびvc_costcenterを定義します。

    ALTER TABLE j_purchaseorder_new ADD (vc_user GENERATED ALWAYS AS
      (json_value(data, '$.User' RETURNING VARCHAR2(20))));
    ALTER TABLE j_purchaseorder_new ADD (vc_costcenter GENERATED ALWAYS AS
      (json_value(data, '$.CostCenter' RETURNING VARCHAR2(6))));
  4. プロシージャDBMS_REDEFINITION.start_redef_tableを使用して、JSONデータ型コンストラクタをテキストJSON列に適用します。

    BEGIN
      DBMS_REDEFINITION.start_redef_table('table_owner',
                                          'j_purchaseorder',
                                          'j_purchaseorder_new',
                                          'ID ID, DATE_LOADED DATE_LOADED, JSON(DATA) PO_DOCUMENT',
                                          REFRESH_DEP_MVIEWS => 'Y',
                                          ENABLE_ROLLBACK => FALSE);
    END;
    /
  5. 元の表に制約、索引、仮想プライベート・データベース(VPD)ポリシーなどの依存物が含まれている場合は、プロシージャDBMS_REDEFINITION.copy_table_dependentsをコールして、それらを仮表にコピーします。

    DECLARE
    n_errors INTEGER;
    BEGIN
      DBMS_REDEFINITION.copy_table_dependents('table_owner',
                                              'j_purchaseorder',
                                              'j_purchaseorder_new',
                                              NUM_ERRORS => n_errors,
                                              IGNORE_ERRORS => FALSE);
      DBMS_OUTPUT.put_line(n_errors);
    END;
    /
  6. (オプション)前のステップで元の表に対して大量のDML操作を発行した場合は、プロシージャDBMS_REDEFINITION.sync_interim_tableを使用してデータを仮表に同期させ、次のステップでの停止時間を最小限に抑えることを検討します。

    DBMS_REDEFINITION.sync_interim_table ('table_owner',
                                          'j_purchaseorder',
                                          'j_purchaseorder_new',
                                          PART_NAME => NULL,
                                          CONTINUE_AFTER_ERRORS => FALSE);
  7. 仮表が想定どおりに動作することを確認します。これが事実であると自分を納得させるために、必要と感じることは何でも実行します。次のステップ8 (元に戻すことはできません)では、2つの表の名前を入れ替えるので、現在の仮表は元の表名で"稼働"します。

    仮表が想定どおりに動作していないことがチェックで判明した場合は、プロシージャDBMS_REDEFINITION.abort_redef_tableを使用して、これまでに行われた変更を元に戻すことができます。再定義中に再発した可能性がある問題を一掃し、これまでに作成された一時オブジェクト(マテリアライズド・ビュー・ログなど)を削除します。

    abort_redef_tableを使用すると、start_redef_tableの起動後でDBMS_REDEFINITION.finish_redef_tableの起動前であればいつでも、再定義プロセスを終了できます。

    DBMS_REDEFINITION.abort_redef_table ('table_owner',
                                         'j_purchaseorder',
                                         'j_purchaseorder_new',
                                         PART_NAME => NULL);
  8. オンライン再定義を終了するには、プロシージャDBMS_REDEFINITION.finish_redef_tableを使用します。このアクションは元に戻すことができません。これにより、元の表と仮表の名前が入れ替わり、両方とも短い期間ロックされます。操作後、元の名前の表には再定義されたデータが格納され、仮名の表には元の(古い)データが格納されます。

    BEGIN
      DBMS_REDEFINITION.finish_redef_table('table_owner',
                                           'j_purchaseorder',
                                           'j_purchaseorder_new',
                                           DML_LOCK_TIMEOUT => 0);
    END;
    /
  9. (オプション)元の(古い)データが現在格納されている仮表が不要になった場合は、削除します。必ず仮表を削除し、元の名前の表は削除しないでください。PURGEの指定はオプションです。PURGEを使用すると、削除した表はリカバリできません。

    DROP TABLE 'table_owner', 'j_purchaseorder_new' CASCADE CONSTRAINTS PURGE;

関連項目: