本記事では、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ステートメントで指定パーティションのダイレクトロードを使用する場合は、ターゲットテーブルはレプリケーションテーブルであってはならず、自動インクリメント列、識別列、Global Indexを含むことはできません。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つの書き込み操作ステートメントを実行できません(つまり、同じテーブルに同時に書き込むことはできません)。インポート中はテーブルがロックされて、インポート中はずっと読み取り操作のみ可能だからです。
- トリガー(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() | Hint を使用してダイレクトロード機能を有効にします。
|
| 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を設定する場合は、ローカルソケット接続を介してデータベースに接続し、このグローバル変数を変更する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を設定する場合は、ローカルソケット接続を介してデータベースに接続し、このグローバル変数を変更する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ステートメントは、append/direct() ヒントと enable_parallel_dml ヒントを使用することにより、ダイレクトロードを実行します。ヒントが指定されていない場合は、構成パラメータ default_load_modeに基づいてデータのインポート動作を決定します。
使用制限
- PDML (Parallel Data Manipulation Language、並列データ操作言語)のみがサポートされています。非PDMLではダイレクトロードを使用できません。並列DMLの詳細については、並列DMLを参照してください。
- インポート中は同時に2つの書き込み操作ステートメントを実行できません(つまり、同じテーブルに同時に書き込むことはできません)。インポート中はテーブルがロックされて、インポート中はずっと読み取り操作のみ可能だからです。
- ダイレクトロードは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 | データをロードする際の並列度。
説明一般的に、並列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ステートメントのヒントを指定します。パーティションを指定しないインポート。
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ステートメントでヒントを指定しません。構成パラメータ
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です。一次パーティションを指定してフルダイレクトロードを行います。
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, '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ステートメントのヒントを指定します。パーティションを指定しないインポート。
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ステートメントでヒントを指定しません。構成パラメータ
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です。一次パーティションを指定してフルダイレクトロードを行います。
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, '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にデータがインポートされたことを示しています。