<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Oracle &#8211; SRA OSS Tech Blog</title>
	<atom:link href="https://www.sraoss.co.jp/tech-blog/tag/oracle/feed/index.xml" rel="self" type="application/rss+xml" />
	<link>https://www.sraoss.co.jp/tech-blog/</link>
	<description>OSS専門の技術ブログ。PostgreSQL、Zabbixを中心に10種類以上のOSSの解説、アップデート情報、運用ヒントを提供。</description>
	<lastBuildDate>Wed, 04 Nov 2026 06:58:03 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>

<image>
	<url>https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2018/07/blog-icon-150x150.png</url>
	<title>Oracle &#8211; SRA OSS Tech Blog</title>
	<link>https://www.sraoss.co.jp/tech-blog/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>YugabyteDB Voyager の紹介</title>
		<link>https://www.sraoss.co.jp/tech-blog/yugabytedb/yugabytedb-voyager-intro/</link>
		
		<dc:creator><![CDATA[三和 陽菜 (Haruna Miwa)]]></dc:creator>
		<pubDate>Wed, 24 Jun 2026 06:01:04 +0000</pubDate>
				<category><![CDATA[YugabyteDB]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[OSS]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[Voyager]]></category>
		<category><![CDATA[マイグレーション]]></category>
		<category><![CDATA[分散SQL]]></category>
		<category><![CDATA[移行]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=20755</guid>

					<description><![CDATA[YugabyteDB Voyagerは、YugabyteDBへの移行を支援するツールです。移行可否のアセスメントから、スキーマ移行、データ移行まで、データベース移行に必要な操作全般を管理することができます。 本稿では、ま ...]]></description>
										<content:encoded><![CDATA[<p>YugabyteDB Voyagerは、YugabyteDBへの移行を支援するツールです。移行可否のアセスメントから、スキーマ移行、データ移行まで、データベース移行に必要な操作全般を管理することができます。<br />
本稿では、まずYugabyteDB Voyagerの概要について解説し、さらに移行方式の一つであるオフラインマイグレーションについて、具体的な操作方法を解説します。</p>
<p><span id="more-20755"></span></p>
<h1>概要</h1>
<p>YugabyteDB Voyagerは、無料かつオープンソースのYugabyteDB移行ツールです。PostgreSQL、Oracle、MySQLといった主要なデータベースを移行元としてサポートしており、オンプレミス環境・クラウド環境のどちらでも使用可能なため、さまざまなシステム構成からの移行に対応できます。また、すべてのYugabyteDB製品を移行対象としてサポートしています。</p>
<p>YugabyteDB Voyagerは、YugabyteDBに移行するにあたりどの程度修正が必要な箇所があるかをリストアップし、移行可能かどうかのアセスメントを支援します。また、実際に移行すると決定した際には、テーブル定義やインデックス定義については自動で変換を行い、移行に必要な労力を最小限に抑えます。データ移行の際にはチューニングを行い、インポートパフォーマンスの向上を自動で行います。</p>
<p>さらに、ソースデータベースとしてPostgreSQLを使用する場合、データベース停止が必要なオフラインマイグレーションの他に、ダウンタイムを最小限に抑えるライブマイグレーションが利用可能です。ビジネスクリティカルなアプリケーションにおいて、YugabyteDBへの移行を強力に支援します。</p>
<h1>移行方式</h1>
<p>YugabyteDB Voyagerで利用可能な移行方式は以下の通りです。</p>
<table>
<thead>
<tr>
<th>移行方式</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td>オフラインマイグレーション</td>
<td>アプリケーションを停止した状態でデータを移行する方式です。</td>
</tr>
<tr>
<td>ライブマイグレーション</td>
<td>アプリケーションを停止せずにデータを移行する方式です。データをエクスポートする際、まずはある時点を基準としたスナップショットを取得します。それ以降に発生したデータ更新は、ディスク上のイベントキューに保管します。データをインポートする際はまず、スナップショットをインポートします。その後、イベントキューに保管されているデータの変更処理を反映させます。</td>
</tr>
<tr>
<td>フォールフォワード付きライブマイグレーション</td>
<td>ライブマイグレーションの際、移行元のDBにレプリカデータベースを用意します。YugabyteDBへの移行後、移行元DBは停止しますがレプリカデータベースには変更を反映し続けます。移行後、うまくいかなかった場合にはレプリカデータベースへ切り戻すことができます。</td>
</tr>
<tr>
<td>フォールバック付きライブマイグレーション</td>
<td>YugabyteDBへ移行した後、データの変更があった場合には移行元DBへも変更を反映させます。移行後、うまくいかなかった場合には元のDBへ切り戻すことができます。</td>
</tr>
</tbody>
</table>
<h1>オフラインマイグレーション</h1>
<p>今回は、PostgreSQLからYugabyteDBへのオフラインマイグレーションを実行してみます。<br />
環境は以下の通りです。</p>
<table>
<tbody>
<tr>
<th>OS</th>
<td>Rocky Linux release 9.7 (Blue Onyx)</td>
</tr>
<tr>
<th>PostgreSQL</th>
<td>17.9</td>
</tr>
<tr>
<th>YugabyteDB</th>
<td>2024.2.2.0</td>
</tr>
<tr>
<th>YugabyteDB Voyager</th>
<td>2026.3.1</td>
</tr>
</tbody>
</table>
<p>今回は移行元データベースとしてPostgreSQLサーバ1台、移行先データベースとしてYugabyteDB3台のクラスタ構成を構築しています。<br />
各サーバの情報は以下の通りです。</p>
<table>
<tbody>
<tr>
<th></th>
<th>PostgreSQL</th>
<th>YugabyteDB#1</th>
<th>YugabyteDB#2</th>
<th>YugabyteDB#3</th>
</tr>
<tr>
<td>IPアドレス</td>
<td>172.20.0.15</td>
<td>172.20.0.11</td>
<td>172.20.0.12</td>
<td>172.20.0.13</td>
</tr>
</tbody>
</table>
<p>今回はPostgreSQLサーバ、YugabyteDBクラスタの構築手順については記載を省略します。YugabyteDBクラスタの構築については<a href="https://www.sraoss.co.jp/tech-blog/yugabytedb/yugabytedb-oss/">YugabyteDB OSS版の使い方</a>、<a href="https://www.sraoss.co.jp/tech-blog/yugabytedb/yugabytedb-aeon-self-managed/">YugabyteDB Aeon Self-Managed (旧 YugabyteDB Anywhere) の使い方</a>も参考にしてください。</p>
<h2>YugabyteDB Voyagerのインストール</h2>
<p>まず、YugabyteDB Voyagerをインストールします。<br />
<a href="https://docs.yugabyte.com/stable/yugabyte-voyager/install-yb-voyager/" target="_blank" rel="noopener">公式ドキュメント</a>の手順に従って、インストールしてください。<br />
本稿ではPostgreSQLサーバにYugabyteDB Voyagerをインストールしています。</p>
<h2>ソースデータベースに対する事前準備</h2>
<p>まず、ソースデータベース(PostgreSQL)にマイグレーション用のユーザを作成します。マイグレーション用ユーザは移行対象のすべてのリソースに対してREAD権限を持っている必要があります。</p>
<p>今回はybvoyagerユーザを作成します。<br />
ソースデータベースに接続し、以下のSQLを実行しました。</p>
<pre>CREATE USER ybvoyager PASSWORD 'password';</pre>
<p>次に、必要な権限を与えます。移行対象のデータベースに接続し、/opt/yb-voyager/guardrails-scripts/以下にある yb-voyager-pg-grant-migration-permissions.sql を実行します。</p>
<pre>psql -h 172.20.0.15 \
     -d db1 \
     -U postgres \
     -v voyager_user='ybvoyager' \
     -v schema_list='public' \
     -v is_live_migration=0 \
     -v is_live_migration_fall_back=0 \
     -f /opt/yb-voyager/guardrails-scripts/yb-voyager-pg-grant-migration-permissions.sql</pre>
<p>これで、ソースデータベースに対する準備は完了しました。</p>
<h2>ターゲットデータベースに対する事前準備</h2>
<p>ターゲットデータベース(YugabyteDB)に移行先のデータベースを用意します。<br />
移行先のデータベース名はソースデータベースと同じ名前でも異なる名前でも問題ありません。(以降のyb-voyagerコマンド実行時に、データベース名を指定しない場合、yb-voyagerは移行先データベースを yugabyte データベースとみなします。)<br />
移行先データベース名をyugabyteから変更したい場合は、YugabyteDB クラスタにデータベースを作成してください。</p>
<pre>CREATE DATABASE db1 WITH COLOCATION = true;</pre>
<p>次に、ターゲットデータベースについてもマイグレーション用ユーザを作成します。スーパーユーザとして作成する必要があります。<br />
今回はybvoyagerユーザを作成しました。</p>
<pre>CREATE USER ybvoyager SUPERUSER PASSWORD 'password';</pre>
<h2>エクスポートディレクトリの設定</h2>
<p>yb-voyagerはすべてのマイグレーションの状態をエクスポートディレクトリに書き出します。これは、Voyagerが使用するメタデータに加えて、スキーマやデータのダンプも含まれます。そのため、ソースデータベース全体を格納できる、十分な空き容量のあるファイルシステム上にエクスポートディレクトリを作成してください。</p>
<pre>mkdir -p $HOME/yb-migrate/export-dir</pre>
<p>マイグレーションを実行すると、yb-voyagerによって、以下のディレクトリが作成されます。</p>
<p>assessment: アセスメント時のメタデータと、アセスメント結果を格納します。<br />
schema: ソースデータベースのスキーマがCSV形式で格納されます。<br />
data: ソースデータベースのデータがCSV形式で格納されます。<br />
metainfo/temp yb-voyagerが内部予約しているディレクトリです。<br />
logs: コマンド実行時のログファイルが格納されます。</p>
<h2>設定ファイルの用意</h2>
<p>yb-voyagerコマンドには、設定値を一括で記載する設定ファイルが用意されています。設定ファイルを使用すると、コマンド実行時に逐一パラメータを指定する必要がないため便利です。(v2025.6.2以降に導入された機能です。)</p>
<p>/opt/yb-voyager/config-templates以下にテンプレートファイルが提供されているので、このテンプレートファイルをコピーして使用します。今回はオフラインマイグレーション用のファイル(offline-migration.yaml)を使用します。</p>
<pre>cp /opt/yb-voyager/config-templates/offline-migration.yaml ~</pre>
<p>ファイル内の、エクスポートディレクトリに関する項目、ソースデータベースの接続情報、ターゲットデータベースへの接続情報を編集する必要があります。以下は設定例です。</p>
<pre>export-dir: /voyager/export-dir
yugabyted-control-plane:
  db-conn-string: postgresql://yugabyte:yugabyte@172.20.0.11:5433  
source:
  db-type: postgresql
  db-host: 172.20.0.15
  db-port: 5432
  db-name: db1
  db-schema: public
  db-user: ybvoyager
  db-password: password
target:
  db-host: 172.20.0.11
  db-port: 5433
  db-name: db1
  db-user: ybvoyager
  db-password: password
</pre>
<h2>マイグレーションのアセスメント</h2>
<p>以下のコマンドを実行して、マイグレーションのアセスメントを実施します。<br />
このとき、先ほど作成したYAMLファイルのパスを&#8211;config-fileに指定します。<br />
今回は、~/offline-migration.yamlを指定しています。</p>
<pre>yb-voyager assess-migration --config-file ~/offline-migration.yaml</pre>
<p>実行すると、評価レポートのパスがコンソールに出力されます。<br />
評価レポートはJSON形式とHTML形式で出力されます。以下はhtml形式の評価レポートです。</p>
<p><img fetchpriority="high" decoding="async" class="alignnone size-full wp-image-20773" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report.png" alt="" width="1857" height="997" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report.png 1857w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report-300x161.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report-1024x550.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report-768x412.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report-1536x825.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report-304x163.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-migration-assessment-report-282x151.png 282w" sizes="(max-width: 1857px) 100vw, 1857px" /></p>
<p>移行の難易度や、非互換のオブジェクトが存在しているかを確認することができます。</p>
<h2 id="スキーマのエクスポート">スキーマのエクスポート</h2>
<p>アセスメントが完了したら、次はソースデータベースからスキーマをエクスポートします。<br />
以下のコマンドを実行してください。</p>
<pre>yb-voyager export schema --config-file ~/offline-migration.yaml</pre>
<p>実行すると、エクスポートディレクトリのschemaディレクトリに、結果が保存されます。</p>
<p>スキーマのエクスポートの際に、yb-voyagerはスキーマ定義の調整を自動で行います。</p>
<h2>スキーマの分析</h2>
<p>スキーマのエクスポート時に、yb-voyagerはスキーマ定義の調整を自動で行います。しかし、自動調整だけではYugabyteDBへのインポートが失敗する可能性があります。YugabyteDBはPostgreSQLと互換性がありますが、分散システムであるため、スキーマに若干の手動変更が必要になります。</p>
<p>以下コマンドを実行し、スキーマを分析してください。</p>
<pre>yb-voyager analyze-schema --config-file ~/offline-migration.yaml</pre>
<p>手動変更が必要なDDLステートメント一覧を表示するレポートを出力します。</p>
<p><img decoding="async" class="alignnone size-full wp-image-20769" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report.png" alt="" width="1857" height="998" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report.png 1857w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report-300x161.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report-1024x550.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report-768x413.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report-1536x825.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report-304x163.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/06/yugabyte-voyager-schema-analysis-report-282x152.png 282w" sizes="(max-width: 1857px) 100vw, 1857px" /></p>
<h3>スキーマの手動修正</h3>
<p>生成されたレポートに記載のあるすべての問題について、EXPORT_DIR/schema/以下にある、対象のDDLを修正してください。手動で修正を加えたら、yb-voyager analyze-schema コマンドを再実行してください。変更内容を反映した新しいレポートが生成されます。生成されたレポートに問題がなくなるまで、この手順を繰り返す必要があります。</p>
<h2>スキーマのインポート</h2>
<p>スキーマの修正が完了したら、ターゲットデータベースにスキーマをインポートします。</p>
<pre>yb-voyager import schema --config-file ~/offline-migration.yaml</pre>
<p>yb-voyagerコマンドは、エクスポートディレクトリのschemaサブディレクトリにあるDDL を、ターゲットのYugabyteDBデータベースに適用します。もし、スキーマのインポートが途中で異常終了してしまった場合は、設定ファイルのignore-existパラメータをtrueに変更してから再実行してください。すでに作成に成功したオブジェクトは無視するようになります。</p>
<h2 id="データのエクスポート">データのエクスポート</h2>
<p>スキーマ移行が完了したら、次はデータ移行を行います。まずは、ソースデータベースからデータをエクスポートします。</p>
<pre>yb-voyager export data --config-file ~/offline-migration.yaml</pre>
<p>このコマンドは、EXPORT_DIR/data以下にCSV形式でデータをダンプします。</p>
<h3>注意事項</h3>
<p>データエクスポートの際は、以下の点に注意してください。</p>
<ul>
<li>PostgreSQLの場合、ソースデータベース上でロックを獲得しようとしている他のプロセスが存在しないことを確認してください。並列ジョブが複数ある場合、データをダンプすることはできません。</li>
<li>シーケンスの移行は、シーケンスの作成とレジューム値の設定という2つのステップで構成されています。レジューム値はデータのエクスポート時に生成されます。また、すべてのテーブルデータがインポートされた直後に、ターゲットのYugabyteDBデータベースにこれらのレジューム値は設定されます。PostgreSQLの場合、移行対象テーブルに紐づけられている、または、テーブルが所有するシーケンスのみが移行時に復元されます。</li>
<li>ソースデータベース上のテーブルの行サイズが大きすぎて、デフォルトのRPCメッセージサイズを超えている場合、インポートデータは「ERROR: Sending too long RPC message&#8230;」というエラーで失敗します。そのため、行サイズが大きいテーブルは、該当箇所を削除してから個別に移行する必要があります。</li>
</ul>
<h2>データのインポート</h2>
<p>データをエクスポートできたら、次はターゲットデータベースにデータをインポートします。</p>
<pre>yb-voyager import data --config-file ~/offline-migration.yaml</pre>
<p>進行状況を確認したい場合は、yb-voyager import data statusを実行してください。</p>
<p>デフォルトでは、yb-voyagerは複数の接続を使用して並列にデータをインポートします。並列度はクラスタのリソース使用状況に基づいて判断されます。</p>
<p>yb-voyagerは、データダンプファイル(EXPORT_DIR/data)をより小さなバッチに分割します。yb-voyagerは、ターゲットのYugabyteDBデータベースクラスタのすべてのノードが使用されるように、バッチを同時に取り込みます。このフェーズは、データインポート中にyb-voyagerが終了した場合でも再開できるように設計されています。再開後、データのインポートは処理が中断された地点から続行されます。</p>
<h3>注意事項</h3>
<p>データインポートの際は、以下の点に注意してください。</p>
<ul>
<li>大規模データセットをインポートする場合は、ターミナルセッションが終了してもインポート処理が中断されないように、screenセッションでimport dataを実行してください。</li>
<li>yb-voyagerのimport dataコマンドがデータ取り込み完了前に終了した場合は、同じ引数で再度実行すれば、データインポート処理が再開されます。</li>
</ul>
<h2>データインポート後のスキーマ調整</h2>
<p>ソースデータベースにNOT VALID制約がある場合は、データインポート後に制約を作成するコマンドを実行する必要があります。</p>
<pre>yb-voyager finalize-schema-post-data-import --config-file ~/offline-migration.yaml</pre>
<h2>マイグレーションの検証</h2>
<p>スキーマとデータのインポートが完了したら、データが正しく移行されていることを確認します。<br />
ソースデータベースとターゲットデータベース(YugabyteDB)の両方で検証用クエリを手動で実行して確認を行います。<br />
例えば、各テーブルの行数を確認するクエリを実行して行数がそろっているかどうかの確認を行ってください。</p>
<h2 id="マイグレーションの終了">マイグレーションの終了</h2>
<p>データが正しく移行されていることを確認できたら、移行する際に作成されたディレクトリ・データをクリーンアップします。<br />
yb-voyager end migration コマンドで、クリーンアップを実行します。</p>
<pre>yb-voyager end migration --config-file ~/offline-migration.yaml</pre>
<p>必要であれば、移行に使用したybvoyagerユーザの削除も行ってください。<br />
yb-voyagerで移行を実施すると、移行されたすべてのオブジェクトはybvoyagerユーザが所有している状態となります。<br />
オブジェクトの所有者を別のユーザに変更してから、ybvoyagerユーザを削除してください。</p>
<h1>終わりに</h1>
<p>本稿ではYugabyteDBへのマイグレーション支援ツール YugabyteDB Voyagerの使用方法を紹介しました。<br />
YugabyteDBはPostgreSQL互換データベースであるとはいえ、アーキテクチャが異なりますので、移行する際はスキーマ定義の修正が必要になります。<br />
YugabyteDB Voyagerは、スキーマ定義の互換性の評価から実施できますので、マイグレーションを行う際の強力なツールとなります。<br />
YugabyteDBへの移行を検討している方は、ぜひYugabyteDB Voyagerをご活用ください。</p>
<h1>参考</h1>
<p><a href="https://docs.yugabyte.com/stable/yugabyte-voyager/">YugabyteDB Voyager 公式ドキュメント</a></p>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/consulting/yugabytedb/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-yugabyte" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、YugabyteDB のコンサルティングサービスを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Ora2Pg (Oracle/PostgreSQLマイグレーションツール)</title>
		<link>https://www.sraoss.co.jp/tech-blog/pgsql/ora2pg/</link>
		
		<dc:creator><![CDATA[データベース技術グループ]]></dc:creator>
		<pubDate>Thu, 20 Aug 2020 03:54:36 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[Ora2Pg]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[サードパーティーソフトウェア]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=6271</guid>

					<description><![CDATA[本記事では、このOra2Pgを実行できる環境の構築方法と、実際にOra2Pgを実行し、Oracle12cからPostgreSQL用に変換されたオブジェクト定義など作成した結果をお伝えしたいと思います。 Ora2Pgの概要 ...]]></description>
										<content:encoded><![CDATA[<p>本記事では、このOra2Pgを実行できる環境の構築方法と、実際にOra2Pgを実行し、Oracle12cからPostgreSQL用に変換されたオブジェクト定義など作成した結果をお伝えしたいと思います。</p>
<p><span id="more-6271"></span></p>
<h2>Ora2Pgの概要</h2>
<p>Ora2Pgとは、Perlで実装されているオープンソースソフトウェアで、OracleまたはMySQLからPostgreSQLへのマイグレーションツールです。<br />
最新バージョンは2019/01/18にリリースされたVersion20.0となっています（2020年6月時点）。</p>
<p>公式サイトは<a href="https://ora2pg.darold.net/" target="_blank" rel="noopener noreferrer">こちら</a>です。</p>
<h3>Ora2Pgでできること</h3>
<p>Ora2Pgで具体的にできることは下記の3つです。</p>
<h4>1. オブジェクト定義の移行</h4>
<p>変換元データベースに接続してオブジェクト情報を参照し、PostgreSQL用のDDLを作成できます。<br />
また、変換元データベースに接続してオブジェクト情報を参照し、変換先のPostgreSQLへ直接（ファイルなどを作成せずに）オブジェクトを作成することもできます。</p>
<h4>2. データの移行</h4>
<p>変換元データベースに接続して情報を参照し、データ移行用のDMLを作成できます。<br />
また、変換元データベースに接続してオブジェクト情報を参照し、変換先のPostgreSQLへ直接（ファイルなどを作成せずに）データを移行することもできます。</p>
<h4>3. SQLの変換</h4>
<p>変換元データベースで実行できる形式のSQLを、PostgreSQLで実行できる形式のSQLに変換できます。</p>
<h3>Ora2Pg稼働環境の構築</h3>
<p>CentOS7にOra2Pgをインストールし、Oracle12cからPostgreSQL12へオブジェクト定義とデータの移行をおこなってみます。</p>
<h4>環境の用意</h4>
<p>Vagrantを利用してOracle Virtual Box上に3つの仮想環境を用意しました。</p>
<ol>
<li>Oracle12c 稼働環境（マイグレーションを想定して少し古いバージョンのOracleを用意しています）</li>
<li>PostgreSQL12 稼働環境</li>
<li>Ora2Pg 稼働環境</li>
</ol>
<p>今回はOra2Pgの紹介ですので、Oracle12c稼働環境とPostgreSQL12稼働環境の構築については、対象外とさせていただいています。<br />
また、Oracle12cにはオラクル社が用意しているサンプルスキーマHuman Resource (HR)が格納されています。</p>
<h3>Ora2Pgをソースコードからインストール</h3>
<p>Ora2Pgは公式サイトからソースコードをダウンロードし、インストールを行います。<br />
公式サイト上に詳しいインストール方法が記載されていますので、まずはその<a href="https://ora2pg.darold.net/documentation.html#INSTALLATION" target="_blank" rel="noopener noreferrer">ドキュメント</a>に沿ってOra2Pgが動作する環境を構築します。</p>
<h4>OracleInstantClientのインストール</h4>
<p>最初に、Ora2Pg本体をインストールするために必要となるライブラリ群をインストールします。<br />
今回はOracle12cを変換元のデータベースとしているため、OracleInstantClientをインストールして、Oracle12cデータベースへ接続できるようにします。<br />
OracleInstantClientは<a href="https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html" target="_blank" rel="noopener noreferrer">Oracle Technology Network（OTN）サイト</a>からダウンロードします。<br />
※ダウンロードにはOTNサイトへのユーザ登録が必要です。</p>
<p>変換元のOracle12cとバージョンを合わせるため、OracleInstantClientも12cの各種rpmをダウンロードしました。</p>
<ul>
<li>oracle-instantclient12.2-basic-12.2.0.1.0-1.x86_64.rpm</li>
<li>oracle-instantclient12.2-devel-12.2.0.1.0-1.x86_64.rpm</li>
<li>oracle-instantclient12.2-jdbc-12.2.0.1.0-1.x86_64.rpm</li>
<li>oracle-instantclient12.2-sqlplus-12.2.0.1.0-1.x86_64.rpm</li>
</ul>
<p>次に、OracleInstantClientのインストールに必要なライブラリをインストールします。</p>
<pre># yum install libaio
</pre>
<p>その後、OracleInstantClientをインストールします。</p>
<pre># rpm -ivh oracle-instantclient12.2-basic-12.2.0.1.0-1.x86_64.rpm
# rpm -ivh oracle-instantclient12.2-devel-12.2.0.1.0-1.x86_64.rpm
# rpm -ivh oracle-instantclient12.2-jdbc-12.2.0.1.0-1.x86_64.rpm
# rpm -ivh oracle-instantclient12.2-sqlplus-12.2.0.1.0-1.x86_64.rpm
</pre>
<p>最後にインストールしたOracleInstantClientのライブラリを共有ライブラリの検索パスに含めます。</p>
<pre># echo '/usr/lib/oracle/12.2/client64/lib' &gt; /etc/ld.so.conf.d/oracle.conf
# ldconfig
</pre>
<p>これでOra2Pg実行端末からOracleデータベースへ接続できるようになりました。</p>
<h3>Perlのインストール</h3>
<p>次はPerl関連のインストールです。Ora2PgをインストールするにはPerl（5.10以上）が必要となります。</p>
<pre># perl -v

This is perl 5, version 16, subversion 3 (v5.16.3) built for x86_64-linux-thread-multi
(with 40 registered patches, see perl -V for more detail)

Copyright 1987-2012, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.
</pre>
<p>CentOs7にデフォルトでインストール済みのものが5.16であったため、そのまま使います。<br />
※ 5.10未満の場合はPerlのアップデートが必要です。</p>
<h4>Perlモジュールのインストール</h4>
<p>Ora2PgからOracleデータベースへ接続するためにDBD::Oracleをインストールすることから始めます。<br />
DBD::OracleはCPANからインストールするので、先にCPANをインストールします。</p>
<pre># yum install perl-CPAN
</pre>
<p>次に、DBD::Oracleのインストールに必要な環境変数を設定します。</p>
<pre># export PERL5LIB=/usr/local/bin
# export LD_LIBRARY_PATH=/usr/lib/oracle/12.2/client64/lib
# export ORACLE_HOME=/usr/lib/oracle/12.2/client64/lib
</pre>
<p>その後、必要なモジュールをCPANからインストールします。</p>
<pre># perl -MCPAN -e 'install Test::NoWarnings'
# perl -MCPAN -e 'install DBI'
# perl -MCPAN -e 'install DBD::Oracle'
</pre>
<p>※ CPANの初回実行時に「設定についてどうするか？」を聞かれますが、すべてデフォルトで進め、自動的に設定してもらいました。</p>
<p>最後に、PerlでMakefileを作成するのに必要なライブラリをインストールします。</p>
<pre># yum install perl-ExtUtils-MakeMaker
</pre>
<h4>Ora2Pgのソースコードのダウンロード</h4>
<p>まずは作業ディレクトリを作成し、Ora2Pg本体をダウンロードします。<br />
今回はora2pgというユーザーを作成して、作業ユーザーとしています。</p>
<pre># useradd ora2pg
# su - ora2pg
$ mkdir workdir
$ cd workdir
</pre>
<p><a href="https://github.com/darold/ora2pg/releases/tag/v20.0" target="_blank" rel="noopener noreferrer">Ora2Pgのgithub</a>から最新版のVer20.0をダウンロードしました。<br />
作業ディレクトリにダウンロードしたファイルを格納し、解凍します。</p>
<pre>$ tar xzf ora2pg-20.0.tar.gz
</pre>
<h4>Ora2Pgのインストール</h4>
<p>root権限で解凍したディレクトリに移動して、インストールを実行します。</p>
<pre># cd /home/ora2pg/workdir/ora2pg-20.0/
# perl Makefile.PL
# make &amp;&amp; make install
</pre>
<p>/usr/local/bin ディレクトリにOra2Pgが無事にインストールされました。</p>
<pre>$ ls /usr/local/bin/ora2pg
/usr/local/bin/ora2pg
</pre>
<h2>Ora2Pgの実行</h2>
<p>Ora2Pgのインストールが無事に完了しましたので、さっそく実行してみたいと思います。</p>
<h3>ora2pg.confの編集</h3>
<p>Ora2Pgはora2pg.confという設定ファイルを読み込んで実行されます。<br />
設定ファイルのひな型は/etc/ora2pg/ora2pg.conf.distにありますので、作業フォルダにora2pg.confとしてコピーして編集します。</p>
<pre>$ cp /etc/ora2pg/ora2pg.conf.dist /home/ora2pg/workdir/ora2pg.conf
</pre>
<h4>Oracleへの接続設定</h4>
<p>ora2pg.conf内の下記3項目にOracle接続のための情報を設定します（viなどでora2pg.confを編集します）。</p>
<pre># Set Oracle database connection (datasource, user, password)
ORACLE_DSN      dbi:Oracle:host=oracle_host;sid=orcl;port=1521
ORACLE_USER     system
ORACLE_PWD      system_pass
</pre>
<p>※ ORACLE_USERにはDBA_OBJECTSを参照できる権限をもつユーザーを指定しないと、Ora2Pg実行時にエラーとなります。</p>
<h3>データ定義移行用のDDLの作成</h3>
<p>データ定義移行用のDDLを出力してみます。<br />
ora2pgコマンドに-cオプションをつけることでora2pg.confの場所を指定します。-cをつけない場合は/etc/ora2pg/ora2pg.confが自動的に参照されます。<br />
その他のオプションについては後述します。</p>
<pre>ora2pg -c ora2pg.conf -t TABLE -b ~/workdir/ -o ora2pg_TABLE.sql
</pre>
<h4>出力結果の確認</h4>
<p>出力ファイルの中身は下記のようなSQL文となっていました。</p>
<pre>-- Generated by Ora2Pg, the Oracle database Schema converter, version 20.0
-- Copyright 2000-2019 Gilles DAROLD. All rights reserved.
-- DATASOURCE: dbi:Oracle:host=ora;sid=orcl;port=1521

SET client_encoding TO 'UTF8';

\set ON_ERROR_STOP ON


CREATE TABLE countries (
        country_id char(2) NOT NULL,
        country_name varchar(40),
        region_id bigint
) ;
COMMENT ON TABLE countries IS E'country table. Contains 25 rows. References with locations table.';
COMMENT ON COLUMN countries.country_id IS E'Primary key of countries table.';
COMMENT ON COLUMN countries.country_name IS E'Country name';
COMMENT ON COLUMN countries.region_id IS E'Region ID for the country. Foreign key to region_id column in the departments table.';
ALTER TABLE countries ADD PRIMARY KEY (country_id);
.
.
.
</pre>
<p>プライマリキーの設定や、コメントなども作成されるようになっています（ora2pg.confで制御することもできます）。</p>
<h3>プロシージャの変換</h3>
<p>ストアドプロシージャも変換してみます。OracleのPL/SQL言語とPostgreSQLのPL/PgSQL言語の相違点については<a href="https://www.sraoss.co.jp/PostgreSQL/Manual/document/12/plpgsql-porting.html" target="_blank" rel="noopener noreferrer">マニュアル</a>にもまとめられていますので、参考にしてください。</p>
<pre>ora2pg -c ora2pg.conf -t PROCEDURE-b ~/workdir/ -o ora2pg_PROCEDURE.sql
</pre>
<h4>出力結果を確認</h4>
<p>出力ファイルの中身は下記のようなSQL文となっていました。</p>
<pre>-- Generated by Ora2Pg, the Oracle database Schema converter, version 20.0
-- Copyright 2000-2019 Gilles DAROLD. All rights reserved.
-- DATASOURCE: dbi:Oracle:host=ora;sid=orcl;port=1521

SET client_encoding TO 'UTF8';

\set ON_ERROR_STOP ON



CREATE OR REPLACE FUNCTION add_job_history ( p_emp_id job_history.employee_id%type , p_start_date job_history.start_date%type , p_end_date job_history.end_date%type , p_job_id job_history.job_id%type , p_department_id job_history.department_id%type ) RETURNS VOID AS $body$
BEGIN
  INSERT INTO job_history(employee_id, start_date, end_date,
                           job_id, department_id)
    VALUES (p_emp_id, p_start_date, p_end_date, p_job_id, p_department_id);
END;
$body$
LANGUAGE PLPGSQL
SECURITY DEFINER
;
-- REVOKE ALL ON FUNCTION add_job_history ( p_emp_id job_history.employee_id%type , p_start_date job_history.start_date%type , p_end_date job_history.end_date%type , p_job_id job_history.job_id%type , p_department_id job_history.department_id%type ) FROM PUBLIC;
.
.
.
</pre>
<p>PostgreSQL11からPostgreSQLでもプロシージャを作成することができるようになっていますが、FUNCTIONとして作成されるようです。</p>
<h3>データ移行用のDMLの作成</h3>
<p>次にデータ移行用のDMLを出力してみます。</p>
<pre>ora2pg -c ora2pg.conf -t INSERT -b ~/workdir/ -o ora2pg_INSERT.sql
</pre>
<h4>出力されたファイルの確認</h4>
<p>出力ファイルの中身は下記のようなINSERT文となっていました。</p>
<pre>BEGIN;
INSERT INTO countries (country_id,country_name,region_id) VALUES (E'AR',E'Argentina',2);
INSERT INTO countries (country_id,country_name,region_id) VALUES (E'AU',E'Australia',3);
INSERT INTO countries (country_id,country_name,region_id) VALUES (E'BE',E'Belgium',1);
INSERT INTO countries (country_id,country_name,region_id) VALUES (E'BR',E'Brazil',2);
INSERT INTO countries (country_id,country_name,region_id) VALUES (E'CA',E'Canada',2);
INSERT INTO countries (country_id,country_name,region_id) VALUES (E'CH',E'Switzerland',1);
INSERT INTO countries (country_id,country_name,region_id) VALUES (E'CN',E'China',3);
.
.
.
</pre>
<h3>変換レポートの出力</h3>
<p>-t オプションにSHOW_REPORTを設定すると、変換レポートを出力できます。</p>
<pre>ora2pg -c ora2pg.conf -t SHOW_REPORT
</pre>
<h4>出力結果</h4>
<pre>[========================&gt;] 8/8 tables (100.0%) end of scanning.
[========================&gt;] 10/10 objects types (100.0%) end of objects auditing.
-------------------------------------------------------------------------------
Ora2Pg v20.0 - Database Migration Report
-------------------------------------------------------------------------------
Version Oracle Database 12c Standard Edition Release 12.2.0.1.0
Schema  HR
Size    1.62 MB

-------------------------------------------------------------------------------
Object  Number  Invalid Comments        Details
-------------------------------------------------------------------------------
DATABASE LINK   0       0       Database links will be exported as SQL/MED PostgreSQL's Foreign Data Wrapper (FDW) extensions using oracle_fdw.
GLOBAL TEMPORARY TABLE  0       0       Global temporary table are not supported by PostgreSQL and will not be exported. You will have to rewrite some application code to match the PostgreSQL temporary table behavior.
INDEX   19      0       11 index(es) are concerned by the export, others are automatically generated and will do so on PostgreSQL. Bitmap will be exported as btree_gin index(es) and hash index(es) will be exported as b-tree index(es) if any. Domain index are exported as b-tree but commented to be edited to mainly use FTS. Cluster, bitmap join and IOT indexes will not be exported at all. Reverse indexes are not exported too, you may use a trigram-based index (see pg_trgm) or a reverse() function based index and search. Use 'varchar_pattern_ops', 'text_pattern_ops' or 'bpchar_pattern_ops' operators in your indexes to improve search with the LIKE operator respectively into varchar, text or char columns.   11 b-tree index(es).
JOB     0       0       Job are not exported. You may set external cron job with them.
PROCEDURE       2       0       Total size of procedure code: 772 bytes.
SEQUENCE        3       0       Sequences are fully supported, but all call to sequence_name.NEXTVAL or sequence_name.CURRVAL will be transformed into NEXTVAL('sequence_name') or CURRVAL('sequence_name').
SYNONYM 0       0       SYNONYMs will be exported as views. SYNONYMs do not exists with PostgreSQL but a common workaround is to use views or set the PostgreSQL search_path in your session to access object outside the current schema.
TABLE   8       0        2 check constraint(s). Total number of rows: 216. Top 10 of tables sorted by number of rows:. employees has 107 rows. departments has 27 rows. countries has 25 rows. locations has 23 rows. jobs has 19 rows. job_history has 10 rows. regions has 4 rows. test has 1 rows. Top 10 of largest tables:.
TRIGGER 2       0       Total size of trigger code: 123 bytes.
VIEW    2       0       Views are fully supported but can use specific functions.
-------------------------------------------------------------------------------
Total   36      0
-------------------------------------------------------------------------------
</pre>
<p>画面では見づらいので&#8211;dump_as_htmlをつけることでHTMLとして出力することもできます（その他、SHOW_REPORTでは変換に必要な推定コストを表示する&#8211;estimate_costオプションも指定できるようです）。</p>
<pre>ora2pg -c ora2pg.conf -t SHOW_REPORT --dump_as_html &gt; ~/workdir/SHOW_REPORT.html
</pre>
<p>今回はサンプルスキーマHRが変換対象ということもあり、変換対象36オブジェクト中、無効なオブジェクトは0個という結果となりました。</p>
<h3>設定値の説明</h3>
<p>ora2pg.conf内の主な設定値は下記の通りです。</p>
<table>
<thead>
<tr>
<th>設定値</th>
<th>意味</th>
<th>備考</th>
</tr>
</thead>
<tbody>
<tr>
<td>TYPE</td>
<td>変換するオブジェクトの種類</td>
<td>実行時に -t オプションとして指定できます。</td>
</tr>
<tr>
<td>OUTPUT_DIR</td>
<td>出力先のディレクトリ</td>
<td>実行時に -b オプションとして指定できます。</td>
</tr>
<tr>
<td>OUTPUT</td>
<td>出力するファイル名</td>
<td>実行時に -o オプションとして指定できます。</td>
</tr>
<tr>
<td>ORACLE_DSN</td>
<td>Oracleデータベースの接続情報</td>
<td></td>
</tr>
<tr>
<td>ORACLE_USER</td>
<td>Oracleデータベースの接続ユーザ</td>
<td></td>
</tr>
<tr>
<td>ORACLE_PWD</td>
<td>Oracleデータベースの接続ユーザのパスワード</td>
<td></td>
</tr>
<tr>
<td>PG_DSN</td>
<td>PostgreSQLの接続情報</td>
<td></td>
</tr>
<tr>
<td>PG_USER</td>
<td>PostgreSQLの接続ユーザ</td>
<td></td>
</tr>
<tr>
<td>PG_PWD</td>
<td>PostgreSQLの接続ユーザのパスワード</td>
<td></td>
</tr>
<tr>
<td>PG_SCHEMA</td>
<td>PostgreSQLの接続スキーマ</td>
<td>インポート先のスキーマです。</td>
</tr>
<tr>
<td>SCHEMA</td>
<td>変換元のスキーマ</td>
<td>指定しないとシステムスキーマ以外の全スキーマが対象となります。</td>
</tr>
<tr>
<td>FILE_PER_FKEYS</td>
<td>外部キーを別ファイルに出力するかどうか</td>
<td></td>
</tr>
</tbody>
</table>
<p>他にも</p>
<ul>
<li>テーブルごとに出力されるSQLファイルを分割する「FILE_PER_TABLE」</li>
<li>数値データ型をnumericに変換するかどうかを決定する「PG_NUMERIC_TYPE」</li>
<li>データ移行の並列度を決定する「JOBS」</li>
</ul>
<p>など多数の設定値が用意されており、細かく挙動を制御できるようになっています。</p>
<h3>Ora2PgをPostgreSQL公式サイトのリポジトリからインストール</h3>
<p>Ora2Pgの公式サイトには記載されていないのですが、実はPostgreSQL公式サイトに用意されているPostgreSQLリポジトリ内にOra2Pgが含まれています。<br />
ご参考までに、このPostgreSQLリポジトリからOra2Pgをインストールする方法もご紹介します。</p>
<h4>PostgreSQLリポジトリの追加</h4>
<p>最初にPostgreSQLリポジトリを追加します。</p>
<pre># yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
</pre>
<p>これでインストール可能なパッケージリスト内にora2pgが存在するようになりました。</p>
<pre># yum list ora2pg
Available Packages
ora2pg.noarch                                        20.0-1.rhel7                                         pgdg-common
</pre>
<h4>OracleInstantClientのインストール</h4>
<p>早速、Ora2Pgのインストールを行いたいところですが、やはり事前にインストールしておくものがあります。<br />
Oracle Technology Network（OTN）サイトからOracleInstantClient（※）をダウンロードしてインストールします。<br />
※バージョン19cをダウンロードしてください。19c以前のバージョンでは、Ora2Pgをインストールする際にエラーとなります。</p>
<pre># rpm -ivh oracle-instantclient19.6-basic-19.6.0.0.0-1.x86_64.rpm
# rpm -ivh oracle-instantclient19.6-devel-19.6.0.0.0-1.x86_64.rpm
# rpm -ivh oracle-instantclient19.6-sqlplus-19.6.0.0.0-1.x86_64.rpm
# rpm -ivh oracle-instantclient19.6-jdbc-19.6.0.0.0-1.x86_64.rpm
</pre>
<h4>Perlモジュールのインストール</h4>
<p>次に、epelリポジトリに含まれているString::Randomモジュールをインストールします。</p>
<pre># yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
# yum install perl-String-Random
</pre>
<p>今度は、non-freeのPostgreSQLリポジトリからDBD::Oracleモジュールをインストールします。</p>
<pre># yum install https://download.postgresql.org/pub/repos/yum/reporpms/non-free/EL-7-x86_64/pgdg-redhat-nonfree-repo-latest.noarch.rpm
# yum install perl-DBD-Oracle
</pre>
<h4>Ora2Pgのインストール</h4>
<p>これでOra2Pgをインストールする準備ができましたので、続けてインストールを行います。</p>
<pre># yum install ora2pg
</pre>
<p>/bin ディレクトリにOra2Pgが無事にインストールされました。</p>
<pre># ora2pg -v
Ora2Pg v20.0

# which ora2pg
/bin/ora2pg
</pre>
<h2>Ora2Pgの注意点</h2>
<p>最後にOra2Pgを利用する上での注意するべき点を挙げさせていただきます。</p>
<p>繰り返しとなりますが今回はシンプルなサンプルスキーマHRが変換対象としましたので、検証した中ではとくに手作業での修正などは必要としませんでした。しかし、実際に運用されているOracleデータベースを変換する際には、OracleとPostgreSQLの違いにより、変換不能なオブジェクトや手作業での修正が必要となることが予想されます。</p>
<p>PostgreSQLはOracleへの互換性が高いといわれておりますが、それでも多くの相違点があります。<br />
たとえば</p>
<ul>
<li>オブジェクト名をダブルコーテーションでくくらない場合、Oracleは大文字に変換されるが、PostgreSQLでは小文字に変換される。</li>
<li>文字列型を定義する際のvarchar(n)などのnは、Oracle（のデフォルト設定）ではバイト数、PostgreSQLでは文字数となる。</li>
</ul>
<p>などを解消できる設定値などはora2pg.conf内に確認することはできませんでした。<br />
Ora2Pgを利用することで移行作業の工数を確かに削減できますが、Ora2Pgでは完全にOracleからPostgreSQLへ移行できるとはいえず、何かしらの修正作業が発生いたします。<br />
加えて、PostgreSQLへ変換した際には変換前と同じ機能が提供されているかどうかの検証作業も必要となることにご注意ください。</p>
<p>以上、Ora2Pgを実行できる環境の構築方法と、簡単ではありましたがOra2Pgを実行した結果を紹介させていただきました。</p>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/pgsql-mainte/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-pgsql" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、PostgreSQL/Pgpool-II のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>oracle_fdw を使ってみる（後編）</title>
		<link>https://www.sraoss.co.jp/tech-blog/pgsql/using_oracle_fdw_2/</link>
		
		<dc:creator><![CDATA[高塚 遥 (Haruka Takatsuka)]]></dc:creator>
		<pubDate>Tue, 13 Nov 2018 03:55:10 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[FDW]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[サードパーティーソフトウェア]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=799</guid>

					<description><![CDATA[oracle_fdw 紹介の後編です。 前編では oracle_fdw を PostgreSQL に導入・外部サーバ定義・ユーザマッピング・外部テーブル定義を順に行い Oracleデータベース上のテーブルに Postgr ...]]></description>
										<content:encoded><![CDATA[<p>oracle_fdw 紹介の後編です。<br />
<a href="/tech-blog/pgsql/using_oracle_fdw_1/">前編</a>では oracle_fdw を PostgreSQL に導入・外部サーバ定義・ユーザマッピング・外部テーブル定義を順に行い Oracleデータベース上のテーブルに PostgreSQL からアクセスする流れを紹介しました。<br />
今回は、機能をもう少し深堀りをしていきます。</p>
<p><span id="more-799"></span></p>
<p>本記事で使用するデータは以下の通りです。これらテーブルが Oracle側に在って、対応する同名のoracle_fdw外部テーブルがPostgreSQL側に作成されています。</p>
<ul>
<li style="list-style-type: none;">● EMP表</li>
</ul>
<pre>      EMP_NO EMP_NAME                       DEPT_CD         POST_CD       SALARY LAST_MODIFIED
  ---------- ------------------------------ --------------- --------- ---------- -------------------
           1 Lion                                           001            10000 2018/08/15 11:00:00
           2 Tiger                                          002             7000 2018/08/15 11:00:00
           3 Fox                            00005           003             5000 2018/08/15 11:10:00
           4 Pig                            00005           005             2000 2018/08/15 11:15:30
           5 Dog                            00002           004             3500 2018/08/15 11:25:00
           6 Cat                            00001           004             3500 2018/08/15 11:25:30
           7 Cow                            00006           003             5200 2018/08/15 11:30:15
           8 Rat                            00004           005             2000 2018/08/15 11:45:00
</pre>
<ul>
<li style="list-style-type: none;">● DEPT表</li>
</ul>
<pre>  DEPT_CD         DEPT_NAME
  --------------- ------------------------------
  00001           総務部
  00002           経理部
  00003           営業部
  00004           広報部
  00005           人事部
  00006           開発部
</pre>
<ul>
<li style="list-style-type: none;">● POST表</li>
</ul>
<pre>  POST_CD   POST_NAME
  --------- ------------------------------
  001       社長
  002       専務
  003       部長
  004       課長
  005       係長
  006       一般社員
</pre>
<h2>実行プランを調べてみる</h2>
<p>PostgreSQLでは EXPLAIN文を使って SQLの実行計画を確認することができます。oracle_fdw は EXPLAIN にも対応していて、PostgreSQL側の EXPLAIN で Oracle側で実行されるSQLや実行計画などの情報を参照できます。</p>
<p>oracle_fdw の外部テーブルを使った SQL の実行計画がどのように見えるかを調べて見ます。</p>
<pre>  db1=&gt; explain SELECT * FROM emp;
                                                                                   QUERY PLAN
  -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   Foreign Scan on emp  (cost=10000.00..20000.00 rows=1000 width=178)
     Oracle query: SELECT /*582407e117cf2d80398b826784bcb7fc*/ r1."EMP_NO", r1."EMP_NAME", r1."DEPT_CD", r1."POST_CD", r1."SALARY", r1."LAST_MODIFIED" FROM "ORAUSER"."EMP" r1
  (2 行)
</pre>
<p>empテーブルをスキャンするために Oracle側で実行する SQL が「Oracle query:」の行に報告されます。</p>
<pre>  db1=&gt; explain (analyze) SELECT * FROM emp;
                                                                                   QUERY PLAN
  -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   Foreign Scan on emp  (cost=10000.00..20000.00 rows=1000 width=178) (actual time=3.096..3.189 rows=8 loops=1)
     Oracle query: SELECT /*582407e117cf2d80398b826784bcb7fc*/ r1."EMP_NO", r1."EMP_NAME", r1."DEPT_CD", r1."POST_CD", r1."SALARY", r1."LAST_MODIFIED" FROM "ORAUSER"."EMP" r1
   Planning time: 1.687 ms
   Execution time: 3.223 ms
  (4 行)
</pre>
<p>SQLを実際に実行してみた結果を報告する analyzeオプションを付与した場合は、上記のように PostgreSQL側から見た所要時間が報告されいます。</p>
<pre>  db1=&gt; explain (analyze, verbose) select * from emp;
                                                                                   QUERY PLAN
  -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   Foreign Scan on pguser.emp  (cost=10000.00..20000.00 rows=1000 width=178) (actual time=0.603..0.650 rows=8 loops=1)
     Output: emp_no, emp_name, dept_cd, post_cd, salary, last_modified
     Oracle query: SELECT /*582407e117cf2d80398b826784bcb7fc*/ r1."EMP_NO", r1."EMP_NAME", r1."DEPT_CD", r1."POST_CD", r1."SALARY", r1."LAST_MODIFIED" FROM "ORAUSER"."EMP" r1
     Oracle plan: SELECT STATEMENT
     Oracle plan:   TABLE ACCESS FULL EMP
   Planning time: 1.085 ms
   Execution time: 0.673 ms
  (7 行)
</pre>
<p>verboseオプションをつけると、「Oracle plan:」という行が出力されます。<br />
これがOracle側の実行計画です。<br />
本当にそうであるか、Oracle側で確認してみます。<br />
「Oracle query:」の行に出力されているSQL文にコメント「/*582407e117cf2d80398b826784bcb7fc*/」が挿入されているので、これをOracleで検索します。</p>
<pre> SQL&gt; SELECT SQL_ID, SQL_TEXT FROM V$SQL WHERE SQL_TEXT LIKE '%582407e117cf2d80398b826784bcb7fc%';

  SQL_ID          SQL_TEXT
  --------------- -----------------------------------------------------------------------------------------------------------------------------------------------------------------
  2zk7rdr3gtgvd   SELECT SQL_ID, SQL_TEXT FROM V$SQL WHERE SQL_TEXT LIKE '%582407e117cf2d80398b826784bcb7fc%'
  fd3s5h31jvhy1   SELECT /*582407e117cf2d80398b826784bcb7fc*/ r1."EMP_NO", r1."EMP_NAME", r1."DEPT_CD", r1."POST_CD", r1."SALARY", r1."LAST_MODIFIED" FROM "ORAUSER"."EMP" r1
</pre>
<p>上記の SQL_ID が「fd3s5h31jvhy1」の行が、PostgreSQLで実行したSQLです。このSQLの実行計画を確認します。</p>
<pre>  SQL&gt; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('fd3s5h31jvhy1', 0));

  PLAN_TABLE_OUTPUT
  ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  SQL_ID  fd3s5h31jvhy1, child number 0
  -------------------------------------
  SELECT /*582407e117cf2d80398b826784bcb7fc*/ r1."EMP_NO", r1."EMP_NAME",
  r1."DEPT_CD", r1."POST_CD", r1."SALARY", r1."LAST_MODIFIED" FROM
  "ORAUSER"."EMP" r1

  Plan hash value: 3956160932

  --------------------------------------------------------------------------
  | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
  --------------------------------------------------------------------------
  |   0 | SELECT STATEMENT  |      |       |       |     3 (100)|          |
  |   1 |  TABLE ACCESS FULL| EMP  |     8 |   552 |     3   (0)| 00:00:01 |
  --------------------------------------------------------------------------

  Note
  -----
     - dynamic sampling used for this statement (level=2)


  19行が選択されました。
</pre>
<p>「verbose」オプション付きで EXPLAINを実行したときに出力された「Oracle plan:」は、確かにOracle側の実行計画であることがわかりました。<br />
この例のように、実行したSQLがどのようにOracleで実行されているのかを確認したいときにはSQL文に付与されたコメントの文字列を使って調べることができます。</p>
<h2>プランナ統計情報</h2>
<p>PostgreSQLではバージョン9.2以降から外部テーブルについてもプランナ統計情報の取得が可能となりました。oracle_fdwではプランナ統計情報にも対応しています。通常のテーブルと同様に ANALYZEコマンドを使用します。ただし、autovacuumプロセスによる自動ANALYZEには対応していない点に注意が必要です。定期的な ANALYZEコマンド実行を運用に組み入れるようにしましょう。</p>
<p>それでは oracle_fdw にANALYZEをしたときの挙動を見ていきましょう。</p>
<pre>  db1=&gt; explain (analyze) SELECT * FROM emp;
                                                                                   QUERY PLAN
  -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   Foreign Scan on emp  (cost=10000.00..20000.00 rows=1000 width=178) (actual time=1.450..1.499 rows=8 loops=1)
     Oracle query: SELECT /*582407e117cf2d80398b826784bcb7fc*/ r1."EMP_NO", r1."EMP_NAME", r1."DEPT_CD", r1."POST_CD", r1."SALARY", r1."LAST_MODIFIED" FROM "ORAUSER"."EMP" r1
   Planning time: 190.054 ms
   Execution time: 1.524 ms
  (4 行)
</pre>
<p>これは外部テーブルを作った直後、未だプランナ統計情報が無い状態で実行しています。<br />
EXPLAIN (analyze) の出力では、「(actual time= &#8230; )」の部分に実際の所要時間と行数、ループ数が報告されます。<br />
応答先頭行の「cost=10000.00..20000.00 rows=1000 width=178」部分の rowsを見ると、実際の行数が 8件であるにもかかわらず 1000件存在している想定で実行計画を立てています。1000件というのは不明な場合のデフォルトの件数です。</p>
<p>次に ANALYZEを実行してから、再度 EXPLAIN を実行してみます。</p>
<pre>  db1=&gt; ANALYZE emp;
  ANALYZE

  db1=&gt; explain (analyze) SELECT * FROM emp;
                                                                                   QUERY PLAN
  -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   Foreign Scan on emp  (cost=10000.00..10080.00 rows=8 width=34) (actual time=0.900..0.991 rows=8 loops=1)
     Oracle query: SELECT /*582407e117cf2d80398b826784bcb7fc*/ r1."EMP_NO", r1."EMP_NAME", r1."DEPT_CD", r1."POST_CD", r1."SALARY", r1."LAST_MODIFIED" FROM "ORAUSER"."EMP" r1
   Planning time: 1.592 ms
   Execution time: 1.023 ms
  (4 行)
</pre>
<p>統計情報のと実際の件数が一致しました。oracle_fdw外部テーブルでもプランナ統計情報が機能しているといえます。</p>
<h2>Push-down機能</h2>
<p>oracle_fdwにより Oracleデータベース上のテーブルにアクセスする SQLが実行できました。<br />
このとき、SQL処理過程でどの部分が Oracleで実行されて、どの部分が PostgreSQLで実行されるのかが気になるところです。<br />
100万件のデータから20件が絞り込まれるようなSQLを実行したとき、以下のパターンが考えられますができることなら Oracle側で絞り込みを行った結果の20件のみをPostgreSQLが取得できる方が良いでしょう。</p>
<ul>
<li style="list-style-type: none;">(A) Oracleで絞り込みを実行した結果の20件をPostgreSQLが取得</li>
<li style="list-style-type: none;">(B) Oracleから100万件のデータを取得し、PostgerSQLで20件に絞り込みを実行</li>
</ul>
<p>検索条件による絞込みをより末端の方で行わせることを push-down（プッシュダウン）と呼びます。<br />
上記例でいえば (B) であったものを (A) の処理にするのが push-down です。</p>
<p>oracle_fdwでは、すべてのケースではないですが WHERE句の push-downに対応しています。<br />
ここから、実際にpush-down が行われていることを EXPLAIN文を使って確認していきます。</p>
<h3>WHERE句のpush-down</h3>
<p>WHERE句の条件を指定した場合について、確認してみます。<br />
emp表から 所属（dept_cd列）が　00005（＝人事部）であるような社員を抽出する SQL を実行します。</p>
<pre>    db1=&gt; select * from emp where dept_cd = '00005';
                                                                                                     QUERY PLAN
    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     Foreign Scan on pguser.emp  (cost=10000.00..20000.00 rows=1000 width=178) (actual time=1.636..1.656 rows=2 loops=1)
       Output: emp_no, emp_name, dept_cd, post_cd, salary, last_modified
       Oracle query: SELECT /*4b7ea9f8203e1ae2db752c3c52185bd8*/ r1."EMP_NO", r1."EMP_NAME", r1."DEPT_CD", r1."POST_CD", r1."SALARY", r1."LAST_MODIFIED" FROM "ORAUSER"."EMP" r1 WHERE (r1."DEPT_CD" = '00005')
       Oracle plan: SELECT STATEMENT
       Oracle plan:   TABLE ACCESS FULL EMP  (filter "R1"."DEPT_CD"='00005')
     Planning time: 194.733 ms
     Execution time: 1.685 ms
    (7 行)
</pre>
<p>「Oracle plan:」に「(filter &#8220;R1&#8221;.&#8221;DEPT_CD&#8221;=&#8217;00005&#8242;)」と出力されていることから、絞り込みがpush-downされていることがわかります。</p>
<p>続いては問題が起きそうなケースを試してみます。PostgreSQLとOracleで結果が異なる関数を実行するとどうなるでしょうか。<br />
substr関数は PostgreSQL と Oracle で仕様が違います。そのため、以下のように結果が変わってきます。</p>
<ul>
<li>PostgreSQLのsubstr関数実行結果</li>
</ul>
<pre>    db1=&gt; SELECT emp_no, emp_name, substr(emp_name, -3, 2) FROM emp WHERE substr(emp_name, -3, 2) = 'io';
     emp_no | emp_name | substr
    --------+----------+--------
    (0 行)
</pre>
<ul>
<li>Oracleのsubstr関数実行結果</li>
</ul>
<pre>    SQL&gt; SELECT EMP_NO, EMP_NAME, SUBSTR(EMP_NAME, -3, 2) FROM EMP WHERE SUBSTR(EMP_NAME, -3, 2) = 'io';

        EMP_NO EMP_NAME                       SUBSTR(EMP_NAME,-3,2)
    ---------- ------------------------------ ------------------------
             1 Lion                           io
</pre>
<p>この SUBSTR関数を WHERE句の条件に指定したとき、PostgreSQLとOracleのどちらで実行されるでしょうか。</p>
<pre>    db1=&gt; SELECT emp_no, emp_name, substr(emp_name, -3, 2) FROM emp WHERE substr(emp_name, -3, 2) = 'io';
     emp_no | emp_name | substr
    --------+----------+--------
          1 | Lion     |
    (1 行)

    db1=&gt; explain (verbose) SELECT emp_no, emp_name, substr(emp_name, -3, 2) FROM emp WHERE substr(emp_name, -3, 2) = 'io';
                                                                             QUERY PLAN
    ------------------------------------------------------------------------------------------------------------------------------------------------------------
     Foreign Scan on pguser.emp  (cost=10000.00..20002.50 rows=1000 width=154)
       Output: emp_no, emp_name, substr((emp_name)::text, '-3'::integer, 2)
       Oracle query: SELECT /*aadff49a5fa2767492d5844f517ca51c*/ r1."EMP_NO", r1."EMP_NAME" FROM "ORAUSER"."EMP" r1 WHERE (substr(r1."EMP_NAME", -3, 2) = 'io')
       Oracle plan: SELECT STATEMENT
       Oracle plan:   TABLE ACCESS FULL EMP  (filter SUBSTR("R1"."EMP_NAME",-3,2)='io')
    (5 行)
</pre>
<p>本例では WHERE句の条件が push-downされたことにより、SUBSTR関数は Oracleで実行されました。<br />
その結果該当データが1件となっています。<br />
この振る舞いは push-downの有無により応答が変わる可能性があるということであり、アプリケーションの不具合の原因となります。<br />
対策としては関数がどちらで実行される可能性もありうるということを考慮にいれて、関数の仕様差異があらわれる使い方を避けることです。</p>
<h3>ORDER BY句のpush-down</h3>
<p>PostgreSQL9.2以降から ORDER BY句の push-down が可能になり、oracle_fdwでも対応しています。<br />
ただし、文字列で並び替えを行う場合には push-down されません。</p>
<p>以下の定義となっている外部テーブルの数値型列（emp_no）と文字型列（emp_name）に対して ORDER BY の push-down を試してみます。</p>
<pre>     db1=&gt; d+ emp
                                                             外部テーブル "pguser.emp"
           列       |               型               | 照合順序 | Null 値を許容 | デフォルト | FDW オプション | ストレージ | 統計の対象 | 説明
     ---------------+--------------------------------+----------+---------------+------------+----------------+------------+------------+------
      emp_no        | integer                        |          | not null      |            | (key 'true')   | plain      |            |
      emp_name      | character varying(50)          |          |               |            |                | extended   |            |
      dept_cd       | character varying(5)           |          |               |            |                | extended   |            |
      post_cd       | character varying(3)           |          |               |            |                | extended   |            |
      salary        | bigint                         |          |               |            |                | plain      |            |
      last_modified | timestamp(0) without time zone |          |               |            |                | plain      |            |
     サーバー: oradb112
     FDW オプション: (schema 'ORAUSER', "table" 'EMP')
</pre>
<ul>
<li>ORDER BY句に数値型カラム(emp_no)を指定</li>
</ul>
<pre>  db1=&gt; explain (analyze, verbose) SELECT * FROM emp ORDER BY emp_no;
                                                                                               QUERY PLAN
      ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
       Foreign Scan on pguser.emp  (cost=10000.00..20000.00 rows=1000 width=170) (actual time=3.169..3.225 rows=7 loops=1)
         Output: emp_no, emp_name, dept_cd, post_cd, salary
         Oracle query: SELECT /*e721c330da0d10a646db6bccb997a7e3*/ r1."EMP_NO", r1."EMP_NAME", r1."DEPT_CD", r1."POST_CD", r1."SALARY" FROM "ORAUSER"."EMP" r1 ORDER BY r1."EMP_NO" ASC NULLS LAST
         Oracle plan: SELECT STATEMENT
         Oracle plan:   SORT ORDER BY
         Oracle plan:     TABLE ACCESS FULL EMP
       Planning time: 3.001 ms
       Execution time: 3.267 ms
      (8 行)
</pre>
<ul>
<li>ORDER BY句に文字列型カラム(emp_name)を指定</li>
</ul>
<pre>db1=&gt; explain (analyze, verbose) SELECT * FROM emp ORDER BY emp_name;
                                                                                QUERY PLAN
      ---------------------------------------------------------------------------------------------------------------------------------------------------------------
       Sort  (cost=20049.83..20052.33 rows=1000 width=170) (actual time=2.003..2.005 rows=7 loops=1)
         Output: emp_no, emp_name, dept_cd, post_cd, salary
         Sort Key: emp.emp_name
         Sort Method: quicksort  Memory: 25kB
         -&gt;  Foreign Scan on pguser.emp  (cost=10000.00..20000.00 rows=1000 width=170) (actual time=1.876..1.928 rows=7 loops=1)
               Output: emp_no, emp_name, dept_cd, post_cd, salary
               Oracle query: SELECT /*f26579891b741d370f31c72dea761fe0*/ r1."EMP_NO", r1."EMP_NAME", r1."DEPT_CD", r1."POST_CD", r1."SALARY" FROM "ORAUSER"."EMP" r1
               Oracle plan: SELECT STATEMENT
               Oracle plan:   TABLE ACCESS FULL EMP
       Planning time: 1.684 ms
       Execution time: 2.055 ms
      (11 行)
</pre>
<p>数値型カラムの場合だけ「Oracle plan:」に「SORT ORDER BY」が出力されていることが確認できました。</p>
<h3>結合のpush-down</h3>
<p>PostgreSQL9.6以降では、以下の条件を満たすとき、結合においてもpush-downが動作します。</p>
<ul>
<li>SELECT文であること</li>
<li>結合対象のテーブルは、同一の外部サーバに定義されていること。</li>
<li>結合は内部結合(inner join)であること。</li>
<li>結合は2つまでであること</li>
<li>結合がpush-downされるとき、ORDER BYはpush-downされない</li>
</ul>
<p>条件を満たすSQLを実行してみます。</p>
<pre>    db1=&gt; explain verbose
    db1-&gt; select e.emp_no, e.emp_name, d.dept_name
    db1-&gt;   from emp e
    db1-&gt;  inner join dept d on e.dept_cd = d.dept_cd;
                                                                                                QUERY PLAN
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     Foreign Scan  (cost=10000.00..20000.00 rows=1000 width=240)
       Output: e.emp_no, e.emp_name, d.dept_name
       Oracle query: SELECT /*1f2567bfb61910168f19b658c678aa90*/ r1."EMP_NO", r1."EMP_NAME", r2."DEPT_NAME" FROM ("ORAUSER"."EMP" r1 INNER JOIN "ORAUSER"."DEPT" r2 ON (r1."DEPT_CD"= r2."DEPT_CD"))
       Oracle plan: SELECT STATEMENT
       Oracle plan:   HASH JOIN   (condition "R1"."DEPT_CD"="R2"."DEPT_CD")
       Oracle plan:     TABLE ACCESS FULL DEPT
       Oracle plan:     TABLE ACCESS FULL EMP
    (7 行)
</pre>
<p>問題なくpush-downされていることが確認できます。</p>
<p>条件違反になるように、結合を3つにして実行するとpush-downは行われないのでしょうか。試してみます。</p>
<pre>    db1=&gt; explain verbose
    db1-&gt; select e.emp_no, e.emp_name, d.dept_name
    db1-&gt;   from emp e
    db1-&gt;  inner join dept d on e.dept_cd = d.dept_cd
    db1-&gt;  inner join post p on e.post_cd = p.post_cd;
                                                                                                  QUERY PLAN
    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     Hash Join  (cost=30012.50..40177.50 rows=5000 width=126)
       Output: e.emp_no, e.emp_name, d.dept_name
       Hash Cond: ((e.dept_cd)::text = (d.dept_cd)::text)
       -&gt;  Foreign Scan  (cost=10000.00..20000.00 rows=1000 width=14)
             Output: e.emp_no, e.emp_name, e.dept_cd
             Oracle query: SELECT /*6c04b217ae3b4d3ffd35b76e854e0966*/ r1."EMP_NO", r1."EMP_NAME", r1."DEPT_CD" FROM ("ORAUSER"."EMP" r1 INNER JOIN "ORAUSER"."POST" r4 ON (r1."POST_CD" = r4."POST_CD"))
             Oracle plan: SELECT STATEMENT
             Oracle plan:   NESTED LOOPS
             Oracle plan:     TABLE ACCESS FULL EMP
             Oracle plan:     INDEX UNIQUE SCAN PK_POST (condition "R1"."POST_CD"="R4"."POST_CD")
       -&gt;  Hash  (cost=20000.00..20000.00 rows=1000 width=142)
             Output: d.dept_name, d.dept_cd
             -&gt;  Foreign Scan on pguser.dept d  (cost=10000.00..20000.00 rows=1000 width=142)
                   Output: d.dept_name, d.dept_cd
                   Oracle query: SELECT /*8e88abaedea07ba4637cb0f885201300*/ r2."DEPT_CD", r2."DEPT_NAME" FROM "ORAUSER"."DEPT" r2
                   Oracle plan: SELECT STATEMENT
                   Oracle plan:   TABLE ACCESS FULL DEPT
    (17 行)
</pre>
<p>emp表とpost表の結合、depto表の参照に分かれてpush-dowされ、それぞれの結果をPostgreSQL側で結合しているようです。</p>
<p>今度は、外部結合(left join)を実行を試してみます。</p>
<pre>    db1=&gt; explain verbose
    db1-&gt; select e.emp_no, e.emp_name, d.dept_name
    db1-&gt;   from emp e
    db1-&gt;  left outer join dept d on e.dept_cd = d.dept_cd;
                                                                    QUERY PLAN
    ------------------------------------------------------------------------------------------------------------------------------------------
     Hash Right Join  (cost=20080.10..30086.65 rows=30 width=126)
       Output: e.emp_no, e.emp_name, d.dept_name
       Hash Cond: ((d.dept_cd)::text = (e.dept_cd)::text)
       -&gt;  Foreign Scan on pguser.dept d  (cost=10000.00..20000.00 rows=1000 width=142)
             Output: d.dept_cd, d.dept_name
             Oracle query: SELECT /*8e88abaedea07ba4637cb0f885201300*/ r2."DEPT_CD", r2."DEPT_NAME" FROM "ORAUSER"."DEPT" r2
             Oracle plan: SELECT STATEMENT
             Oracle plan:   TABLE ACCESS FULL DEPT
       -&gt;  Hash  (cost=10080.00..10080.00 rows=8 width=14)
             Output: e.emp_no, e.emp_name, e.dept_cd
             -&gt;  Foreign Scan on pguser.emp e  (cost=10000.00..10080.00 rows=8 width=14)
                   Output: e.emp_no, e.emp_name, e.dept_cd
                   Oracle query: SELECT /*f8e48586f7f43a704253aec0be7a2a79*/ r1."EMP_NO", r1."EMP_NAME", r1."DEPT_CD" FROM "ORAUSER"."EMP" r1
                   Oracle plan: SELECT STATEMENT
                   Oracle plan:   TABLE ACCESS FULL EMP
    (15 行)
</pre>
<p>emp表、dept表への参照がそれぞれpush-downされ、PostgreSQLで外部結合が行われました。</p>
<p>最後に、結合と&#8221;order by&#8221;を同時に行います。</p>
<pre>    db1=&gt; explain verbose
    db1-&gt; select e.emp_no, e.emp_name, d.dept_name
    db1-&gt;   from emp e
    db1-&gt;  inner join dept d on e.dept_cd = d.dept_cd
    db1-&gt;  order by e.emp_no;
                                                                                                   QUERY PLAN
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     Sort  (cost=20049.83..20052.33 rows=1000 width=126)
       Output: e.emp_no, e.emp_name, d.dept_name
       Sort Key: e.emp_no
       -&gt;  Foreign Scan  (cost=10000.00..20000.00 rows=1000 width=126)
             Output: e.emp_no, e.emp_name, d.dept_name
             Oracle query: SELECT /*1f2567bfb61910168f19b658c678aa90*/ r1."EMP_NO", r1."EMP_NAME", r2."DEPT_NAME" FROM ("ORAUSER"."EMP" r1 INNER JOIN "ORAUSER"."DEPT" r2 ON (r1."DEPT_CD" = r2."DEPT_CD"))
             Oracle plan: SELECT STATEMENT
             Oracle plan:   HASH JOIN   (condition "R1"."DEPT_CD"="R2"."DEPT_CD")
             Oracle plan:     TABLE ACCESS FULL DEPT
             Oracle plan:     TABLE ACCESS FULL EMP
    (10 行)
</pre>
<p>結合はpush-downされますが、「order by」はPostgreSQLで実行されることがわかりました。</p>
<p>このように、条件を満たさない SQL の場合には、push-down は部分的にだけ行われます。<br />
少しでも条件に反したら全く push-downしないわけではありません。</p>
<h2>更新とトランザクション</h2>
<p>oracle_fdwは更新SQLにも対応しています。<br />
以下のように PostgreSQL から Oracle側のデータを変更できます。</p>
<pre>db1=&gt; INSERT INTO post VALUES ('007', 'アルバイト');
INSERT 0 1
db1=&gt; SELECT * FROM post ;
post_code | post_name
-----------+------------
001 | 社長
002 | 専務
003 | 部長
004 | 課長
005 | 係長
006 | 一般社員
007 | アルバイト
(7 rows)
</pre>
<p>トランザクションにも対応していて、PostgreSQLで更新内容をロールバックすると、Oracle側でもロールバックされます。以下に例を示します。</p>
<pre>db1=&gt; BEGIN;
BEGIN
db1=&gt; DELETE FROM post WHERE post_code = '007';
DELETE 1
db1=&gt; SELECT * FROM post ;
 post_code | post_name
-----------+-----------
 001       | 社長
 002       | 専務
 003       | 部長
 004       | 課長
 005       | 係長
 006       | 一般社員
(6 rows)

db1=&gt; ROLLBACK;
ROLLBACK


SQL&gt; SELECT * FROM post WHERE post_id = '007';

POST_ID
---------------------------------------------
POST_NAME
--------------------------------------------------------------------------------
007
アルバイト
</pre>
<h3>更新における注意点</h3>
<p>更新SQLを実行する場合には特に、PostgreSQLと Oracle のデータ型の振る舞いの違いについて注意が必要です。</p>
<p>POSTテーブルの POST_NAME列は VARCHAR(30) 型、PostgreSQL内の外部テーブルとしても varchar(30) 型です。そこに以下のように マルチバイト文字で20文字のデータ投入しますと、Oracle側でエラーが発生します。これは Oracleでは VARCHARの長さは文字数ではなくバイト数を基準としているからです。</p>
<pre>db1=&gt; INSERT INTO post VALUES ('999', '例外ケース／特別ケース／上記非該当ケース'
);
ERROR:  error executing query: OCIStmtExecute failed to execute remote query
DETAIL:  ORA-12899: value too large for column "ORAUSER"."POST"."POST_NAME" (actual: 40, maximum: 30)
</pre>
<p>そのほか、浮動小数点データ型や日付時刻データ型における端数の丸め方など、データ型の振る舞いの違いにより、値が両データベース間を行き来することで期待と違う値が見えたり、格納されてしまったりすることがあります。</p>
<p>PostgreSQLとOracleで対応させることができるデータ型であっても、必ずしも同一の振る舞いをするデータ型ではないことを認識するようにしてください。</p>
<h2>まとめ</h2>
<p>後編では oracle_fdw の外部テーブルが実際にどのように動作するかを見てきました。</p>
<p>検索処理のpush-down、更新SQL、トランザクション処理などに対応していることが確認できました。<br />
EXPLAIN を使って SQL処理のどの部分が Oracle側で実行されるのかを調べることで、応答データが期待に反していたり、性能が出ないといった問題に対処できました。<br />
また、両データベース製品の関数やデータ型における仕様の違いに注意が必要です。</p>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/pgsql-mainte/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-pgsql" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、PostgreSQL/Pgpool-II のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>oracle_fdw を使ってみる（前編）</title>
		<link>https://www.sraoss.co.jp/tech-blog/pgsql/using_oracle_fdw_1/</link>
		
		<dc:creator><![CDATA[高塚 遥 (Haruka Takatsuka)]]></dc:creator>
		<pubDate>Fri, 10 Aug 2018 04:00:19 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[FDW]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[サードパーティーソフトウェア]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=303</guid>

					<description><![CDATA[更新日時: 2020年3月16日 PostgreSQLには、標準SQLの拡張である SQL/MED (&#8220;Management of External Data&#8221;)に沿った外部データアクセスの仕組み ...]]></description>
										<content:encoded><![CDATA[<h6><span id="timestamp">更新日時: <b>2020年3月16日</b></span></h6>
<p>PostgreSQLには、標準SQLの拡張である SQL/MED (&#8220;Management of External Data&#8221;)に沿った外部データアクセスの仕組みが備わっています。外部データの種類に応じた外部データラッパー（ Foreign Data Wrapper 、FDW）を適用することで、様々な外部データをPostgreSQL内のテーブルと同様に扱うことができます。</p>
<p>oracle_fdw は外部データラッパーの1つで Oracle Database に対応しています。oracle_fdw を使用することで、Oracle Database のテーブルやビューを PostgreSQL 上のSQLから読み書きできるようになります。</p>
<p>oracle_fdwはバージョン9.1以降のPostgreSQLおよびバージョン10.1以上のOracle Client（および Oracle Instant Client）で利用可能です。Oracle Database のサーバ側バージョンは、使用するOracle Clientが対応していれば大丈夫です。</p>
<p>本記事ではoracle_fdw の導入方法、使用方法を紹介します。続いて公開予定の後編の記事では、実際の使用にあたって気になる「こんなことをしたらどうなる？」「どの程度 PostgreSQL側で、どの程度Oracle側で処理されるの？」「データ型の違いはどうなるの？」といった様々な挙動の詳細に迫ります。</p>
<p><span id="more-303"></span></p>
<h2>oracle_fdw を導入する</h2>
<p>始めに導入方法を解説します。本記事作成にあたっては以下のバージョンで動作確認を行っています。</p>
<table>
<tbody>
<tr>
<td>PostgreSQL 10.4</td>
</tr>
<tr>
<td>oracle_fdw 2.1.0</td>
</tr>
<tr>
<td>Oracle Database 11g R2 XE</td>
</tr>
<tr>
<td>Oracle Instant Client 12.1</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<h3>Oracleデータベースの用意</h3>
<p>Oracle Database のデータベースは既にセットアップ済みであるものとします。本記事では Oracle Database 11g R2 XE バージョンを使用しています。</p>
<p>&nbsp;</p>
<h3>OCI ライブラリのインストール</h3>
<p>oracle_fdw は OCI（Oracle Call Interface）ライブラリを使って Oracleデータベースにアクセスします。そのため、PostgreSQL稼動サーバに OCI ライブラリのインストールが必要になります。本記事では Oracle Instant Client 12.1をインストールします。Oracle Instant Clientは <a href="http://www.oracle.com/technetwork/database/database-technologies/instant-client/overview/index.html">OTN（Oracle Technology Network）Webサイト</a>で配布されています。</p>
<pre># rpm -ivh oracle-instantclient12.1-basic-12.1.0.2.0-1.x86_64.rpm 
           oracle-instantclient12.1-devel-12.1.0.2.0-1.x86_64.rpm
</pre>
<p>また、接続確認用にSQL*Plusモジュールもインストールしています。</p>
<pre># rpm -ivh oracle-instantclient12.1-sqlplus-12.1.0.2.0-1.x86_64.rpm
</pre>
<p>Oracle ClientとServerとの互換性については、以下のページを参考にして下さい。<br />
<a href="https://www.oracle.com/jp/system-requirement/interoperability-support-195844-ja.html"> https://www.oracle.com/jp/system-requirement/interoperability-support-195844-ja.html</a></p>
<h3>インストール</h3>
<p>oracle_fdwのページ（<a href="https://github.com/laurenz/oracle_fdw">https://github.com/laurenz/oracle_fdw</a>）からoracle_fdwのソースコードをZIP形式でダウンロードします。ここではリポジトリ上の最新コードをダウンロードすることにします。</p>
<p>ダウンロード後、解凍処理を行いソースコンパイルを実施します。このとき、PostgreSQLのコマンドにPATHが通っている必要があります。また、ソースコードを展開したディレクトリにあるMakefile 内に、Oracle Clientの標準的なパスが一通り列挙されています。導入したOracle Clientのパスがここに無ければ、既存の記述を真似て適宜に書き加えてから make を実行してください。</p>
<pre>$ unzip oracle_fdw-master.zip
$ cd oracle_fdw-master
$ make
$ make install
</pre>
<p>ソフトウェアのインストールが済んだら、PostgreSQLサービスを起動（既に起動しているなら再起動）します。このとき、PostgreSQLを起動するユーザにおいて Oracle Instant Client のライブラリにライブラリパスが通っている必要があります。</p>
<p>PostgreSQLをrpmからインストールしている場合には、以下のファイルが作られていますので、</p>
<pre>/etc/ld.so.conf.d/postgresql-pgdg-libs.conf
</pre>
<p>そこに以下のようにライブラリのパスを追加しておきます。ファイルを書き換えたら忘れずに rootユーザでldconfigコマンドを実行して変更を反映させましょう。</p>
<pre>/usr/pgsql-10/lib
/usr/lib/oracle/12.1/client64/lib</pre>
<p>手動でPostgreSQLを起動しているなら、以下のように LD_LIBRARY_PATH環境変数を使って指定しても良いでしょう。</p>
<pre>$ export LD_LIBRARY_PATH=/usr/lib/oracle/12.1/client64/lib
$ pg_ctl start
</pre>
<h3>データベースへの登録</h3>
<p>次に使用したいデータベース（ここでは db1）に対して、SQL の CREATE EXTENSIONコマンドを使ってoracle_fdw拡張モジュールをインストールします。ややこしいのですが、これも「インストールする」と表現します。psql の dx コマンドでインストール済みの拡張モジュールを確認できます。</p>
<pre>db1=# CREATE EXTENSION oracle_fdw;
CREATE EXTENSION
db1=# \dx oracle_fdw
インストール済みの拡張一覧
名前 | バージョン | スキーマ | 説明
------------+------------+----------+----------------------------------------
oracle_fdw | 1.1 | public | foreign data wrapper for Oracle access
(1 行)
</pre>
<p>このとき、PostgreSQL起動前に Oracle Clientライブラリの設定が正しく行われていないときには以下のエラーが発生します。</p>
<pre>db1=# CREATE EXTENSION oracle_fldw;
ERROR: could not load library "/usr/pgsql-10/lib/oracle_fdw.so": libclntsh.so.12.1: cannot open shared object file: No such file or directory
</pre>
<h2>Oracle外部テーブルを定義する</h2>
<p>それでは Oracleデータベース上に存在するテーブルをPostgreSQLの外部テーブルとして定義してみましょう。</p>
<p>Oracleデータベース上には以下のようにテーブルTBL_ORA_TEST1 があるものとします。</p>
<pre>SQL&gt; SELECT OWNER, TABLE_NAME FROM DBA_TABLES WHERE OWNER = 'ORAUSER';

OWNER TABLE_NAME
--------------- ------------------------------
ORAUSER TBL_ORA_TEST1

SQL&gt; DESC TBL_ORA_TEST1
名前 NULL? 型
----------------------------------------- -------- ----------------------------
ID NOT NULL NUMBER(5)
ITEM VARCHAR2(100)
UPD_DATE TIMESTAMP(6)

SELECT * FROM TBL_ORA_TEST1;

ID ITEM UPD_DATE
---------- ------------------------------ ------------------------------
1 ORACLE DATA 1 18-07-18 14:19:29.402316
2 PostgreSQL INSERT DATA 1 18-07-18 14:56:15.870785
</pre>
<p>以下の(1) から(3) の手順で、OracleデータベースのテーブルをPostgreSQLの外部テーブルに定義します。</p>
<h3>(1) 外部サーバ作成</h3>
<p>Oracleデータベースにアクセスするための接続情報を外部サーバ(oradb112)として定義します。</p>
<pre>db1=# CREATE SERVER oradb112 FOREIGN DATA WRAPPER oracle_fdw
db1-# OPTIONS (dbserver '//192.168.156.102:1521/XE');
CREATE SERVER
db1=# \des
外部サーバー一覧
名前 | 所有者 | 外部データラッパ
----------+----------+------------------
oradb112 | postgres | oracle_fdw
(1 行)
</pre>
<p>テスト用の一般データベースユーザpguserが定義した外部サーバを使用できるように、権限を付与します。</p>
<pre>db1=# GRANT USAGE ON FOREIGN SERVER oradb112 TO pguser;
GRANT
</pre>
<h3>(2) ユーザマッピング定義</h3>
<p>外部サーバ（oradb112）とユーザ（pguser）の対応付けの定義を行います。PostgreSQL上で ユーザpguser が外部テーブルにアクセスしたとき、oradb112外部サーバに定義されたリモート先Oracleデータベースにアクセスするデータユーザはorauserである、ということを定義しています。</p>
<pre>db1=&gt; CREATE USER MAPPING FOR pguser SERVER oradb112 OPTIONS (USER 'orauser', PASSWORD 'orapass');
CREATE USER MAPPING
db1=&gt;
db1=&gt; deu
ユーザーマッピング一覧
サーバー | ユーザー名
----------+------------
oradb112 | pguser
(1 行)
</pre>
<h3>(3) 外部テーブル定義</h3>
<p>Oracleデータベース上のテーブル、ビューをPostgreSQLの外部テーブルとして定義します。ここでは Oracleデータベース上のテーブルTBL_ORA_TEST1 を外部テーブルftbl_ora_test1 として定義します。</p>
<pre>db1=&gt; CREATE FOREIGN TABLE ftbl_ora_test1
db1-&gt; (
db1(&gt; id int OPTIONS (key 'true') NOT NULL,
db1(&gt; item varchar(100),
db1(&gt; upd_date timestamp
db1(&gt; )
db1-&gt; SERVER oradb112 OPTIONS (SCHEMA 'ORAUSER', TABLE 'TBL_ORA_TEST1');
CREATE FOREIGN TABLE
</pre>
<p>id列に付加されている「OPTIONS (key &#8216;true&#8217;)」という記述は、この列が主キー列であることを示しています。複数の列から構成される主キーである場合には、それらの列全てにこのオプションを付加します。</p>
<p>作成した外部テーブルを確認します。</p>
<pre>db1=&gt; \det
外部テーブル一覧
スキーマ | テーブル | サーバー
----------+----------------+----------
public | ftbl_ora_test1 | oradb112
(1 行)
db1=&gt;
db1=&gt; \d ftbl_ora_test1
外部テーブル "public.ftbl_ora_test1"
列 | 型 | 照合順序 | Null 値を許容 | デフォルト | FDW オプション
----------+-----------------------------+----------+---------------+------------+----------------
id | integer | | not null | | (key 'true')
item | character varying(100) | | | |
upd_date | timestamp without time zone | | | |
サーバー: oradb112
FDW オプション: (schema 'ORAUSER', "table" 'TBL_ORA_TEST1')
</pre>
<p>oracle_fdwではクエリを外部テーブルとして定義することもできます。</p>
<p>以下の例では、Oracleデータベース上のテーブルに対するクエリを外部テーブルとして定義しています。<br />
クエリを外部テーブルとして定義する際には、OPTIONS句のSCHEMAを定義してはいけません。</p>
<pre>db1=&gt; CREATE FOREIGN TABLE ftbl_ora_test1_q
db1-&gt; (
db1(&gt; id int OPTIONS (key 'true') NOT NULL,
db1(&gt; item varchar(100),
db1(&gt; upd_date timestamp
db1(&gt; )
db1-&gt; SERVER oradb112 OPTIONS(TABLE '(SELECT id, item, upd_date FROM tbl_ora_test1 where item like ''%PostgreSQL%'')');
CREATE FOREIGN TABLE

db1=&gt; \det
外部テーブル一覧
スキーマ | テーブル | サーバー
----------+------------------+----------
public | ftbl_ora_test1_q | oradb112

db1=&gt; d ftbl_ora_test1_q
外部テーブル "public.ftbl_ora_test1_q"
列 | 型 | 照合順序 | Null 値を許容 | デフォルト | FDW オプション
----------+-----------------------------+----------+---------------+------------+----------------
id | integer | | not null | | (key 'true')
item | character varying(100) | | | |
upd_date | timestamp without time zone | | | |
サーバー: oradb112
FDW オプション: ("table" '(SELECT id, item, upd_date FROM tbl_ora_test1 where item like ''%PostgreSQL%'')')
</pre>
<h2>Oracle外部テーブルを使用する</h2>
<p>外部テーブルとして定義を行うことで、OracleのテーブルをPostgreSQLからSQLでアクセスできるようになりました。</p>
<h3>SELECTの実行</h3>
<p>上記４で定義を行った外部テーブルftbl_ora_test1、 ftbl_ora_test1_q に SELECT を実行します。</p>
<pre>db1=&gt; select * from ftbl_ora_test1;
id | item | upd_date
----+--------------------------+----------------------------
1 | ORACLE DATA 1 | 2018-07-18 14:19:29.402316
2 | PostgreSQL INSERT DATA 1 | 2018-07-18 14:56:15.870785
(2 行)

db1=&gt; select * from ftbl_ora_test1_q;
id | item | upd_date
----+--------------------------+----------------------------
2 | PostgreSQL INSERT DATA 1 | 2018-07-18 14:56:15.870785
(1 行)
</pre>
<p>無事データを取り出すことができました。</p>
<h3>INSERT/UPDATE/DELETEの実行</h3>
<p>PostgreSQL9.3以降であれば、oracle_fdw は外部テーブルに対して、INSERT/UPDATE/DELETEを実行することができます。<br />
ただし、UPDATE/DELETEについてはOracleのテーブルに設定された主キー列に対応する外部テーブルの列に&#8221;key&#8221;オプションを設定することが必要です。</p>
<p>&#8220;key&#8221; オプションが指定されている場合、以下のように動作します。</p>
<pre>db1=&gt; d ftbl_ora_test1
外部テーブル "public.ftbl_ora_test1"
列 | 型 | 照合順序 | Null 値を許容 | デフォルト | FDW オプション
----------+--------------------------------+----------+---------------+------------+----------------
id | integer | | not null | | (key 'true')
item | character varying(100) | | | |
upd_date | timestamp(6) without time zone | | | |
サーバー: oradb112
FDW オプション: (schema 'ORAUSER', "table" 'TBL_ORA_TEST1')

db1=&gt; UPDATE ftbl_ora_test1
db1-&gt; SET item = 'PostgreSQL UPDATE DATA2',
db1-&gt; upd_date = CURRENT_TIMESTAMP
db1-&gt; WHERE id = 3;
UPDATE 1
</pre>
<p>&#8220;key&#8221; オプションが指定されていない場合、以下のように更新操作に対してエラーが発生します。</p>
<pre>db1=&gt; d ftbl_ora_test1_ng
外部テーブル "public.ftbl_ora_test1_ng"
列 | 型 | 照合順序 | Null 値を許容 | デフォルト | FDW オプション
----------+-----------------------------+----------+---------------+------------+----------------
id | integer | | not null | |
item | character varying(100) | | | |
upd_date | timestamp without time zone | | | |
サーバー: oradb112
FDW オプション: (schema 'ORAUSER', "table" 'TBL_ORA_TEST1')

db1=&gt; UPDATE ftbl_ora_test1_ng
db1-&gt; SET item = 'PostgreSQL UPDATE DATA2',
db1-&gt; upd_date = CURRENT_TIMESTAMP
db1-&gt; WHERE id = 3;
ERROR: no primary key column specified for foreign Oracle table
DETAIL: For UPDATE or DELETE, at least one foreign table column must be marked as primary key column.
HINT: Set the option "key" on the columns that belong to the primary key.
</pre>
<h3>IMPORT FOREIGN SCHEMA</h3>
<p>oracle_fdw の機能を使用することで、OracleデータベースのテーブルやビューをPostgreSQLの外部テーブルとして定義しアクセスが可能であることを説明してきました。<br />
ここで、Oracleのデータベースリンク機能と対比して考えたとき、Oracleのデータベースリンクであればスキーマに対して１つの定義で<br />
対象スキーマが権限を保有するオブジェクトへのアクセスが可能となることに対して、PostgreSQLではアクセスを行いたいテーブル１つ１つを定義することに手間を感じることもあるかと思います。<br />
PostgreSQLが9.5以降であれば、「IMPORT FOREIGN SCHEMA」を使用することでOracleデータベースの特定スキーマに存在するテーブルやビューの定義をPostgreSQLの外部テーブルとして一括で定義することが可能となります。</p>
<p>Oracleデータベース上のテーブルリストが以下のようにであるとします。</p>
<pre>SQL&gt; SELECT owner, table_name FROM dba_tables WHERE OWNER = 'ORAUSER' ORDER BY table_name

OWNER TABLE_NAME
---------- ------------------------------
ORAUSER TBL_ORA_TEST1
ORAUSER TBL_ORA_TEST2
ORAUSER TBL_ORA_TEST3
ORAUSER TBL_ORA_TEST4
ORAUSER TBL_ORA_TEST5
</pre>
<p>上記のOracleデータベース上のスキーマ「ORAUSER」が所有するテーブルをIMPORT FOREIGN SCHEMAでまとめて外部テーブル定義をすることができます。</p>
<pre>db1=&gt; det
外部テーブル一覧
スキーマ | テーブル | サーバー
----------+----------+----------
(0 行)
db1=&gt;
db1=&gt; IMPORT FOREIGN SCHEMA "ORAUSER" FROM SERVER oradb112 INTO pguser;
IMPORT FOREIGN SCHEMA
db1=&gt;
db1=&gt; det
外部テーブル一覧
スキーマ | テーブル | サーバー
----------+---------------+----------
pguser | tbl_ora_test1 | oradb112
pguser | tbl_ora_test2 | oradb112
pguser | tbl_ora_test3 | oradb112
pguser | tbl_ora_test4 | oradb112
pguser | tbl_ora_test5 | oradb112
(5 行)
</pre>
<h3>識別子の大文字と小文字</h3>
<p>OracleデータベースとPostgreSQLではテーブル名やユーザ名などの識別子について、大文字小文字の扱いが異なります。クォーティングすることなく識別子名を書くと、Oracleデータベースでは大文字に揃えられ、PostgreSQLでは小文字に揃えられます。この違いにより以下の点に注意が必要となります。</p>
<ul>
<li>外部テーブル定義（CREATE FOREIGN TABLE）の際、OPTIONS句のスキーマ名およびユーザ名は Oracleのシステムカタログに定義されている情報（基本的には大文字）と同様に指定する必要があります。</li>
<li>IMPORT FOREIGN SCHEMAを実行する際に、Oracleデータベースのスキーマを指定しますが Oracleのシステムカタログに定義されている情報（基本的には大文字）と同様に指定する必要があります。</li>
<li>PostgreSQLでは、小文字に変換されてしまうため、Oracleデータベース上のスキーマ名を &#8220;（ダブルクォート）で括る必要があります。</li>
</ul>
<p>&nbsp;</p>
<h2>まとめ</h2>
<p>oracle_fdw は、Oracle上のテーブルやビューをPostgreSQLの外部テーブルにマッピングすることで PostgreSQLから直接SQLアクセスを実行可能とするツールです。これにより、PostgreSQL上のテーブルとOracle上のテーブルを結合させるSQLが実行可能となります。</p>
<p>PostgreSQLとOracleが共存している環境で Oracleのデータベースリンクのような機能をお探しであればデータへのアクセスのみとなりますが、代替機能として有用な手段となります。</p>
<p>本記事の後編ではoracle_fdw の動作・挙動の詳細を検証していきます。</p>
<p>&nbsp;</p>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/pgsql-mainte/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-pgsql" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、PostgreSQL/Pgpool-II のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
