Oracle Data Pumpを使用したシャード・データベースへの移行

次のトピックで説明する例およびガイドラインを使用して、Oracle Data Pumpエクスポート・ユーティリティでソース・データベースからDDL定義およびデータを抽出し、データベース・エクスポート・ファイルに対してデータ・ポンプ・インポート・ユーティリティを使用してターゲット・シャード・データベースに移入できます。

シャード・データベースのスキーマをすでに作成している場合は、データ移行のトピックにすぐに移動できます。

シャード・データベースへのスキーマの移行

非シャード・データベースからシャード・データベースへの移行には、いくつかのスキーマ変更が必要です。少なくとも、キーワードSHARDEDまたはDUPLICATEDCREATE TABLE文に追加する必要があります。場合によっては、表のパーティション化も変更するか、シェーディング・キーが追加された列を変更する必要があります。

シャード・データベース・スキーマを適切に設計するには、非シャード・データベースのスキーマおよびワークロードを分析し、次の決定を行う必要があります。

  • シャーディングする表と複製する表
  • 表ファミリ内のシャード表間の親子関係
  • シャード表で使用されるシャーディング方法
  • シャーディング・キーとして何を使用するか

これらの決定が簡単でない場合は、シャーディング・アドバイザを使用して決定できます。シャーディング・アドバイザは、Oracle Sharding環境への移行を検討している非シャードOracle Databaseに対して実行するツールです。

非シャードからシャード・データベースへのスキーマおよびデータの移行を示すために、次の図に示すサンプル・データ・モデルを使用します。

図7-1 スキーマの移行例のデータ・モデル

図7-1の説明が続きます
「図7-1 スキーマの移行例のデータ・モデル」の説明

データ・モデルはCustomers、Orders、StockItemsおよびLineItemsの4つの表で構成され、データ・モデルでは次の主キー制約が施行されます。

  • Customer.(CustNo)

  • Orders.(PONo)

  • StockItems.(StockNo)

  • LineItems.(LineNo, PONo)

このデータ・モデルでは、次の参照整合性制約が定義されます。

  • Customers.CustNo -> Orders.CustNo

  • Orders.PONo -> LineItems.PONo

  • StockItems.StockNo -> LineItems.StockNo

次のDDL文は、非シャード・スキーマ定義の例を作成します。

CREATE TABLE Customers (
 CustNo     NUMBER(3) NOT NULL,
 CusName    VARCHAR2(30) NOT NULL,
 Street     VARCHAR2(20) NOT NULL,
 City       VARCHAR2(20) NOT NULL,
 State      CHAR(2) NOT NULL,
 Zip        VARCHAR2(10) NOT NULL,
 Phone      VARCHAR2(12),
 PRIMARY KEY (CustNo)
);

CREATE TABLE Orders (
 PoNo       NUMBER(5),
 CustNo     NUMBER(3) REFERENCES Customers,
 OrderDate  DATE,
 ShipDate   DATE,
 ToStreet   VARCHAR2(20),
 ToCity     VARCHAR2(20),
 ToState    CHAR(2),
 ToZip      VARCHAR2(10),
 PRIMARY KEY (PoNo)
);

CREATE TABLE LineItems (
 LineNo      NUMBER(2),
 PoNo        NUMBER(5) REFERENCES Orders,
 StockNo     NUMBER(4) REFERENCES StockItems,
 Quantity    NUMBER(2),
 Discount    NUMBER(4,2),
 PRIMARY KEY (LineNo, PoNo)
);

CREATE TABLE StockItems (
 StockNo     NUMBER(4) PRIMARY KEY,
 Description VARCHAR2(20),
 Price       NUMBER(6,2)
);

サンプル・スキーマの移行

例として、前述のサンプル・スキーマをシャード・データベースに移行するには、次のステップを実行します。

  1. ソース・データベースのエクスポート・ディレクトリへのアクセスを取得します。

    データベース管理者は、次に示すように、データベース・ユーザーにデータベース・エクスポート・ディレクトリへのアクセスに必要な権限を付与する必要があります。

    CREATE OR REPLACE DIRECTORY expdir AS ‘/some/directory’; 
    GRANT READ, WRITE ON DIRECTORY expdir TO uname;
    GRANT EXP_FULL_DATABASE TO uname;
    

    全データベース・エクスポートでは、データベース管理者がユーザーunameEXP_FULL_DATABASEロールを付与する必要があります。表レベルのエクスポートには、追加のロールは必要ありません。

  2. ソース・データベースからDDL定義を抽出します。

    DDL文を抽出する便利な方法は、データ・ポンプ抽出ファイルを作成することです。この例に示すように、エクスポートできるのはメタデータのみ、または移行する表のセットを含むスキーマの一部のみです。

    expdp uname/pwd directory=EXPDIR dumpfile=sample_mdt.dmp logfile=sample_mdt.log INCLUDE=TABLE:\"IN \( \'CUSTOMERS\', \'ORDERS\', \'STOCKITEMS\', \'LINEITEMS\' \) \" CONTENT=METADATA_ONLY FLASHBACK_TIME=SYSTIMESTAMP

    その後、このデータベース・エクスポート・ファイルに対してデータ・ポンプ・インポート・ユーティリティを使用します。

    impdp uname/pwd@orignode directory=expdir dumpfile=sample_mdt.dmp sqlfile=sample_ddl.sql

    この例では、impdpコマンドは、実際にはダンプ・ファイルの内容をインポートしません。そのかわりに、sqlfileパラメータによって、sample_ddl.sqlという名前のスクリプトの作成がトリガーされます。このスクリプトには、エクスポート・ダンプ・ファイル内のすべてのDDLが格納されています。

    このようにエクスポートをトリミングして、時間がかかることがあるデータ・ポンプ・プロセスなしに、データベース・メタデータの一貫したイメージを効率的に取得します。それでも、テキスト形式でDDL文を取得して、シャード・データベース・スキーマ設計で要求されるようにDDLを変更する必要があります。

  3. シャード・データベースの抽出されたDDL文を変更します。

    前述のサンプル・スキーマの場合、シャード・データベースに対応するDDL文は、次のようになります。これは、システム管理シャーディングの例です。

    CREATE SHARDED TABLE Customers (
     CustNo     NUMBER(3) NOT NULL,
     CusName    VARCHAR2(30) NOT NULL,
     Street     VARCHAR2(20) NOT NULL,
     City       VARCHAR2(20) NOT NULL,
     State      CHAR(2) NOT NULL,
     Zip        VARCHAR2(10) NOT NULL,
     Phone      VARCHAR2(12),
     CONSTRAINT RootPK PRIMARY KEY (CustNo)
    )
    PARTITION BY CONSISTENT HASH (CustNo)
    PARTITIONS AUTO
    TABLESPACE SET ts1
    ;
    
    CREATE SHARDED TABLE Orders (
     PoNo       NUMBER(5) NOT NULL,
     CustNo     NUMBER(3) NOT NULL,
     OrderDate  DATE,
     ShipDate   DATE,
     ToStreet   VARCHAR2(20),
     ToCity     VARCHAR2(20),
     ToState    CHAR(2),
     ToZip      VARCHAR2(10),
     CONSTRAINT OrderPK PRIMARY KEY (CustNo, PoNo),
     CONSTRAINT CustFK Foreign Key (CustNo) REFERENCES Customers (CustNo)
    )
    PARTITION BY REFERENCE (CustFK)
    ;
    CREATE SHARDED TABLE LineItems (
     LineNo      NUMBER(2) NOT NULL,
     PoNo        NUMBER(5) NOT NULL,
     CustNo      NUMBER(3) NOT NULL,
     StockNo     NUMBER(4) NOT NULL,
     Quantity    NUMBER(2),
     Discount    NUMBER(4,2),
     CONSTRAINT LinePK PRIMARY KEY (CustNo, LineNo, PoNo),
     CONSTRAINT LineFK FOREIGN KEY (CustNo, PoNo) REFERENCES Orders (CustNo, PoNo)
    )
    PARTITION BY REFERENCE (LineFK)
    ;
    
    CREATE DUPLICATED TABLE StockItems (
     StockNo     NUMBER(4) PRIMARY KEY,
     Description VARCHAR2(20),
     Price       NUMBER(6,2)
    );
    

    シャード・データベースのスキーマに関するいくつかの観測事項を次に示します。

    • Customers - Orders: LineItemsは、Customersをルート表として、子表が参照によってパーティション化されたSHARDED表の表ファミリを形成します。StockItemsはDUPLICATED表です。

    • シャーディング・キーとしてCustNoが選択されます。したがって、この列は表ファミリのすべての表に含める必要があります。非シャード・データベースでは、LineItems表にCustNo列はありませんでしたが、表のシャード・バージョンに含まれていました。シャーディング・キー列は、シャード表のすべての主キー制約および外部キー制約にも存在する必要があります。

    • StockItemsが重複表になりました。重複表のマスター・コピーはシャード・カタログ・データベースに存在します。したがって、StockItems表を参照するLineItems表の外部キー制約は強制できず、削除されます。

  4. 変更したDDLをターゲット・データベースに対して実行します。

    シャード・カタログ・データベースに接続して実行します

    ALTER SESSION ENABLE SHARD DDL;

    次に、前述のDDLを実行してシャード表および重複表を作成します。

    データのロード前に、GDSCTL VALIDATEコマンドを使用してシャーディング構成を検証することをお薦めします。

    gdsctl> validate

    不整合やエラーが見つかった場合は、GDSCTLコマンドのSHOW DDLおよびRECOVERを使用して問題を修正する必要があります。検証に成功すると、シャード・データベースはデータ・ロードの準備が整っていることになります。

シャード・データベースへのデータの移行

非シャード・データベースからシャード・データベースに移行するには、ソース・データベースの非シャード表からターゲット・データベースのシャード表および重複表にデータを移動する必要があります。

非シャード表から重複表へのデータの移動は簡単ですが、非シャード表からシャード表へのデータの移動には特に注意が必要です。

重複表へのデータのロード

Data Pump、SQL Loader、プレーンSQLなどの既存のデータベース・ツールを使用して、重複表にデータをロードできます。データはシャード・カタログ・データベースにロードする必要があります。その後、全シャードに自動的にレプリケートされます。

重複表の内容はマテリアライズド・ビューを使用してデータベース・シャードに完全にレプリケートされるため、重複表のロードにかかる時間は同じデータを通常の表にロードするよりも長くなる場合があります。

図7-2 重複表のロード



シャード表へのデータのロード

シャード表をロードする場合、各データベース・シャードにはデータ・セットの個別のサブセットが含まれるため、ロード中に各表のデータをシャード間で分割(パーティション化)する必要があります。

データベース・シャードのすべてにサブセットのデータをロードするには、Oracle Data Pumpユーティリティを使用できます。ソース・データベースのデータは、Data Pumpダンプ・ファイルにエクスポートできます。その後、同じダンプ・ファイルを使用して、各シャードで同時にData Pumpインポートを実行できます。

ダンプ・ファイルは、すべてのシャードからアクセス可能な共有記憶域に配置するか、各シャードのローカル記憶域にコピーできます。個々のシャードにインポートする場合、Data Pumpインポートは現在のシャードに属していない行を無視します。

図7-3 データベース・シャードへのシャード表の直接ロード



すべてのシャードがパラレルにロードされるため、データをシャードに直接ロードする方がはるかに高速です。線形スケーラビリティも提供されます。シャード・データベース内のシャードが多いほど、データ収集率が高くなります。

サンプル・スキーマ・データのロード

例として、次のステップでは、サンプル・スキーマ・データを非シャードからシャード・データベースに移動する方法を示します。構文の例は、前のトピックで紹介したサンプルのCustomers-Orders-LineItems-StockItemsスキーマに基づいています。

  1. データベース表からデータをエクスポートします。
    expdp uname/pwd@non_sharded_db directory=expdir dumpfile=original_tables.dmp logfile=original_tables.log SCHEMAS=UNAME INCLUDE=TABLE:\"IN \( \'CUSTOMERS\', \'ORDERS\', \'STOCKITEMS\' ) \" FLASHBACK_TIME=SYSTIMESTAMP CONTENT=DATA_ONLY

    ソース表(非シャード・データベース内)がパーティション化されている場合は、非パーティション化形式(data_options=group_partition_table_data)でダンプ・ファイルにエクスポートします。

    たとえば、Orders表がソース・データベースのパーティション表である場合は、次のようにエクスポートします。

    $ cat ordexp.par
    directory=expdir
    logfile=ordexp.log
    dumpfile=ord_%U.dmp
    tables=ORDERS
    parallel=8
    COMPRESSION=ALL
    content=data_only
    DATA_OPTIONS=GROUP_PARTITION_TABLE_DATA
    
    $ expdp user/password parfile=ordexp.par
    

    SHARDEDおよびDUPLICATED表はターゲット・データベースにすでに作成されているため、表の内容(DATA_ONLY)のみをエクスポートします。

    Data Pumpエクスポート・ユーティリティ・ファイルは、表ごとに一貫性があります。エクスポート内のすべての表の一貫性を同じ時点で保つ場合は、前述の例に示すように、FLASHBACK_SCNまたはFLASHBACK_TIMEパラメータを使用する必要があります。「特定」の時点での一貫性があるデータベース・エクスポート・ファイルを用意することをお薦めします。

  2. ターゲットのデータベース・ノードでエクスポート・ファイル(original_tables.dmp)にアクセスできるようにしてから、シャード・データベースへのデータのインポートを開始します。

    このファイル(並列エクスポートの場合は複数のファイル)は、ターゲット・データベース・システムに移動することも、ネットワーク経由で共有することもできます。

  3. すべてのターゲット・データベース(シャード・カタログおよびシャード)をインポート用に準備します。

    データベース管理者は、次に示すように、データベース・ユーザーにデータベース・インポート・ディレクトリへのアクセスに必要な権限を付与する必要があります。

    CREATE OR REPLACE DIRECTORY expdir AS ‘/some/directory’; 
    GRANT READ, WRITE ON DIRECTORY expdir TO uname;
    GRANT IMP_FULL_DATABASE TO uname;
    
  4. シャード・カタログを使用してDUPLICATED表(StockItems)をロードします。

    次に、インポート・コマンドの例を示します。

    impdp uname/pwd@catnode:1521/ctlg directory=expdir dumpfile=original_tables.dmp logfile=imp_dup.log tables=StockItems content=DATA_ONLY
  5. シャードにSHARDED表を直接ロードします。

    エクスポートされたSHARDED表(Customers、Orders)をロードする最適な方法は、各シャード(shrd1,2、…、N)でデータ・ポンプを直接実行することです。次に、最初のシャードでのインポート・コマンドの例を示します。

    impdp uname/pwd@shrdnode:1521/shrd1 directory=expdir DUMPFILE=original_tables.dmp LOGFILE=imp_shd1.log TABLES=”Customers, Orders, LineItems” CONTENT=DATA_ONLY

    他のすべてのシャードで、このステップを繰り返します。すべてのシャードのデータのロードに同じダンプ・ファイル(original_tables.dmp)が使用されることに注意してください。Data Pumpインポートでは、現在のシャードに属さない行は無視されます。この操作は、すべてのシャードでパラレルに実行できます。

    並列性がある非常に大きなパーティション表への高速ロードの利点を得るには、データ・ポンプ・パラメータDATA_OPTIONSに値_FORCE_PARALLEL_DMLを含める必要があります。

    $ cat ordimp.par
    directory=expdir
    logfile=ordimp.log
    dumpfile=ord_%U.dmp
    tables=ORDERS
    parallel=8
    content=data_only
    DATA_OPTIONS=_force_parallel_dml
    $ impdp user/password parfile=ordimp.par
    

    次の例で示すように、DATA PUMPタイプの外部表を使用してデータを移行することもできます。

    1. ソース・データベースでエクスポートします。

      CREATE TABLE ORDERS_EXT 
       ORGANIZATION EXTERNAL 
          ( TYPE ORACLE_DATAPUMP 
            DEFAULT DIRECTORY "expdir" 
            ACCESS PARAMETERS ( DEBUG = (3 , 33489664)) 
            LOCATION ('ord1.dat',
                      'ord2.dat',
                      'ord3.dat',
                      'ord4.dat') 
          ) 
      PARALLEL 8 
      REJECT LIMIT UNLIMITED
      AS SELECT * FROM user.ORDERS;
      
    2. 各ターゲット・シャードにインポートします。

      CREATE TABLE ORDERS_EXT 
       ORGANIZATION EXTERNAL 
          ( TYPE ORACLE_DATAPUMP 
            DEFAULT DIRECTORY "expdir" 
            ACCESS PARAMETERS ( DEBUG = (3 , 33489664)) 
            LOCATION ('ord1.dat',
                      'ord2.dat',
                      'ord3.dat',
                      'ord4.dat') 
          ) 
      PARALLEL 8 
      REJECT LIMIT UNLIMITED
      ;
      INSERT /*+ APPEND ENABLE_PARALLEL_DML PARALLEL(a,12) pq_distribute(a, random) */ INTO "user"."ORDERS" a
      SELECT /*+ full(b) parallel(b,12) pq_distribute(b, random)*/ 
      * 
      FROM "ORDERS_EXT" 
      WHERE <predicate*>;
      Commit;
      

      (*) WHERE句の述語はシャーディング方法によって異なります。たとえば、範囲別のユーザー定義シャーディングの場合、特定のシャードのCustNoの範囲に基づきます。システム管理(コンシステント・ハッシュ・ベース)シャーディングの場合は、外部表を使用したシャード・データベースへのデータのロードのユースケースを参照してください。

ノート:

expdpおよびimpdpコマンドでPARALLELパラメータを使用すると、Data Pumpの実行速度を上げることができます。エクスポートの場合、この例に示すように、このパラメータをDUMPFILEパラメータの%Uワイルド・カードと組み合せて使用して、複数のダンプ・ファイルを作成できるようにする必要があります。

expdp uname/pwd@orignode SCHEMAS=uname directory=expdir dumpfile=samp_%U.dmp logfile=samp.log FLASHBACK_TIME=SYSTIMESTAMP PARALLEL=4 

前述のコマンドでは、4つのパラレル・ワーカーが使用され、接尾辞_01、_02、_03および_04を持つ4つのダンプ・ファイルが作成されます。インポート時に同じワイルドカードを使用すると、複数の入力ファイルを参照できるようになります。

シャーディング・キーのないデータの移行

例として、次のステップは、シャーディング・キーを含まないソース表からシャード表にデータを移行する方法を示しています。

前のトピックのデータ・ポンプ・エクスポートおよびインポート・コマンドの例には、LineItems表は含まれていません。これは、非シャード・データベースのこの表にシャーディング・キー列(CustNo)が含まれていないためです。ただし、この列は表のシャード・バージョンで必要です。

非シャード・バージョンとシャード・バージョンの表のスキーマが一致しないため、次のステップに示すように、LineItemsのデータ移行は異なる方法で処理する必要があります。

  1. ソースの非シャードのデータベースで、この列の値を生成するための列およびSQL式が欠落している一時ビューを作成します。
    CREATE OR REPLACE VIEW Lineitems_View AS
      SELECT l.*,
            (SELECT o.CustNo From Orders o WHERE l.PoNo=o.PoNo) CustNo
    FROM LineItems l;
    

    これにより、Orders表との外部キー関係に基づいて列CustNoが移入されたビューLineItems_Viewが作成されます。

  2. データ・ポンプ・エクスポート・ユーティリティのVIEWS_AS_TABLESオプションを使用して、新しいビューをエクスポートします。
    expdp uname/pwd@non_sharded_db directory=expdir DUMPFILE=original_tables_vat.dmp LOGFILE=original_tables_vat.log FLASHBACK_TIME=SYSTIMESTAMP CONTENT=DATA_ONLY TABLES=Uname.Customers,Uname.Orders,Uname.StockItems  VIEWS_AS_TABLES=Uname.LineItems_
  3. 個々のシャード(shrd1、shrd2、..、shrdN)でデータ・ポンプ・インポートを直接実行して、データをシャード表にインポートします。

    次に、最初のシャードでインポートを実行する例を示します。

    impdp uname/pwd@shrdnode:1521/shrd1 directory=expdir DUMPFILE=original_tables_vat.dmp LOGFILE=imp_shd_vat1.log CONTENT=DATA_ONLY TABLES=Uname.Customers,Uname.Orders,Uname.LineItems_View VIEWS_AS_TABLES=Uname.LineItems_View REMAP_TABLE=Lineitems_View:Lineitems

    この例では、impdpツールのVIEWS_AS_TABLESオプションを使用して、エクスポート操作中に表としてエクスポートされたビューLineItems_Viewをインポートします。また、パラメータREMAP_TABLEを使用して、このデータを実際に元の表LineItemsに挿入する必要があることを示します。