embulk-output-oracleを高速化したので使い方についてまとめる
embulk-output-oracleを劇的に高速化した0.2.2がリリースされたので、使い方について書いてみる。
どのくらい速くなったかは改めてまとめる予定だけど、これに沿った感じになると思う。
3つの挿入モード
READMEにも書いたけど、embulk-output-oracleには
- normal
- direct
- oci
の3つの挿入モードがあり、insert_methodで指定する。
normal
"normal"は文字通り、通常のINSERT文による挿入。
direct
"direct"は、ダイレクト・パス・インサートにより挿入する。これは、いろいろ制約があるものの通常のINSERTより高速だ(SQL*Loaderに近い)。
ちなみに、INSERT文に/* APPEND_VALUES */ヒントを付けることにより、ダイレクト・パス・インサートにすることができる。
oci
"oci"は、Oracleのネイティブクライアント(Oracle Instant Client)をOCI(Oracle Call Interface)を経由で使ってダイレクト・パス・インサートを実行する。JDBC経由の"direct"よりさらに高速だ。
なお、"oci"を使う場合でも、データベースのメタ情報の取得などにJDBCを使うので、JDBCドライバは必須だ。
接続の設定
host、port、database、user、passwordを指定する。
host、port、databaseの代わりに、urlを指定してもよい。
ただし、insert_methodが"oci"の場合は、url指定でもhost、port、databaseは必須だ。OCIでの接続にこれらが必要だからだ。
JDBCドライバ
embulk-output-oracleはJDBCドライバを同梱していないので、別途ダウンロードする必要がある。
driver_pathに、ドライバのパスを指定する。
動作するバージョンについては、後述。
データ型
データ型については、0.2.1のときと変わっていないので、こちらを参照。
ymlのサンプル
ymlのサンプルはこんな感じ。
in: type: file path_prefix: '/data/example.csv' parser: charset: UTF-8 newline: CRLF type: csv delimiter: ',' columns: - {name: ID, type: string} - {name: VARCHAR2_ITEM, type: string} - {name: INTEGER_ITEM, type: long} - {name: NUMBER_item, type: string} - {name: DATE_ITEM, type: timestamp, format: '%Y/%m/%d'} - {name: TIMESTAMP_ITEM, type: timestamp, format: '%Y/%m/%d %H:%M:%S'} out: type: oracle host: localhost database: TESTDB user: TEST_USER password: test_pw table: EXAMPLE mode: insert insert_method: direct driver_path: /drivers/ojdbc7.jar
embulk-input-filesplitにより更に高速化
入力がテキストファイルの場合は、embulk-input-filesplitによりマルチスレッドでファイルを読み込むことにより、更に高速化する。
ymlのサンプルはこんな感じ。
in: type: filesplit path: '/data/example.csv' parser: charset: UTF-8 newline: CRLF type: csv delimiter: ',' columns: - {name: ID, type: string} - {name: VARCHAR2_ITEM, type: string} - {name: INTEGER_ITEM, type: long} - {name: NUMBER_item, type: string} - {name: DATE_ITEM, type: timestamp, format: '%Y/%m/%d'} - {name: TIMESTAMP_ITEM, type: timestamp, format: '%Y/%m/%d %H:%M:%S'} out: type: oracle host: localhost database: TESTDB user: TEST_USER password: test_pw table: EXAMPLE mode: insert insert_method: direct driver_path: /drivers/ojdbc7.jar
動作環境について
全ての組み合わせで動作確認を行うことはできていないが、とりあえず分かってる範囲で書いてみる。
サーバ側は12cで確認したが、前のバージョンでも動くと思う。たぶん。
normal(通常のINSERT)
12cのJDBCドライバ、11gR2のJDBCドライバでは正常に動作したが、11gR1のJDBCドライバでは以下のエラーが発生した。
Caused by: java.sql.BatchUpdateException: ORA-00928: SELECTキーワードがありません。 at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:629) at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:9409) at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:211) at org.embulk.output.jdbc.StandardBatchInsert.flush(StandardBatchInsert.java:64)
10gのJDBCドライバではそもそも接続できなかった(Java1.4の時代のだし…)。
direct(ダイレクト・パス・インサート)
12cのJDBCドライバで以下のエラーが発生。11gR2、11gR1のJDBCドライバでは正常に動作した。
Caused by: java.lang.ArrayIndexOutOfBoundsException at java.lang.System.arraycopy(Native Method) at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:12208) at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:246) at org.embulk.output.jdbc.StandardBatchInsert.flush(StandardBatchInsert.java:64)
oci(OCIによるダイレクト・パス・インサート)
"oci"では、embulk-output-oracle側もネイティブライブラリが必要になる。とりあえずWindows(x68-64)用とLinux(x68-64)用しか同梱していないので…、他の環境の人はここの下にあるビルドスクリプトを参考にご自分でビルドしてください。。
また、"oci"を使うにはOracle Instant Clientをインストールする必要がある。
Windowsの場合はPATH、Linuxの場合はLD_LIBRARY_PATHを設定する。
また、Linuxの場合は
ln -s libclntsh.so.12.1 libclntsh.so ln -s libocci.so.12.1 libocci.so
も必要。embulk-output-oracleのネイティブライブラリは11gのライブラリを使ってビルドしているので、12cのクライアントを使う人は更に
ln -n libocci.so.12.1 libocci.so.11.1 ln -n libclntsh.so.12.1 libclntsh.so.11.1
も必要。
動作確認したところでは、11gR1のLinux版のクライアントで
Caused by: java.sql.SQLException: OCI : OCIDirPathPrepare failed. ORA-01009: missing mandatory parameter at org.embulk.output.oracle.oci.OCIWrapper.throwException(OCIWrapper.java:74) at org.embulk.output.oracle.oci.OCIWrapper.prepareLoad(OCIWrapper.java:40) at org.embulk.output.oracle.oci.OCIManager.open(OCIManager.java:34)
というエラーが発生した。
まとめると、こんな感じ。
モード | バージョン | ||
---|---|---|---|
11gR1 | 11gR2 | 12c | |
normal | × | ○ | ○ |
direct | ○ | ○ | × |
oci | ○ | ○ | Linuxは× |
結構×があるな…。
まとめ
embulk-output-oracle(0.2.2)では、通常のINSERTの他に、ダイレクト・パス・インサート、OCIによるダイレクト・パス・インサートもできるようになった。
OCIはちょっと環境構築が面倒だけどこの中で最速で、embulk-input-filesplitを組み合わせると更に高速化するのでお勧め。
どのくらい速くなるかは、近いうちに改めてまとめる予定。
あと、embulk-output-jdbcのcommitterになりました。
Embulk | 0.5.4 |
embulk-output-oracle | 0.2.2 |
2015/4/17: ymlファイル中のcolumnsのnameを小文字から大文字に修正しました。Oracle上のカラム名はおそらく大文字の場合が多いと思いますが、大文字/小文字も含めてカラム名が一致しないと無視されてしまいます。