テーブルに既存データがある状態で増分データをインポートしたい場合、増分ダイレクトロード機能を利用できます。フルダイレクトロードでも増分データをインポートできますが、フルダイレクトロードで増分データをインポートする過程では、すべての元データをオーバーライドするため、インポートのパフォーマンスが低下します。増分ダイレクトロード機能は、フルダイレクトロードとは異なり、インポートのプロセスで増分データのみを操作するため、インポートのパフォーマンスを保証できます。
本記事では、LOAD DATAステートメント、INSERT INTO SELECTステートメント、CREATE TABLE AS SELECTステートメントを使用して、増分ダイレクトロードを実現する方法について説明します。
注意点
ダイレクトロードを使用する際の注意点は、以下のとおりです:
増分ダイレクトロードのデータはダンプをトリガーするため、データ量が少なくて数分以内にインポートが完了する場合は、増分ダイレクトロードの使用は推奨されません。
増分ダイレクトロードは、ターゲットテーブルに非一意のローカルインデックスがある場合をサポートします。
LOAD DATAステートメントは複数行トランザクションでの実行をサポートしており、実行時に先行するトランザクションを自動的にコミットします。INSERT INTO SELECTステートメントを使用してデータをダイレクトロードする場合は、PDML (Parallel Data Manipulation Language、並列データ操作言語)のみがサポートされており、非PDMLではダイレクトロードを使用できません。LOAD DATAステートメントとINSERT INTO SELECTステートメントで指定パーティションのダイレクトロードを使用する場合は、ターゲットテーブルはレプリケーションテーブルであってはならず、自動インクリメント列、識別列、Global Indexを含むことはできません。V4.3.5バージョンについて、V4.3.5 BP1バージョン以降の増分ダイレクトロードでは、以下の点が変更されています:
- ターゲットテーブルの最後のレベルのパーティションがHash/Keyパーティションの場合、パーティションレベルのダイレクトロードをサポートします。
- ヒープテーブルにローカル一意のインデックスが1つある場合のみをサポートします。ターゲットテーブルに複数のローカル一意のインデックスまたはグローバル一意のインデックスが存在する場合、インポート操作は失敗します。
LOAD DATA/INSERT INTO SELECTステートメントにおいて、複数のインポートタスクで重複するパーティションがある場合、パーティションの並列インポートはサポートされません。重複するパーティションがない場合、パーティションの並列インポートをサポートします。- セッション変数 foreign_key_checksの値がFalseの場合、ダイレクトロード操作は外部キー制約の検証を実行しません。
LOAD DATAステートメントを使用したデータのダイレクトロード
LOAD DATAステートメントは DIRECT() ヒントを使用して増分ダイレクトロードを実行します。ヒントが指定されていない場合は、構成パラメータ default_load_modeに基づいてデータインポート動作を決定します。
使用制限
- インポート中は同時に2つの書き込み操作ステートメントを実行できません(つまり、同じテーブルに同時に書き込むことはできません)。インポート中はテーブルがロックされて、インポート中はずっと読み取り操作のみ可能だからです。
- トリガー(Trigger)での使用はサポートされていません。
- 生成列を含むテーブルはサポートされていません(特定のインデックスは隠れた生成列を作成する場合があります。例:KEY
idx_c2(c2(16)) GLOBAL)。 - 単一行で2MBを超えるデータのインポートはサポートされていません。
- Liboblogとフラッシュバッククエリ(Flashback Query)はサポートされていません。
- 外部キーを持つテーブルは、増分ダイレクトロードをサポートしません。
使用構文
LOAD DATA /*+ [DIRECT(need_sort,max_error,{'inc'|'inc_replace'})] parallel(N) */ [REMOTE_OSS | LOCAL] INFILE 'file_name' INTO TABLE table_name [PARTITION(PARTITION_OPTION)] [COMPRESSION]...
LOAD DATA構文の詳細については、LOAD DATAを参照してください。
パラメータの説明:
| パラメータ | 説明 |
|---|---|
| DIRECT() | ヒントを使用してダイレクトロード機能を有効にします。DIRECT() パラメータの説明は以下のとおりです:
注意
|
| parallel(N) | 必須項目です。データロードの並列度で、デフォルトは4です。 |
| REMOTE_OSS | LOCAL | オプション項目です。
|
| file_name | 入力ファイルのパスとファイル名を指定します。このパラメータ形式は REMOTE_OSS | LOCAL のタイプと相互に対応しています:
説明OSS上のファイルをインポートする際は、以下の情報を確認する必要があります:
|
| table_name | データをインポートするテーブル名。テーブルの任意の列数の指定できます。 |
| PARTITION_OPTION | パーティションダイレクトロード時のパーティション名を指定します:
|
| COMPRESSION | 圧縮ファイル形式を指定します。値は以下のとおりです:
|
説明
LOAD DATAステートメントの増分ダイレクトロードも、フルダイレクトロードと同様に、ワイルドカード方式での複数ファイルインポートをサポートします。ただし、LOAD DATA文のワイルドカードが有効なのはOBServerのローカルマシン上のみです(他のマシンからOBServerにログインしてLOAD DATA文でワイルドカードを使用しても機能しません)。
使用例
LOAD DATAステートメントの増分ダイレクトロードの操作手順は、フルダイレクトロードの手順と同じで、full フィールドの値を inc または inc_replace に置き換えるだけです。
説明
以下の例は、サーバー側のファイルからデータをインポートする方法です。OceanBaseデータベースの LOAD DATAステートメントは、データのダイレクトロードに加えて、ローカルファイルの読み込み(LOCAL INFILE)もサポートしています。LOAD DATA LOCAL INFILE の詳細な例については、LOAD DATAステートメントを使用したデータインポートを参照してください
OBServerノードが配置されているマシンにログインし、
/home/adminディレクトリにテストデータtbl1を作成します。説明
OceanBaseデータベースの
LOAD DATAステートメントは、OBServerノードのローカルにある入力ファイルの読み込みのみをサポートしています。そのため、インポートする前にファイルをいずれかのOBServerにコピーする必要があります。[xxx@xxx /home/admin]# ssh admin@10.10.10.1[admin@xxx /home/admin]# vi tbl1.csv 1,11 2,22 3,33インポートファイルのパスを設定します。
システム変数
secure_file_privを設定して、ファイルのインポートまたはエクスポート時にアクセス可能なパスを設定します。注意
セキュリティ上の理由により、システム変数
secure_file_privを設定する場合は、ローカルソケット接続を介してデータベースに接続し、このグローバル変数を変更するSQLステートメントを実行する必要があります。詳細については、secure_file_priv を参照してください。接続したいOBServerノードが配置されているマシンにログインします。
[xxx@xxx /home/admin]# ssh admin@10.10.10.1以下のコマンドを実行し、ローカルのUnixソケット接続メソッドを使用してテナント
mysql001に接続します。obclient -S /home/admin/oceanbase/run/sql.sock -uroot@mysql001 -p******インポートパスを
/home/adminに設定します。obclient [(none)]> SET GLOBAL secure_file_priv = "/home/admin"; Query OK, 0 rows affected
データベースに再接続した後、
LOAD /*+ DIRECT */ DATAステートメントを使用してデータをインポートします。テーブル
tbl1を作成します。obclient [test]> CREATE TABLE tbl1 ( col1 INT PRIMARY KEY, col2 INT ) PARTITION BY RANGE (col1) SUBPARTITION BY RANGE (col1) ( PARTITION p0 VALUES LESS THAN (100) ( SUBPARTITION p0_1 VALUES LESS THAN (50), SUBPARTITION p0_2 VALUES LESS THAN (100) ), PARTITION p1 VALUES LESS THAN (200) ( SUBPARTITION p1_1 VALUES LESS THAN (150), SUBPARTITION p1_2 VALUES LESS THAN (200) ) ); Query OK, 0 rows affectedテーブル
tbl1にデータがあるかどうかをクエリします。テーブルが空であることが表示されます。obclient [test]> SELECT * FROM tbl1; Empty setダイレクトロードを使用して、
tbl1.csvファイルのデータをテーブルtbl1にインポートします。テーブル
tbl1のすべての列を指定して、データをインポートします。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl1 FIELDS TERMINATED BY ','; Query OK, 3 rows affected Records: 3 Deleted: 0 Skipped: 0 Warnings: 0テーブル
tbl1の指定された任意の列を指定して、データをインポートします。例:col1、col2列を指定。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl1 FIELDS TERMINATED BY ','(col1,col2); Query OK, 3 rows affected Records: 3 Deleted: 0 Skipped: 0 Warnings: 0(オプション)テーブル
tbl1のパーティションを指定して、データをインポートします。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl1 partition(p0, p1) FIELDS TERMINATED BY ',';(オプション)テーブル
tbl1のサブパーティションを指定して、データをインポートします。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl1 partition(p0sp0_1, p1sp1_1) FIELDS TERMINATED BY ',';構成パラメータ
default_load_modeを使用して、データをインポートします。default_load_modeの値をINC_DIRECT_WRITEまたはINC_REPLACE_DIRECT_WRITEに設定します。obclient [test]> ALTER SYSTEM SET default_load_mode ='INC_DIRECT_WRITE';LOAD DATAステートメントでヒントを指定しません。obclient [test]> LOAD DATA INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 FIELDS TERMINATED BY ',';
テーブル
tbl1にデータがインポートされているかどうかを検証します。obclient [test]> SELECT * FROM tbl1;クエリ結果は以下のとおりです:
+------+------+ | col1 | col2 | +------+------+ | 1 | 11 | | 2 | 22 | | 3 | 33 | +------+------+ 3 rows in set結果は、テーブル
tbl2にデータがインポートされたことを示しています。
OBServerノードが配置されているマシンにログインし、
/home/adminディレクトリにテストデータtbl1を作成します。説明
OceanBaseデータベースの
LOAD DATAステートメントは、OBServerノードのローカルにある入力ファイルの読み込みのみをサポートしています。そのため、インポートする前にファイルをいずれかのOBServerにコピーする必要があります。[xxx@xxx /home/admin]# ssh admin@10.10.10.1[admin@xxx /home/admin]# vi tbl1.csv 1,11 2,22 3,33インポートファイルのパスを設定します。
システム変数
secure_file_privを設定して、ファイルのインポートまたはエクスポート時にアクセス可能なパスを設定します。注意
セキュリティ上の理由により、システム変数
secure_file_privを設定する場合は、ローカルソケット接続を介してデータベースに接続し、このグローバル変数を変更するSQLステートメントを実行する必要があります。詳細については、secure_file_priv を参照してください。接続したいOBServerノードが配置されているマシンにログインします。
[xxx@xxx /home/admin]# ssh admin@10.10.10.1以下のコマンドを実行して、ローカルUnixソケット接続を介してテナント
oracle001に接続します。obclient -S /home/admin/oceanbase/run/sql.sock -usys@oracle001 -p******インポートパスを
/home/adminに設定します。obclient [(none)]> SET GLOBAL secure_file_priv = "/home/admin"; Query OK, 0 rows affected
データベースに再接続した後、
LOAD /*+ DIRECT */ DATAステートメントを使用してデータをインポートします。テーブル
tbl2を作成します。obclient [test]> CREATE TABLE tbl2 ( col1 INT PRIMARY KEY, col2 INT ) PARTITION BY RANGE (col1) SUBPARTITION BY RANGE (col1) ( PARTITION p0 VALUES LESS THAN (100) ( SUBPARTITION sp0_1 VALUES LESS THAN (50), SUBPARTITION sp0_2 VALUES LESS THAN (100) ), PARTITION p1 VALUES LESS THAN (200) ( SUBPARTITION sp1_1 VALUES LESS THAN (150), SUBPARTITION sp1_2 VALUES LESS THAN (200) ) ); Query OK, 0 rows affectedテーブル
tbl2にデータがあるかどうかをクエリします。テーブルが空であることが表示されます。obclient [test]> SELECT * FROM tbl2; Empty setダイレクトロードを使用して、
tbl1.csvファイルのデータをテーブルtbl2にインポートします。テーブル
tbl2のすべての列を指定して、データをインポートします。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 FIELDS TERMINATED BY ','; Query OK, 3 rows affected Records: 3 Deleted: 0 Skipped: 0 Warnings: 0テーブル
tbl2の指定された任意の列を指定して、データをインポートします。例:col1、col2列を指定。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 FIELDS TERMINATED BY ','(col1,col2); Query OK, 3 rows affected Records: 3 Deleted: 0 Skipped: 0 Warnings: 0(オプション)テーブル
tbl2のパーティションを指定して、データをインポートします。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 partition(p0, p1) FIELDS TERMINATED BY ',';(オプション)テーブル
tbl2のサブパーティションを指定して、データをインポートします。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 partition(p0sp0_1, p1sp1_1) FIELDS TERMINATED BY ',';構成パラメータ
default_load_modeを使用して、データをインポートします。default_load_modeの値をINC_DIRECT_WRITEまたはINC_REPLACE_DIRECT_WRITEに設定します。obclient [test]> ALTER SYSTEM SET default_load_mode ='INC_DIRECT_WRITE';LOAD DATAステートメントでヒントを指定しません。obclient [test]> LOAD DATA INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 FIELDS TERMINATED BY ',';
テーブル
tbl2にデータがインポートされているかどうかを確認します。obclient [test]> SELECT * FROM tbl2;クエリ結果は以下のとおりです:
+------+------+ | col1 | col2 | +------+------+ | 1 | 11 | | 2 | 22 | | 3 | 33 | +------+------+ 3 rows in set結果は、テーブル
tbl2にデータがインポートされたことを示しています。
INSERT INTO SELECTステートメントを使用したデータのダイレクトロード
INSERT INTO SELECTステートメントは、direct() に加えて enable_parallel_dml ヒントを使用することにより、ダイレクトロードを実行します。ヒントが指定されていない場合は、構成パラメータ default_load_modeに基づいてデータのインポート動作を決定します。
使用制限
- PDML (Parallel Data Manipulation Language、並列データ操作言語)のみがサポートされています。非PDMLではダイレクトロードを使用できません。並列DMLの詳細については、並列DMLを参照してください。
- インポート中は同時に2つの書き込み操作ステートメントを実行できません(つまり、同じテーブルに同時に書き込むことはできません)。インポート中はテーブルがロックされて、インポート中はずっと読み取り操作のみ可能だからです。
- トリガー(Trigger)での使用はサポートされていません。
- 生成列を含むテーブルはサポートされていません(特定のインデックスは隠れた生成列を作成する場合があります。例:KEY
idx_c2(c2(16)) GLOBAL)。 - Liboblogとフラッシュバッククエリ(Flashback Query)はサポートされていません。
- インデックス(主キーを除く)を持つテーブルは、増分ダイレクトロードをサポートしません。
- 外部キーを持つテーブルは、増分ダイレクトロードをサポートしません。
使用構文
INSERT /*+ [DIRECT(need_sort,max_error,{'inc'|'inc_replace'})] enable_parallel_dml parallel(N) */ INTO table_name [PARTITION(PARTITION_OPTION)] select_sentence
INSERT INTO 構文の詳細については、INSERT (MySQLモード)および INSERT (Oracleモード)を参照してください。
パラメータの説明:
| パラメータ | 説明 |
|---|---|
| DIRECT() | ヒントを使用してダイレクトロード機能を有効にします。DIRECT() パラメータの説明は以下のとおりです:
|
| enable_parallel_dml | データをロードする際の並列度。
説明一般的に、並列DMLを有効にするためには、 |
| parallel(N) | データをロードする際の並列度。必須項目で、値は1より大きい整数です。 |
| table_name | データをインポートするテーブル名。テーブルの任意の列数の指定できます。 |
| PARTITION_OPTION | パーティションダイレクトロード時のパーティション名を指定します:
|
使用例
INSERT INTO SELECTステートメントの増分ダイレクトロードの操作手順は、フルダイレクトロードの手順と同じで、full フィールドの値を inc または inc_replace に置き換えるだけです。
例1:INSERT INTO SELECTを使用した増分ダイレクトロードの完全な例です。
ダイレクトロードを使用して、テーブル tbl2 の一部のデータをテーブル tbl1 にインポートします。
テーブル
tbl1にデータがあるかどうかをクエリします。テーブルが空であることが表示されます。obclient [test]> SELECT * FROM tbl1; Empty setテーブル
tbl2にデータがあるかどうかをクエリします。obclient [test]> SELECT * FROM tbl2;テーブル
tbl2にデータがあることをクエリできます。+------+------+------+ | col1 | col2 | col3 | +------+------+------+ | 1 | a1 | 11 | | 2 | a2 | 22 | | 3 | a3 | 33 | +------+------+------+ 3 rows in setダイレクトロードを使用して、テーブル
tbl2のデータをテーブルtbl1にインポートします。INSERT INTO SELECTステートメントのヒントを指定します。パーティションを指定しないインポート。
obclient [test]> INSERT /*+ DIRECT(true, 0, 'inc_replace') enable_parallel_dml parallel(16) */ INTO tbl1 SELECT t2.col1,t2.col3 FROM tbl2 t2; Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0(オプション)パーティションを指定するインポート。
obclient [test]> INSERT /*+ DIRECT(true, 0, 'inc_replace') enable_parallel_dml parallel(16) */ INTO tbl1 partition(p0, p1) SELECT t2.col1,1 FROM tbl2 partition(p0, p1) t2; Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0obclient [test]> INSERT /*+ DIRECT(true, 0, 'inc_replace') enable_parallel_dml parallel(16) */ INTO tbl1 partition(p0, p1) SELECT t2.col1,1 FROM tbl2 partition(p0sp0_1, p1sp1_1) t2; Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0
INSERT INTO SELECTステートメントでヒントを指定しません。構成パラメータ
default_load_modeの値をINC_DIRECT_WRITEまたはINC_REPLACE_DIRECT_WRITEに設定します。obclient [test]> ALTER SYSTEM SET default_load_mode ='INC_DIRECT_WRITE';obclient [test]> INSERT INTO tbl1 SELECT t2.col1,t2.col3 FROM tbl1 t2;
テーブル
tbl1にデータがインポートされているかどうかを検証します。obclient [test]> SELECT * FROM tbl1;クエリ結果は以下のとおりです:
+------+------+ | col1 | col2 | +------+------+ | 1 | 11 | | 2 | 22 | | 3 | 33 | +------+------+ 3 rows in set結果は、テーブル
tbl1にデータがインポートされたことを示しています。(オプション)
EXPLAIN EXTENDEDステートメントの戻り結果のNoteで、ダイレクトロードでデータが書き込まれたかどうかを確認します。obclient [test]> EXPLAIN EXTENDED INSERT /*+ direct(true, 0, 'inc_replace') enable_parallel_dml parallel(16) */ INTO tbl1 SELECT t2.col1,t2.col3 FROM tbl2 t2;結果は次のとおりです:
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Query Plan | +--------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ============================================================================== | | |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| | | ------------------------------------------------------------------------------ | | |0 |PX COORDINATOR | |3 |27 | | | |1 |└─EXCHANGE OUT DISTR |:EX10001 |3 |27 | | | |2 | └─INSERT | |3 |26 | | | |3 | └─EXCHANGE IN DISTR | |3 |1 | | | |4 | └─EXCHANGE OUT DISTR (RANDOM)|:EX10000 |3 |1 | | | |5 | └─SUBPLAN SCAN |ANONYMOUS_VIEW1|3 |1 | | | |6 | └─PX BLOCK ITERATOR | |3 |1 | | | |7 | └─TABLE FULL SCAN |t2 |3 |1 | | | ============================================================================== | | Outputs & filters: | | ------------------------------------- | | 0 - output(nil), filter(nil), rowset=16 | | 1 - output(nil), filter(nil), rowset=16 | | dop=16 | | 2 - output(nil), filter(nil) | | columns([{tbl1: ({tbl1: (tbl1.__pk_increment(0x7efa518277d0), tbl1.col1(0x7efa518119c0), tbl1.col3(0x7efa51811e00))})}]), partitions(p0), | | column_values([T_HIDDEN_PK(0x7efa51827c10)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col1(0x7efa51826f50))(0x7efa51828030)], [column_conv(INT, | | PS:(11,0),NULL,ANONYMOUS_VIEW1.col3(0x7efa51827390))(0x7efa5182ff60)]) | | 3 - output([T_HIDDEN_PK(0x7efa51827c10)], [ANONYMOUS_VIEW1.col1(0x7efa51826f50)], [ANONYMOUS_VIEW1.col3(0x7efa51827390)]), filter(nil), rowset=16 | | 4 - output([T_HIDDEN_PK(0x7efa51827c10)], [ANONYMOUS_VIEW1.col1(0x7efa51826f50)], [ANONYMOUS_VIEW1.col3(0x7efa51827390)]), filter(nil), rowset=16 | | dop=16 | | 5 - output([ANONYMOUS_VIEW1.col1(0x7efa51826f50)], [ANONYMOUS_VIEW1.col3(0x7efa51827390)]), filter(nil), rowset=16 | | access([ANONYMOUS_VIEW1.col1(0x7efa51826f50)], [ANONYMOUS_VIEW1.col3(0x7efa51827390)]) | | 6 - output([t2.col1(0x7efa51825f10)], [t2.col3(0x7efa518267c0)]), filter(nil), rowset=16 | | 7 - output([t2.col1(0x7efa51825f10)], [t2.col3(0x7efa518267c0)]), filter(nil), rowset=16 | | access([t2.col1(0x7efa51825f10)], [t2.col3(0x7efa518267c0)]), partitions(p0) | | is_index_back=false, is_global_index=false, | | range_key([t2.__pk_increment(0x7efa51856410)]), range(MIN ; MAX)always true | | Used Hint: | | ------------------------------------- | | /*+ | | | | USE_PLAN_CACHE( NONE ) | | PARALLEL(16) | | ENABLE_PARALLEL_DML | | DIRECT(TRUE, 0, 'INC_REPLACE') | | */ | | Qb name trace: | | ------------------------------------- | | stmt_id:0, stmt_type:T_EXPLAIN | | stmt_id:1, INS$1 | | stmt_id:2, SEL$1 | | Outline Data: | | ------------------------------------- | | /*+ | | BEGIN_OUTLINE_DATA | | PARALLEL(@"SEL$1" "t2"@"SEL$1" 16) | | FULL(@"SEL$1" "t2"@"SEL$1") | | USE_PLAN_CACHE( NONE ) | | PARALLEL(16) | | ENABLE_PARALLEL_DML | | OPTIMIZER_FEATURES_ENABLE('4.3.3.0') | | DIRECT(TRUE, 0, 'INC_REPLACE') | | END_OUTLINE_DATA | | */ | | Optimization Info: | | ------------------------------------- | | t2: | | table_rows:3 | | physical_range_rows:3 | | logical_range_rows:3 | | index_back_rows:0 | | output_rows:3 | | table_dop:16 | | dop_method:Global DOP | | avaiable_index_name:[tbl2] | | stats info:[version=0, is_locked=0, is_expired=0] | | dynamic sampling level:0 | | estimation method:[DEFAULT, STORAGE] | | Plan Type: | | DISTRIBUTED | | Note: | | Degree of Parallelism is 16 because of hint | | Direct-mode is enabled in insert into select | +--------------------------------------------------------------------------------------------------------------------------------------------------------------+ 77 rows in set (0.009 sec)
例2:Range-Hashコンポジット・パーティションテーブルに対して、パーティションを指定してデータをダイレクトロードします。
ターゲットテーブルはサブパーティションです。パーティションはRange、サブパーティションはHashで、パーティションを指定して増分ダイレクトロードを行います。
RangeパーティションとHashサブパーティションの2つのパーティションを含むテーブル
tbl1を作成します。obclient [test]> CREATE TABLE tbl1(col1 INT,col2 INT) PARTITION BY RANGE COLUMNS(col1) SUBPARTITION BY HASH(col2) SUBPARTITIONS 3 ( PARTITION p0 VALUES LESS THAN(10), PARTITION p1 VALUES LESS THAN(20));ダイレクトロードを使用して、テーブル
tbl2のデータをテーブルtbl1のp0、p1パーティションにインポートします。obclient [test]> insert /*+ direct(true, 0, 'inc_replace') enable_parallel_dml parallel(3) append */ into tbl1 partition(p0,p1) select * from tbl2 where col1 <20;
例1:INSERT INTO SELECTを使用した増分ダイレクトロードの完全な例です。
ダイレクトロードを使用して、テーブル tbl4 の一部のデータをテーブル tbl3 にインポートします。
テーブル
tbl3にデータがあるかどうかをクエリします。テーブルが空であることが表示されます。obclient [test]> SELECT * FROM tbl3; Empty setテーブル
tbl4にデータがあるかどうかをクエリします。obclient [test]> SELECT * FROM tbl4;テーブル
tbl4にデータがあることをクエリしました。+------+------+------+ | COL1 | COL2 | COL3 | +------+------+------+ | 1 | a1 | 11 | | 2 | a2 | 22 | | 3 | a3 | 33 | +------+------+------+ 3 rows in set (0.000 sec)ダイレクトロードを使用して、テーブル
tbl4のデータをテーブルtbl3にインポートします。INSERT INTO SELECTステートメントの ヒントを指定します。パーティションを指定しないインポート。
obclient [test]> INSERT /*+ direct(true, 0, 'inc_replace') enable_parallel_dml parallel(16) */ INTO tbl3 SELECT t2.col1, t2.col3 FROM tbl4 t2 WHERE ROWNUM <= 10000; Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0(オプション)パーティションを指定するインポート。
obclient [test]> INSERT /*+ DIRECT(true, 0, 'inc_replace') enable_parallel_dml parallel(16) */ INTO tbl3 partition(p0, p1) SELECT t2.col1,1 FROM tbl4 partition(p0, p1) t2; Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0obclient [test]> INSERT /*+ DIRECT(true, 0, 'inc_replace') enable_parallel_dml parallel(16) */ INTO tbl3 partition(p0, p1) SELECT t2.col1,1 FROM tbl4 partition(p0sp0_1, p1sp1_1) t2; Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0
INSERT INTO SELECTステートメントの ヒントを指定しません。構成パラメータ
default_load_modeの値をINC_DIRECT_WRITEまたはINC_REPLACE_DIRECT_WRITEに設定します。obclient [test]> ALTER SYSTEM SET default_load_mode ='INC_DIRECT_WRITE';obclient [test]> INSERT INTO tbl3 SELECT t2.col1, t2.col3 FROM tbl4 t2 WHERE ROWNUM <= 10000;
テーブル
tbl3にデータがインポートされているかどうかを検証します。obclient [test]> SELECT * FROM tbl3;クエリ結果は以下のとおりです:
+------+------+ | col1 | col3 | +------+------+ | 1 | 11 | | 2 | 22 | | 3 | 33 | +------+------+ 3 rows in set結果は、テーブル
tbl3にデータがインポートされたことを示しています。(オプション)
EXPLAIN EXTENDEDステートメントの戻り結果のNoteで、ダイレクトロードでデータが書き込まれたかどうかを確認します。obclient [test]> EXPLAIN EXTENDED INSERT /*+ direct(true, 0, 'inc_replace') enable_parallel_dml parallel(16) */ INTO tbl3 SELECT t2.col1,t2.col3 FROM tbl4 t2 WHERE ROWNUM <= 10000; 結果は次のとおりです: ```shell +--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Query Plan | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ========================================================================================= | | |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| | | ----------------------------------------------------------------------------------------- | | |0 |PX COORDINATOR | |3 |34 | | | |1 |└─EXCHANGE OUT DISTR |:EX10002 |3 |33 | | | |2 | └─INSERT | |3 |32 | | | |3 | └─EXCHANGE IN DISTR | |3 |7 | | | |4 | └─EXCHANGE OUT DISTR (RANDOM) |:EX10001 |3 |7 | | | |5 | └─MATERIAL | |3 |3 | | | |6 | └─SUBPLAN SCAN |ANONYMOUS_VIEW1|3 |3 | | | |7 | └─LIMIT | |3 |3 | | | |8 | └─EXCHANGE IN DISTR | |3 |3 | | | |9 | └─EXCHANGE OUT DISTR |:EX10000 |3 |1 | | | |10| └─LIMIT | |3 |1 | | | |11| └─PX BLOCK ITERATOR | |3 |1 | | | |12| └─COLUMN TABLE FULL SCAN|T2 |3 |1 | | | ========================================================================================= | | Outputs & filters: | | ------------------------------------- | | 0 - output(nil), filter(nil), rowset=16 | | 1 - output(nil), filter(nil), rowset=16 | | dop=16 | | 2 - output(nil), filter(nil) | | columns([{TBL3: ({TBL3: (TBL3.__pk_increment(0x7efaad22b0e0), TBL3.COL1(0x7efaad2123f0), TBL3.COL3(0x7efaad212830))})}]), partitions(p0), | | column_values([T_HIDDEN_PK(0x7efaad22b520)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL1(0x7efaad22a860))(0x7efaad22b930)], [column_conv(NUMBER, | | PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL3(0x7efaad22aca0))(0x7efaad233850)]) | | 3 - output([T_HIDDEN_PK(0x7efaad22b520)], [ANONYMOUS_VIEW1.COL1(0x7efaad22a860)], [ANONYMOUS_VIEW1.COL3(0x7efaad22aca0)]), filter(nil), rowset=16 | | 4 - output([T_HIDDEN_PK(0x7efaad22b520)], [ANONYMOUS_VIEW1.COL1(0x7efaad22a860)], [ANONYMOUS_VIEW1.COL3(0x7efaad22aca0)]), filter(nil), rowset=16 | | is_single, dop=1 | | 5 - output([ANONYMOUS_VIEW1.COL1(0x7efaad22a860)], [ANONYMOUS_VIEW1.COL3(0x7efaad22aca0)]), filter(nil), rowset=16 | | 6 - output([ANONYMOUS_VIEW1.COL1(0x7efaad22a860)], [ANONYMOUS_VIEW1.COL3(0x7efaad22aca0)]), filter(nil), rowset=16 | | access([ANONYMOUS_VIEW1.COL1(0x7efaad22a860)], [ANONYMOUS_VIEW1.COL3(0x7efaad22aca0)]) | | 7 - output([T2.COL1(0x7efaad229470)], [T2.COL3(0x7efaad229f40)]), filter(nil), rowset=16 | | limit(cast(FLOOR(cast(10000, NUMBER(-1, -85))(0x7efaad227ef0))(0x7efaad25ac30), BIGINT(-1, 0))(0x7efaad25b6d0)), offset(nil) | | 8 - output([T2.COL1(0x7efaad229470)], [T2.COL3(0x7efaad229f40)]), filter(nil), rowset=16 | | 9 - output([T2.COL1(0x7efaad229470)], [T2.COL3(0x7efaad229f40)]), filter(nil), rowset=16 | | dop=16 | | 10 - output([T2.COL1(0x7efaad229470)], [T2.COL3(0x7efaad229f40)]), filter(nil), rowset=16 | | limit(cast(FLOOR(cast(10000, NUMBER(-1, -85))(0x7efaad227ef0))(0x7efaad25ac30), BIGINT(-1, 0))(0x7efaad25b6d0)), offset(nil) | | 11 - output([T2.COL1(0x7efaad229470)], [T2.COL3(0x7efaad229f40)]), filter(nil), rowset=16 | | 12 - output([T2.COL1(0x7efaad229470)], [T2.COL3(0x7efaad229f40)]), filter(nil), rowset=16 | | access([T2.COL1(0x7efaad229470)], [T2.COL3(0x7efaad229f40)]), partitions(p0) | | limit(cast(FLOOR(cast(10000, NUMBER(-1, -85))(0x7efaad227ef0))(0x7efaad25ac30), BIGINT(-1, 0))(0x7efaad25b6d0)), offset(nil), is_index_back=false, | | is_global_index=false, | | range_key([T2.__pk_increment(0x7efaad25a720)]), range(MIN ; MAX)always true | | Used Hint: | | ------------------------------------- | | /*+ | | | | USE_PLAN_CACHE( NONE ) | | PARALLEL(16) | | ENABLE_PARALLEL_DML | | DIRECT(TRUE, 0, 'INC_REPLACE') | | */ | | Qb name trace: | | ------------------------------------- | | stmt_id:0, stmt_type:T_EXPLAIN | | stmt_id:1, INS$1 | | stmt_id:2, SEL$1 | | stmt_id:3, parent:SEL$1 > SEL$658037CB > SEL$DCAFFB86 | | Outline Data: | | ------------------------------------- | | /*+ | | BEGIN_OUTLINE_DATA | | PARALLEL(@"SEL$DCAFFB86" "T2"@"SEL$1" 16) | | FULL(@"SEL$DCAFFB86" "T2"@"SEL$1") | | USE_COLUMN_TABLE(@"SEL$DCAFFB86" "T2"@"SEL$1") | | MERGE(@"SEL$658037CB" < "SEL$1") | | USE_PLAN_CACHE( NONE ) | | PARALLEL(16) | | ENABLE_PARALLEL_DML | | OPTIMIZER_FEATURES_ENABLE('4.3.3.0') | | DIRECT(TRUE, 0, 'INC_REPLACE') | | END_OUTLINE_DATA | | */ | | Optimization Info: | | ------------------------------------- | | T2: | | table_rows:3 | | physical_range_rows:3 | | logical_range_rows:3 | | index_back_rows:0 | | output_rows:3 | | table_dop:16 | | dop_method:Global DOP | | avaiable_index_name:[TBL4] | | stats info:[version=0, is_locked=0, is_expired=0] | | dynamic sampling level:0 | | estimation method:[DEFAULT, STORAGE] | | Plan Type: | | DISTRIBUTED | | Note: | | Degree of Parallelism is 16 because of hint | | Direct-mode is enabled in insert into select | | Expr Constraints: | | cast(FLOOR(cast(10000, NUMBER(-1, -85))), BIGINT(-1, 0)) >= 1 result is TRUE | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 96 rows in set (0.007 sec)
例2:Range-Hashコンポジット・パーティションテーブルに対して、一次パーティションを指定してデータをダイレクトロードします。
ターゲットテーブルはコンポジット・パーティションテーブルです。一次パーティションはRange、サブパーティションはHashで、一次パーティションを指定して増分ダイレクトロードを行います。
RangeパーティションとHashサブパーティションの2つのパーティションを含むテーブル
tbl1を作成します。obclient [test]> CREATE TABLE tbl1_1 ( col1 INT, col2 INT ) PARTITION BY RANGE (col1) SUBPARTITION BY HASH (col2) SUBPARTITION TEMPLATE ( SUBPARTITION sp1, SUBPARTITION sp2, SUBPARTITION sp3 ) ( PARTITION p0 VALUES LESS THAN (10), PARTITION p1 VALUES LESS THAN (20) );ダイレクトロードを使用して、テーブル
tbl2のデータをテーブルtbl1のp0、p1パーティションにインポートします。obclient [test]> insert /*+ direct(true, 0, 'inc_replace') enable_parallel_dml parallel(3) append */ into tbl1 partition(p0,p1) select * from tbl2 where col1 <20;
CREATE TABLE AS SELECTステートメントを使用したデータのダイレクトロード
CREATE TABLE AS SELECTステートメントは DIRECT() ヒントおよび PARALLE() ヒントを設定してダイレクトロードのデータロード方式を指定します。ヒントが指定されていない場合は、構成パラメータ default_load_modeに基づいてデータインポート動作を決定します。
使用構文
CREATE /*+ [DIRECT(need_sort,max_error,{'inc'|'inc_replace'})] parallel(N) */ TABLE table_name [AS] select_sentence
CREATE TABLE AS SELECT 構文の詳細については、CREATE TABLE (MySQLモード)および CREATE TABLE (Oracleモード)を参照してください。
パラメータの説明:
| パラメータ | 説明 |
|---|---|
| DIRECT() | ヒントを使用してダイレクトロード機能を有効にします。DIRECT() パラメータの説明は以下のとおりです:
注意
|
| parallel(N) | データをロードする際の並列度。必須項目で、値は1より大きい整数です。 |
使用例
ダイレクトロードを使用して、テーブル tbl1 のデータを他のテーブルにインポートします。
テーブル
tbl1を作成します。obclient [test]> CREATE TABLE tbl1(c1 int);テーブル
tbl1にデータを挿入します。obclient [test]> INSERT INTO tbl1 VALUES (1),(2),(3);テーブル
tbl1のデータをクエリします。obclient [test]> SELECT * FROM tbl1;クエリ結果は以下のとおりです:
+------+ | c1 | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.027 sec)ダイレクトロードを使用して、テーブル
tbl1のデータをテーブルtbl2にインポートします。CREATE TABLE AS SELECTステートメントの ヒントを指定します。incヒントを使用してデータをダイレクトロードします。obclient [test]> CREATE /*+ direct(true, 0, 'inc') parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;inc_replaceヒントを使用してデータをダイレクトロードします。obclient [test]> CREATE /*+ direct(true, 0, 'inc_replace') parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;
CREATE TABLE AS SELECTステートメントの ヒントを指定しません。構成パラメータ
default_load_modeの値をINC_DIRECT_WRITEまたはINC_REPLACE_DIRECT_WRITEに設定します。obclient [test]> ALTER SYSTEM SET default_load_mode ='INC_DIRECT_WRITE';obclient [test]> CREATE TABLE tbl2 AS SELECT * FROM tbl1;
テーブル
tbl2にデータがインポートされているかどうかを確認します。obclient [test]> SELECT * FROM tbl2;クエリ結果は以下のとおりです:
+------+ | c1 | +------+ | 1 | | 3 | | 2 | +------+ 3 rows in set (0.050 sec)結果は、テーブル
tbl2にデータがインポートされたことを示しています。
ダイレクトロードを使用して、テーブル tbl1 のデータを他のテーブルにインポートします。
テーブル
tbl1を作成します。obclient [SYS]> CREATE TABLE tbl1(c1 int);テーブル
tbl1にデータを挿入します。obclient [SYS]> INSERT INTO tbl1 VALUES (1),(2),(3);テーブル
tbl1のデータをクエリします。obclient [SYS]> SELECT * FROM tbl1;クエリ結果は以下のとおりです:
+------+ | C1 | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.045 sec)ダイレクトロードを使用して、テーブル
tbl1のデータをテーブルtbl2にインポートします。CREATE TABLE AS SELECTステートメントの ヒントを指定します。incヒントを使用してデータをダイレクトロードします。obclient [SYS]> CREATE /*+ direct(true, 0, 'inc') parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;inc_replaceヒントを使用してデータをダイレクトロードします。obclient [SYS]> CREATE /*+ direct(true, 0, 'inc_replace') parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;
CREATE TABLE AS SELECTステートメントの ヒントを指定しません。構成パラメータ
default_load_modeの値をINC_DIRECT_WRITEまたはINC_REPLACE_DIRECT_WRITEに設定します。obclient [SYS]> ALTER SYSTEM SET default_load_mode ='INC_DIRECT_WRITE';obclient [SYS]> CREATE TABLE tbl2 AS SELECT * FROM tbl1;
テーブル
tbl2にデータがインポートされているかどうかを確認します。obclient [SYS]> SELECT * FROM tbl2;クエリ結果は以下のとおりです:
+------+ | C1 | +------+ | 3 | | 2 | | 1 | +------+ 3 rows in set (0.013 sec)結果は、テーブル
tbl2にデータがインポートされたことを示しています。