本記事では、LOAD DATAステートメント、INSERT INTO SELECTステートメント、およびCREATE TABLE AS SELECTステートメントを使用してフルダイレクトロードを実現する方法について説明します。
注意点
フルダイレクトロードを使用する際の注意点は以下のとおりです:
OceanBaseデータベースはV4.3.0バージョンからLOBデータ型のダイレクトロードをサポートしています。
ダイレクトロード中はテーブルロックがかかり、テーブルへの他のデータ書き込みはできません。プロセス全体を通じてテーブルは読み取り専用となります。
フルダイレクトロードは、大規模テーブルの初回インポート、10GB~TBレベルのデータ移行、およびCPUとメモリがそれほど余裕のないシナリオに適しています。これは、ダイレクトロードの実行パスが短く、CPUオーバーヘッドを節約できるためです。
LOAD DATAステートメントは複数行トランザクション内での実行をサポートしており、実行時に先行するトランザクションを自動的にコミットします。INSERT INTO SELECTステートメントを使用したデータのダイレクトロードは、PDML(Parallel Data Manipulation Language、並列データ操作言語)のみをサポートしており、非PDMLではダイレクトロードを使用できません。LOAD DATAステートメントおよびINSERT INTO SELECTステートメントで指定パーティションへのダイレクトロードを使用する場合、対象テーブルはレプリケーションテーブルであってはならず、自動インクリメント列、識別列、グローバルインデックスを含むことはできません。V4.3.5バージョンについては、V4.3.5 BP1バージョン以降のフルダイレクトロードで以下の変更があります:
- 対象テーブルの最終レベルパーティションがHash/Keyパーティションの場合、パーティションレベルのダイレクトロードをサポートします。
- セッションレベル変数 foreign_key_checks の値がFalseの場合、ダイレクトロード操作は外部キー制約の検証を行いません。
LOAD DATAステートメントによる一意インデックスを持つテーブルへのフルダイレクトロードにおいて、重複する一意インデックスキーが存在する場合、現在はREPLACEまたはIGNOREキーワードをサポートしておらず、フォールトトレランス行の設定もサポートしていません。
LOAD DATAステートメントを使用したデータのダイレクトロード
LOAD DATAステートメントは、append/direct() ヒントを使用してダイレクトロードを実行します。ヒントが指定されていない場合は、パラメータ default_load_modeに基づいてデータインポートの動作を決定します。
注意
OceanBaseデータベースは、パラレル処理技術により LOAD DATA のデータインポートレートを最適化します。この操作はデータを複数のサブタスクに分割して並列実行し、各サブタスクは独立したトランザクションとして扱われ、実行順序は固定されていません。そのため、主キーのないテーブルでは、データの書き込み順序が元のファイルの順序と異なる場合があります。
使用上の制限
- インポート中は、2つの書き込み操作文を同時に実行できません(つまり、1つのテーブルに同時に書き込むことはできません)。インポートプロセスでは最初にテーブルロックが取得され、インポート全体を通じて読み取り操作のみが可能となるためです。
- トリガー(Trigger)での使用はサポートされていません。
- 生成列を含むテーブルはサポートされていません(一部のインデックスは隠れた生成列を作成する場合があります。例:KEY
idx_c2(c2(16)) GLOBAL)。 - 単一行が2MBを超えるデータのインポートはサポートされていません。
- Liboblogおよびフラッシュバッククエリ(Flashback Query)はサポートされていません。
使用構文
LOAD DATA /*+ [APPEND | DIRECT(need_sort,max_error,'full')] parallel(N) */ [REMOTE_OSS | LOCAL] INFILE 'file_name' INTO TABLE table_name [PARTITION(PARTITION_OPTION)] [COMPRESSION]...
LOAD DATA 構文の詳細については、LOAD DATAを参照してください。
パラメータの説明:
パラメータ |
説明 |
|---|---|
| APPEND | DIRECT() | ヒントを使用してダイレクトロード機能を有効にします。
|
| parallel(N) | 必須項目。データ読み込みの並列度です。デフォルトは4です。 |
| REMOTE_OSS | LOCAL | オプションです。
|
| file_name | インポートファイルのパスとファイル名を指定します。このパラメータの形式は REMOTE_OSS | LOCAL のタイプに対応しています:
説明OSS上のファイルをインポートする際は、以下の情報を確認する必要があります:
|
| table_name | データをインポートするテーブルの名前。任意の数の列を指定できます。 |
| PARTITION_OPTION | パーティションダイレクトロード時のパーティション名を指定します:
|
| COMPRESSION | 圧縮ファイル形式を指定します。値は次のとおりです。
|
使用例
説明
以下の例は、サーバー側ファイルからデータをインポートする方法です。OceanBaseデータベースの LOAD DATA ステートメントによるデータのダイレクトロードは、ローカルファイルの読み込み(LOCAL INFILE)もサポートしています。LOAD DATA LOCAL INFILE の詳細な使用例については、LOAD DATA ステートメントを使用したデータのインポート
OBServerノードに接続するマシンにログインし、
/home/adminディレクトリにテストデータを作成します。説明
OceanBaseデータベースの
LOAD DATAステートメントは、OBServerノードのローカルにある入力ファイルのみの読み込みをサポートしています。そのため、インポートする前にファイルをいずれかのOBServerにコピーする必要があります。OBServerノードが存在するマシンにアクセスします。
[xxx@xxx /home/admin]# ssh admin@10.10.10.1テストデータ
tbl1.csvを作成します。[admin@xxx /home/admin]# vi tbl1.csv 1,11 2,22 3,33
インポートファイルのパスを設定します。
システム変数
secure_file_privを設定し、インポートまたはエクスポート時にアクセス可能なパスを構成します。注意
セキュリティ上の理由から、システム変数
secure_file_privを設定する際は、ローカルUnixソケット接続を介してデータベースに接続し、このグローバル変数を変更する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ステートメントを使用してデータをインポートします。テーブル
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 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テーブル
tbl2にデータがあるかどうかを確認します。この時点では、テーブルは空で表示されます。obclient [test]> SELECT * FROM tbl2; Empty setダイレクトロードを使用して、
tbl1.csvファイルのデータをテーブルtbl2にインポートします。データをインポートするテーブル
tbl2のすべての列を指定します。obclient [test]> LOAD DATA /*+ direct(true,1024,'full') 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,'full') 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,'full') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 partition(p0, p1) FIELDS TERMINATED BY ',';データをインポートするテーブル
tbl2のサブパーティションを指定します。obclient [test]> LOAD DATA /*+ direct(true,1024,'full') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 partition(p0sp0_1, p1sp1_1) FIELDS TERMINATED BY ',';パラメータ
default_load_modeを使用してデータをインポートします。default_load_modeの値をFULL_DIRECT_WRITEに設定します。obclient [test]> ALTER SYSTEM SET default_load_mode ='FULL_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にデータがインポートされていることを示しています。
OBServerノードに接続するマシンにログインし、
/home/adminディレクトリにテストデータtbl1を作成します。説明
OceanBaseデータベースの
LOAD DATAステートメントは、OBServerノードのローカルにある入力ファイルのみを読み込むことができます。そのため、インポートする前にファイルをいずれかのOBServerにコピーする必要があります。OBServerノードが存在するマシンにアクセスします。
[xxx@xxx /home/admin]# ssh admin@10.10.10.1テストデータ
tbl1.csvを作成します。[admin@xxx /home/admin]# vi tbl1.csv 1,11 2,22 3,33
インポートファイルのパスを設定します。
システム変数
secure_file_privを設定して、インポートまたはエクスポート時にアクセス可能なパスを構成します。注意
セキュリティ上の理由から、システム変数
secure_file_privを設定する際は、ローカルのUnixソケット接続を介してデータベースに接続し、このグローバル変数を変更する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 [SYS]> CREATE TABLE tbl2 ( 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テーブル
tbl2にデータがあるかどうかを確認します。この時点では、テーブルは空です。obclient [SYS]> SELECT * FROM tbl2; Empty setダイレクトロードを使用して、
tbl1.csvファイルのデータをテーブルtbl2にインポートします。データをインポートするテーブル
tbl2のすべての列を指定します。obclient [SYS]> LOAD DATA /*+ direct(true,1024,'full') 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 [SYS]> LOAD DATA /*+ direct(true,1024,'full') 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 [SYS]> LOAD DATA /*+ direct(true,1024,'full') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 partition(p0, p1) FIELDS TERMINATED BY ',';(オプション)データをインポートするテーブル
tbl2のサブパーティションを指定します。obclient [SYS]> LOAD DATA /*+ direct(true,1024,'full') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 partition(p0sp0_1, p1sp1_1) FIELDS TERMINATED BY ',';パラメータ
default_load_modeを使用してデータをインポートします。default_load_modeの値をFULL_DIRECT_WRITEに設定します。obclient [SYS]> ALTER SYSTEM SET default_load_mode ='FULL_DIRECT_WRITE';LOAD DATAステートメントのヒントを指定しません。obclient [SYS]> LOAD DATA INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 FIELDS TERMINATED BY ',';
テーブル
tbl2にデータがインポートされているかどうかを検証します。obclient [SYS]> SELECT * FROM tbl2;クエリ結果は次のとおりです:
+------+------+ | col1 | col2 | +------+------+ | 1 | 11 | | 2 | 22 | | 3 | 33 | +------+------+ 3 rows in set結果は、テーブル
tbl2にデータがインポートされていることを示しています。
INSERT INTO SELECTステートメントを使用したデータのダイレクトロード
INSERT INTO SELECT ステートメントは、Hintとして append/direct() および enable_parallel_dml を使用してダイレクトロードを実行します。Hintが指定されていない場合は、パラメータ default_load_mode に基づいてデータのインポート動作を決定します。
使用上の制限
- ダイレクトロードはPDML(Parallel Data Manipulation Language、並列データ操作言語)のみをサポートしており、非PDMLでは使用できません。並列DMLの詳細については、並列DMLを参照してください。
- インポート中は、2つの書き込み操作ステートメントを同時に実行することはできません(つまり、1つのテーブルに同時に書き込むことはできません)。インポートプロセスでは最初にテーブルロックが取得され、インポート全体を通じて読み取り操作のみが可能となるためです。
- ダイレクトロードはDDLステートメントに属するため、複数行トランザクション(複数の操作を含むトランザクション)内で実行することはできません。
- BEGIN内での実行はできません。
- Autocommitは1に設定する必要があります。
- トリガー(Trigger)での使用はサポートされていません。
- 生成列を含むテーブルはサポートされていません(一部のインデックスは隠れた生成列を作成する場合があります。例:KEY
idx_c2(c2(16)) GLOBAL)。 - Liboblogおよびフラッシュバッククエリ(Flashback Query)はサポートされていません。
使用構文
INSERT /*+ [APPEND |DIRECT(need_sort,max_error,'full')] enable_parallel_dml parallel(N) */ INTO table_name [PARTITION(PARTITION_OPTION)] select_sentence
INSERT INTO 構文の詳細については、INSERT(MySQLモード)およびINSERT(Oracleモード)を参照してください。
パラメータの説明:
パラメータ |
説明 |
|---|---|
| APPEND | DIRECT() | ヒントを使用してダイレクトロード機能を有効にします。
|
| enable_parallel_dml | データロードの並列度。
説明通常、 |
| parallel(N) | データロードの並列度です。必須項目で、1より大きい整数を指定します。 |
| table_name | データをインポートするテーブル名です。任意の列数を指定できます。 |
| PARTITION_OPTION | パーティションダイレクトロード時のパーティション名を指定します:
|
使い方
例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ステートメントのHintを指定します。パーティションインポートを指定しません。
obclient [test]> INSERT /*+ DIRECT(true, 0, 'full') 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, 'full') 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, 'full') 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ステートメントのHintを指定しません。パラメータ
default_load_modeの値をFULL_DIRECT_WRITEに設定します。obclient [test]> ALTER SYSTEM SET default_load_mode ='FULL_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, 'full') 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(0x7efa63627790), tbl1.col1(0x7efa63611980), tbl1.col3(0x7efa63611dc0))})}]), partitions(p0), | | column_values([T_HIDDEN_PK(0x7efa63627bd0)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col1(0x7efa63626f10))(0x7efa63627ff0)], [column_conv(INT, | | PS:(11,0),NULL,ANONYMOUS_VIEW1.col3(0x7efa63627350))(0x7efa6362ff20)]) | | 3 - output([T_HIDDEN_PK(0x7efa63627bd0)], [ANONYMOUS_VIEW1.col1(0x7efa63626f10)], [ANONYMOUS_VIEW1.col3(0x7efa63627350)]), filter(nil), rowset=16 | | 4 - output([T_HIDDEN_PK(0x7efa63627bd0)], [ANONYMOUS_VIEW1.col1(0x7efa63626f10)], [ANONYMOUS_VIEW1.col3(0x7efa63627350)]), filter(nil), rowset=16 | | dop=16 | | 5 - output([ANONYMOUS_VIEW1.col1(0x7efa63626f10)], [ANONYMOUS_VIEW1.col3(0x7efa63627350)]), filter(nil), rowset=16 | | access([ANONYMOUS_VIEW1.col1(0x7efa63626f10)], [ANONYMOUS_VIEW1.col3(0x7efa63627350)]) | | 6 - output([t2.col1(0x7efa63625ed0)], [t2.col3(0x7efa63626780)]), filter(nil), rowset=16 | | 7 - output([t2.col1(0x7efa63625ed0)], [t2.col3(0x7efa63626780)]), filter(nil), rowset=16 | | access([t2.col1(0x7efa63625ed0)], [t2.col3(0x7efa63626780)]), partitions(p0) | | is_index_back=false, is_global_index=false, | | range_key([t2.__pk_increment(0x7efa63656410)]), range(MIN ; MAX)always true | | Used Hint: | | ------------------------------------- | | /*+ | | | | USE_PLAN_CACHE( NONE ) | | PARALLEL(16) | | ENABLE_PARALLEL_DML | | DIRECT(TRUE, 0, 'FULL') | | */ | | 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, 'FULL') | | 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パーティションです。パーティション単位でのフルダイレクトロードを指定します。
2つのパーティションを含むテーブル
tbl1を作成します。パーティションはRangeパーティション、サブパーティションはHashパーティションです。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, 'full') 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ステートメントのHintを指定します。パーティションを指定せずにインポートします。
obclient [test]> INSERT /*+ direct(true, 0, 'full') 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, 'full') 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, 'full') 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ステートメントのHintを指定しません。パラメータ
default_load_modeの値をFULL_DIRECT_WRITEに設定します。obclient [test]> ALTER SYSTEM SET default_load_mode ='FULL_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, 'full') enable_parallel_dml parallel(16) */ INTO tbl3 SELECT t2.col1,t2.col3 FROM tbl4 t2;戻り結果は次のとおりです:
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Query Plan | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | =================================================================================== | | |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| | | ----------------------------------------------------------------------------------- | | |0 |OPTIMIZER STATS MERGE | |3 |29 | | | |1 |└─PX COORDINATOR | |3 |29 | | | |2 | └─EXCHANGE OUT DISTR |:EX10001 |3 |27 | | | |3 | └─INSERT | |3 |27 | | | |4 | └─OPTIMIZER STATS GATHER | |3 |1 | | | |5 | └─EXCHANGE IN DISTR | |3 |1 | | | |6 | └─EXCHANGE OUT DISTR (RANDOM) |:EX10000 |3 |1 | | | |7 | └─SUBPLAN SCAN |ANONYMOUS_VIEW1|3 |1 | | | |8 | └─PX BLOCK ITERATOR | |3 |1 | | | |9 | └─COLUMN TABLE FULL SCAN|T2 |3 |1 | | | =================================================================================== | | Outputs & filters: | | ------------------------------------- | | 0 - output(nil), filter(nil), rowset=16 | | 1 - output([column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL1(0x7ef8f6027720))(0x7ef8f60287f0)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60))(0x7ef8f6030710)]), filter(nil), rowset=16 | | 2 - output([column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL1(0x7ef8f6027720))(0x7ef8f60287f0)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60))(0x7ef8f6030710)]), filter(nil), rowset=16 | | dop=16 | | 3 - output([column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL1(0x7ef8f6027720))(0x7ef8f60287f0)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60))(0x7ef8f6030710)]), filter(nil) | | columns([{TBL3: ({TBL3: (TBL3.__pk_increment(0x7ef8f6027fa0), TBL3.COL1(0x7ef8f6011d50), TBL3.COL3(0x7ef8f6012190))})}]), partitions(p0), | | column_values([T_HIDDEN_PK(0x7ef8f60283e0)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL1(0x7ef8f6027720))(0x7ef8f60287f0)], [column_conv(NUMBER, | | PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60))(0x7ef8f6030710)]) | | 4 - output([column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL1(0x7ef8f6027720))(0x7ef8f60287f0)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60))(0x7ef8f6030710)], | | [T_HIDDEN_PK(0x7ef8f60283e0)]), filter(nil), rowset=16 | | 5 - output([T_HIDDEN_PK(0x7ef8f60283e0)], [ANONYMOUS_VIEW1.COL1(0x7ef8f6027720)], [ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60)]), filter(nil), rowset=16 | | 6 - output([T_HIDDEN_PK(0x7ef8f60283e0)], [ANONYMOUS_VIEW1.COL1(0x7ef8f6027720)], [ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60)]), filter(nil), rowset=16 | | dop=16 | | 7 - output([ANONYMOUS_VIEW1.COL1(0x7ef8f6027720)], [ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60)]), filter(nil), rowset=16 | | access([ANONYMOUS_VIEW1.COL1(0x7ef8f6027720)], [ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60)]) | | 8 - output([T2.COL1(0x7ef8f60264c0)], [T2.COL3(0x7ef8f6026f90)]), filter(nil), rowset=16 | | 9 - output([T2.COL1(0x7ef8f60264c0)], [T2.COL3(0x7ef8f6026f90)]), filter(nil), rowset=16 | | access([T2.COL1(0x7ef8f60264c0)], [T2.COL3(0x7ef8f6026f90)]), partitions(p0) | | is_index_back=false, is_global_index=false, | | range_key([T2.__pk_increment(0x7ef8f60584a0)]), range(MIN ; MAX)always true | | Used Hint: | | ------------------------------------- | | /*+ | | | | USE_PLAN_CACHE( NONE ) | | PARALLEL(16) | | ENABLE_PARALLEL_DML | | DIRECT(TRUE, 0, 'FULL') | | */ | | 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_COLUMN_TABLE(@"SEL$1" "T2"@"SEL$1") | | USE_PLAN_CACHE( NONE ) | | PARALLEL(16) | | ENABLE_PARALLEL_DML | | OPTIMIZER_FEATURES_ENABLE('4.3.3.0') | | DIRECT(TRUE, 0, 'FULL') | | 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 | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 82 rows in set (0.006 sec)
例2:Range-Hashサブパーティションテーブルに対して、パーティション単位でダイレクトロードを指定してデータをインポートする場合。
ターゲットテーブルはサブパーティションであり、パーティション単位がRangeパーティション、サブパーティション単位がHashパーティションです。パーティション単位でのフルダイレクトロードを指定します。
2つのパーティションを含むテーブル
tbl1を作成します。パーティション単位がRangeパーティション、サブパーティション単位がHashパーティションです。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, 'full') 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() ヒントを設定することでダイレクトロードのデータロード方式を指定します。ヒントが指定されていない場合は、パラメータ default_load_modeに基づいてデータインポートの動作を決定します。
使用構文
CREATE /*+ [APPEND | DIRECT(need_sort,max_error,load_type)] parallel(N) */ TABLE table_name [AS] select_sentence
CREATE TABLE 構文の詳細については、CREATE TABLE(MySQLモード)およびCREATE TABLE(Oracleモード)を参照してください。
パラメータの説明:
パラメータ |
説明 |
|---|---|
| APPEND | 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ステートメントのヒントを指定します。APPENDヒントを使用してデータをダイレクトロードします。obclient [test]> CREATE /*+ append parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;DIRECTヒントを使用してデータをダイレクトロードします。obclient [test]> CREATE /*+ direct(true, 0, 'full') parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;
CREATE TABLE AS SELECTステートメントのヒントを指定しません。パラメータ
default_load_modeの値をFULL_DIRECT_WRITEに設定します。obclient [test]> ALTER SYSTEM SET default_load_mode ='FULL_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ステートメントのヒントを指定します。APPENDヒントを使用してデータをダイレクトロードします。obclient [SYS]> CREATE /*+ append parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;DIRECTヒントを使用してデータをダイレクトロードします。obclient [SYS]> CREATE /*+ direct(true, 0, 'full') parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;
CREATE TABLE AS SELECTステートメントでヒントを指定しません。default_load_modeの値をFULL_DIRECT_WRITEに設定します。obclient [SYS]> ALTER SYSTEM SET default_load_mode ='FULL_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にデータがインポートされたことを示しています。