Oracleデータベースにアクセスする ~oracle_fdwを使いこなすために~

PostgreSQLには、PostgreSQLの外部にある様々なデータに対してアクセスするための仕組みとして、外部データラッパー(FDW: Foreign Data Wrapper)が用意されています。Oracleデータベースにアクセスするための外部データラッパーであるoracle_fdwの使い方については、「Oracleデータベースにアクセスする ~oracle_fdwの基本的な使い方~」で紹介しています。

今回は、oracle_fdwをより効果的に利用するためのポイントについて解説します。
なお、確認に使用した環境は、PostgreSQL 11.1、oracle_fdw 2.1.0、Oracle Instant Client 18.5(OCIライブラリー)、Oracle Database 18c XEです。

1. プッシュダウン(push down)の仕組み

外部データラッパーには、プッシュダウンという機構があり、oracle_fdwにも備わっています。この機構は、クライアントから問合せのあったSQL文に含まれるWHERE句(検索条件)、ORDER BY句(ソート条件)、および、JOIN句(結合条件)の処理を、リモート側で実行させます。なお、WHERE句とJOIN句については、ローカルとリモートとの間のデータ転送量を抑え、通信におけるボトルネックを減少させる効果があります。例えば、外部テーブルの1000件のデータに対してWHERE句で10件に絞り込むようなSELECT文を実行する場合、Oracle側で絞り込みを行い、その結果をPostgreSQL側に送信することで、通信量を100分の1に抑えることができます。
以下に、WHERE句、ORDER BY句、および、JOIN句のプッシュダウンについて、利用上のポイントを解説します。

1.1 WHERE句のプッシュダウン

問合せのSQL文にWHERE句があると、WHERE句に記述されたステートメントがOracleデータベースに渡され、実行されます。その際に注意が必要な点は、WHERE句のステートメントに関数が使われていると、その関数もOracle側で実行されることです。PostgreSQLとOracleデータベースでは、同じ関数名であっても仕様に違いがある場合があります。そのため、WHERE句のステートメントに関数がある場合は、Oracle側の関数仕様を確認しておく必要があります。

ここで、EXPLAINコマンドで実行計画を出力することで、WHERE句がプッシュダウンされることを確認してみます。なお、ANALYZEおよびVERBOSEオプションを指定することにより、Oracle側で実行されるSQL文(Oracle query:)と実行計画(Oracle plan:)も出力します。「Foreign Scan」ブロックがOracle側のテーブルに対する実行計画であり、「Oracle query:」にWHERE句があり、「Oracle plan:」のところに検索条件があることから、WHERE句に記述されたステートメントがOracle側で実行されていることを確認できます。

ソースコード1

次に、WHERE句のステートメントにRPAD関数を使用したときの実行結果を見てみます。この関数は、OracleデータベースとPostgreSQLにおいて、マルチバイト文字を使用した場合の実行結果が異なります。以下のSQL文のように、WHERE句ステートメントに、PostgreSQLの仕様を意識して「RPAD(name, 8, '*') = 'あいう*****'」と指定しても、このSQL文が実行されるときにWHERE句ステートメントがプッシュダウンされるため、RPAD関数はOracle側で実行されます。nameカラムに「あいう」というデータが存在しているとき、RPAD(name, 8, '*')の実行結果は「あいう**」になり、WHERE句の条件に合いません。そのため、このSQL文の実行結果は0行になります。

ソースコード2

1.2 ORDER BY句のプッシュダウン

Loading component...

Loading component...

Loading component...

Loading component...

Loading component...

1.3 JOIN句のプッシュダウン

問合せのSQL文にJOIN句があると、JOIN句に記述されたステートメントがOracleデータベースに渡され、Oracle側で結合が実行される場合があります。JOIN句のプッシュダウンには、以下の制約などがあるため、確認しておく必要があります。

Loading component...

Loading component...

Loading component...

Loading component...

Loading component...

2. 更新トランザクションの利用

Loading component...

  • 外部テーブルを同時更新しないようにする
  • 例外「シリアライズの失敗 SQLSTATE(40001)」が発生したら、ROLLBACKして、再度トランザクションを実行する(Oracle側のエラー:「ORA-08177: can't serialize access for this transaction」)

Loading component...

またoracle_fdwは、プリペアドステートメント(PREPARE)、および、2相コミット(PREPARE TRANSACTIONなど)については、Oracleデータベースを含む制御が必要になるため、サポートしていません。

3. データ型の違い

Loading component...

Loading component...

Loading component...

Loading component...

4. 外部テーブル定義の制約とデフォルト値

Loading component...

4.1 制約チェックとデフォルト値適用のタイミング

Loading component...

Loading component...

Loading component...

参考

図2のINSERT文の制約違反エラーのメッセージを示します。DETAILに「ORA-01400:」があることから、Oracleデータベース側でエラーが発生していることが分かります。

Loading component...

4.2 推奨に従わない場合の問題点

外部テーブルを定義する際に、制約やデフォルト値を、連携先のOracle側のテーブル定義の設定に合わせて指定しなかった場合、以下のような問題が発生する場合があるため、注意が必要です。

Loading component...

Loading component...

Loading component...

Loading component...

5. その他の利用時のポイント

oracle_fdwを利用する上での、その他のポイントを以下に示します。

Loading component...

oracle_fdwを実際に利用することを想定し、考慮すべきいくつかの重要な点について解説しました。詳細な点については、oracle_fdwのドキュメントを参照の上、ご利用ください。

2020年3月27日公開

こちらもおすすめ

Loading component...

Loading component...

富士通のソフトウェア公式チャンネル(YouTube)

富士通のミドルウェア製品のご紹介や各種イベント・セミナーの講演内容、デモンストレーションなどの動画をご覧いただけます。

Loading component...

Loading component...