Oracleエラー対応(ORA-04052):DDBLINKを経由したMATERIALIZED VIEW作成時にORA-04052が発生

Oracleエラー対応(ORA-04052):DDBLINKを経由したMATERIALIZED VIEW作成時にORA-04052が発生

現役DBAが解説 ~Oracleエラー対応~

アプリからの問い合わせ内容

DBAは日々アプリ担当者からの問い合わせに対応しています。
ある日頂いた問い合わせはこちら。

「別ユーザ(BBB)のVIEWを元にしたVIEWは作成できるが、MATERIALIZED VIEWが作成できない」

--ユーザAAAでSQL実行
--VIEW作成は問題無い
SQL> create view AAA.VIEW as
 2 select * from BBB.TEST_VIEW;

View created.

--MATERIALIZED VIEW作成ではエラーが発生する
SQL> create materialized view AAA.MVIEW as
 2 select * from BBB.TEST_VIEW;
select * from BBB.TEST_VIEW

ERROR at line 2:
ORA-04052: error occurred when looking up remote object CCC.TEST_TABLE@TEST_LINK
ORA-00604: error occurred at recursive SQL level 1
ORA-02019: connection description for remote database not found

調査

ORA-4052に書かれている「error occurred when looking up remote object CCC.TEST_TABLE@TEST_LINK」ですが、CREATE文の中には「CCC.TEST_TABLE@TEST_LINK」が無いのに何故いきなりエラー文の中に出てくるのでしょうか。

こちらは調査の結果、SELECT対象であるBBB.TEST_VIEWがプライベートDBLINK(TEST_LINK)経由で別DBのテーブル、CCC.TEST_TABLEを参照して作られたVIEWであることが判明しました。

BBB.TEST_VIEWの作成SQL

CREATE VIEW BBB.TEST_VIEW AS SELECT * FROM CCC.TEST_TABLE@TEST_LINK

このことから、今回のエラーは「BBB.TEST_VIEWを参照しようとしたが、大元のCCC.TEST_TABLE@TEST_LINKが見つからない」ためであると予測できます。

しかし、問い合わせにある通り、同じSELECT文を構文に入れたVIEWは作成できています。
更に、ユーザAAAでSELECT文単体(select * from BBB.TEST_VIEW)を実行したところ正常にデータが取得できたため、SELECT文自体に問題は無いことになります。

では何故MATERIALIZED VIEW作成時のみエラーが発生したのでしょうか。

原因

各種調査を続けた結果、今回のエラーはOracleの内部転換動作によるものでした。内部転換動作とは、Oracleが内部的にVIEWやSYNONYMを実オブジェクトに自動的に変換する動きで、MATERIALIZED VIEW関連動作時のみ作用します。

今回の場合、VIEW作成では内部転換動作が起きず、内部的にもBBB.TEST_VIEWを見る動きになります。

select * from BBB.TEST_VIEW;

しかし、MATERIALIZED VIEW作成では内部転換動作が発生し、内部的にはBBB.TEST_VIEWではなく、実オブジェクトであるCCC.TEST_TABLE@TEST_LINKを見るように変換されてしまいます。

select * from CCC.TEST_TABLE@TEST_LINK;

そしてユーザAAAは、ユーザBBBが持つプライベートDBLINK(TEST_LINK)を利用できません。そのため、ユーザAAAはDBLINK経由の参照ができずORA-04052が発生してしまった、という訳です。

対応策

本エラーに対し、考えられる対応策は下記3つとなります。

①ユーザBBBのプライベートDBLINK(TEST_LINK)をパブリックDBLINKに変更する

パブリックDBLINKなら、どのユーザからでも利用できるためエラーが回避できます。
ただし、全ユーザがパブリックDBLINK経由でオブジェクトを参照できてしまうためセキュリティ面で注意が必要です。

②ユーザAAAにも同名のプライベートDBLINK(TEST_LINK)を作る

CCC.TEST_TABLEを参照できる同名のプライベートDBLINKをユーザAAAに作ることで、ユーザAAAから「CCC.TEST_TABLE@TEST_LINK」が参照可能となり、エラーが回避できます。

③参照先のVIEW(BBB.TEST_VIEW)をMATERIALIZED VIEWもしくはTABLEに変更する

参照先を実データを持つオブジェクトにすれば、参照時にDBLINK自体使用しませんのでエラーが回避できます。この場合は、実データを持つことからデータ管理およびデータ量に注意が必要です。

 

実際、こちらの問い合わせでは最も影響範囲が小さいと思われる②をDBAから提案し、無事MATERIALIZED VIEWを作成することができました。

まとめ

DBLINKを経由するMATERIALIZED VIEW作成時は、SELECT文単体では問題無くとも、Oracleの内部転換動作によるオブジェクト参照不可エラーが発生する場合があります。

エラー発生時は、参照経路においてDBLINKを使用しているオブジェクトを確認して頂き、状況に応じて対応策を講じてください。