ヘッダーをスキップ
Oracle® Database Heterogeneous Connectivityユーザーズ・ガイド
11gリリース2 (11.2)
E94922-01
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

3 Oracle Database Gatewayの機能

この章では、Oracle Database Gatewayの主要な機能について説明します。この章の内容は、次のとおりです。

3.1 SQLとPL/SQLのサポート

SQL文の変換とデータ型のマッピングは、機能に基づいて実行されます。PL/SQLコールは、Oracle以外のシステムのストアド・プロシージャにマップされます。SQL文に関してリモート・システムに機能がない場合は、単純な問合せが発行されるか、文が複数の問合せに分割されます。その後、Oracleデータベースでの後処理によって必要な結果が得られます。

異機種間サービスでは、ほとんどの場合はOracle以外のシステムをOracle分散セッションに取り込むことができますが、これにはいくつかの制限があります。一般的な制限事項を次に示します。

3.2 異機種間レプリケーション

Oracle以外のシステムとOracle Databaseの間では、マテリアライズド・ビューを使用してデータをレプリケートできます。


注意:

OracleとOracle以外のデータベースの間で情報をレプリケートするには、Oracle Streamsと呼ばれる別の方法もあります。

Oracle Streamsの使用方法の詳細は、『Oracle Streams概要および管理』を参照してください。


マテリアライズド・ビューは、特定の時点でOracle以外のマスター・サイトの表からキャプチャされたデータをインスタンス化します。この時点はリフレッシュ操作によって定義され、リフレッシュ操作が、このデータをOracle Databaseにコピーし、Oracleシステム上のコピーをOracle以外のシステムのマスター・コピーと同期します。その後、マテリアライズド・データがOracle Databaseでビューとして使用できるようになります。

レプリケーション機能は、リフレッシュをスケジュールし、マテリアライズド・ビューを管理しやすいようにレプリケーション・グループに収集するためのメカニズムを提供します。リフレッシュ・グループにより、複数のマテリアライズド・ビューをシングル・オブジェクトと同様にリフレッシュできます。

異機種間レプリケーションのサポートは、必ずOracle間レプリケーション機能全体のサブセットに限定されます。

Oracleの異機種間サービス機能を介したOracle以外のデータへのアクセスには、その他の制限が適用されます。次に最も重要な制限事項を示します。

次の例に、Oracle以外のシステムからOracleデータ・ストアにデータをレプリケートする3つのマテリアライズド・ビューの基本設定と使用例を示します。


注意:

次の例で、remote_dbはOracle DatabaseからアクセスするOracle以外のシステムを指します。

これらの例を環境にあわせて変更してください。そのままの状態では実行しないでください。


例1: 異機種間レプリケーションに使用するマテリアライズド・ビューの作成

この例では、以降の例に使用する3つのマテリアライズド・ビューを作成します。

  1. customer@remote_db表の主キーのマテリアライズド・ビューを作成します。

    CREATE MATERIALIZED VIEW pk_mv REFRESH COMPLETE AS
      SELECT * FROM customer@remote_db WHERE "zip" = 94555;
  1. orders@remote_db表およびcustomer@remote_db表の副問合せのマテリアライズド・ビューを作成します。

    CREATE MATERIALIZED VIEW sq_mv REFRESH COMPLETE AS
      SELECT * FROM orders@remote_db o WHERE EXISTS
        (SELECT c."c_id" FROM customer@remote_db c
           WHERE c."zip" = 94555 and c."c_id"  = o."c_id" );
  1. remote_db上の複数の表からのデータの複合マテリアライズド・ビューを作成します。

    CREATE MATERIALIZED VIEW cx_mv
      REFRESH COMPLETE AS
      SELECT  c."c_id", o."o_id"
        FROM customer@remote_db c,
             orders@remote_db o,
             order_line@remote_db ol
        WHERE c."c_id" = o."c_id"
        AND o."o_id" = ol."o_id";

例2: 異機種間レプリケーションに使用するリフレッシュ・グループの設定

BEGIN
  dbms_refresh.make('refgroup1',
   'pk_mv, sq_mv, cx_mv',
   NULL, NULL);
 END;
 /

例3: 3つのマテリアライズド・ビューすべての強制リフレッシュ

BEGIN
   dbms_refresh.refresh('refgroup1');
END;
 /

関連項目:

マテリアライズド・ビューとレプリケーション機能の詳細は、『Oracle Databaseアドバンスト・レプリケーション』を参照してください。

3.3 パススルーSQL

パススルーSQL機能を使用すると、文を最初にOracle Databaseで解析せずに直接Oracle以外のシステムに送ることができます。この機能は、Oracle以外のシステムでOracleに等価文のない文での操作が見込まれる場合に役立ちます。

この項には、次の項目が含まれます。

3.3.1 DBMS_HS_PASSTHROUGHパッケージの使用

PL/SQLのDBMS_HS_PASSTHROUGHパッケージを使用すると、Oracle以外のシステムで直接パススルーSQL文を実行できます。このパッケージで実行される文は、標準のSQL文と同じトランザクションで実行されます。

DBMS_HS_PASSTHROUGHパッケージは仮想パッケージです。概念上は、Oracle以外のシステムに常駐します。ただし、実際には、このパッケージのコールは異機種間サービスにより仲介され、1つ以上の異機種間サービス・コールにマップされます。次に、これらの異機種間サービス・コールは、ドライバによりOracle以外のシステムのAPIにマップされます。クライアント・アプリケーションは、Oracle以外のシステムのストアド・プロシージャをコールする場合と同じ方法で、データベース・リンクを介してパッケージ内のプロシージャをコールします。異機種間サービスにより実行される特殊処理は、ユーザーに対して透過的です。


関連項目:

このパッケージの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

3.3.2 パススルーSQLの使用による影響の検討

Oracle以外のシステムでトランザクションを暗黙的にコミットまたはロールバックするパススルーSQL文を実行すると、そのトランザクションに影響します。たとえば、一部のシステムでは、データ定義言語(DDL)文を含むトランザクションが暗黙的にコミットされます。Oracle Databaseは迂回されるため、トランザクションがOracle以外のシステムにコミットされたことを認識しません。そのため、Oracle Databaseではトランザクションがコミットされない間に、Oracle以外のシステムでデータがコミットされる可能性があります。

Oracle Databaseでトランザクションがロールバックされると、Oracle DatabaseとOracle以外のシステム間でデータに一貫性がなくなる可能性があります。このような状況では、グローバルなデータ非一貫性が発生します。

アプリケーションで通常のCOMMIT文を実行すれば、Oracle DatabaseはOracle以外のシステムと分散トランザクションを調整できることに注意してください。パススルー機能を使用して実行される文は、分散トランザクションの一部となります。

3.3.3 パススルーSQL文の実行

次の表に、DBMS_HS_PASSTHROUGHパッケージで提供されるファンクションとプロシージャを示します。これらを使用してパススルーSQL文を実行できます。

プロシージャ/ファンクション 説明
OPEN_CURSOR カーソルのオープン。
CLOSE_CURSOR カーソルのクローズ。
PARSE 文の解析。
BIND_VARIABLE IN変数のバインド。
BIND_OUT_VARIABLE OUT変数のバインド。
BIND_INOUT_VARIABLE IN OUT変数のバインド。
EXECUTE_NON_QUERY 非問合せ文の実行。
EXECUTE_IMMEDIATE バインド変数なしの非問合せ文の実行。
FETCH_ROW 問合せからの行のフェッチ。
GET_VALUE SELECT文からの列値の取得、またはOUTバインド・パラメータの取得。

3.3.3.1 非問合せの実行

非問合せには、次の文および文のタイプが含まれます。

  • INSERT

  • UPDATE

  • DELETE

  • DDL

非問合せ文を実行するには、EXECUTE_IMMEDIATEファンクションを使用します。たとえば、データベース・リンクsalesdbを使用してアクセスできるOracle以外のシステムでDDL文を実行するには、次のように入力します。

DECLARE
  num_rows INTEGER;

BEGIN
  num_rows := DBMS_HS_PASSTHROUGH.EXECUTE_IMMEDIATE@salesdb
            ('CREATE TABLE dept1 (n SMALLINT, loc CHARACTER(10))');
END;

変数num_rowsには、実行された文によって影響を受ける行数が割り当てられます。DDL文の場合は、0(ゼロ)が戻されます。EXECUTE_IMMEDIATEファンクションでは問合せを実行できず、バインド変数を使用できないことに注意してください。

3.3.3.1.1 バインド変数の使用: 概要

バインド変数を使用すると、同じSQL文に様々な値を指定して複数回使用できるため、SQL文に必要な解析回数が減少します。たとえば、表に4行挿入する場合は、SQL文を1回解析し、行ごとにバインドして実行できます。1つのSQL文に0個以上のバインド変数を使用できます。

バインド変数を使用してパススルーSQL文を実行する手順は、次のとおりです。

  1. カーソルをオープンします。

  2. Oracle以外のシステムでSQL文を解析します。

  3. 変数をバインドします。

  4. Oracle以外のシステムでSQL文を実行します。

  5. カーソルをクローズします。

図3-1に、バインド変数を使用した非問合せ実行のフロー図を示します。

図3-1 非問合せ用パススルーSQLフロー図

図3-1の説明が続きます
「図3-1 非問合せ用パススルーSQLフロー図」の説明

3.3.3.1.2 INバインド変数の使用

文でバインド変数を指定する方法は、Oracle以外のシステムの構文により決定されます。たとえば、Oracleシステムでは、先行コロンを使用してバインド変数を定義します。次に例を示します。

...
UPDATE emp
SET sal=sal*1.1
WHERE ename=:ename;
...

この文で、enameはバインド変数です。Oracle以外のシステムでは、バインド変数の指定に疑問符が必要になる場合があります。次に例を示します。

...
UPDATE emp
SET sal=sal*1.1
WHERE ename= ?;
...

バインド変数の手順では、ホスト・プログラム変数(この場合はPL/SQL)をこれらの各バインド変数と位置的に関連付ける必要があります。たとえば、前述の文を実行するには、次のPL/SQLプログラムを使用します。

DECLARE
  c INTEGER;
  nr INTEGER;
BEGIN
  c := DBMS_HS_PASSTHROUGH.OPEN_CURSOR@salesdb;
  DBMS_HS_PASSTHROUGH.PARSE@salesdb(c,
        'UPDATE emp SET SAL=SAL*1.1 WHERE ename=?');
  DBMS_HS_PASSTHROUGH.BIND_VARIABLE@salesdb(c,1,'JONES');
  nr:=DBMS_HS_PASSTHROUGH.EXECUTE_NON_QUERY@salesdb(c);
  DBMS_OUTPUT.PUT_LINE(nr||' rows updated');
  DBMS_HS_PASSTHROUGH.CLOSE_CURSOR@salesdb(c);
END;
3.3.3.1.3 OUTバインド変数の使用

Oracle以外のシステムはOUTバインド変数をサポートできます。OUTバインド変数を使用すると、その値はSQL文の実行後まで認識されません。

OUTバインド変数はSQL文の実行後に移入されますが、Oracle以外のシステムでは、特定のバインド変数がOUTバインド変数であることをSQL文の実行前に認識する必要があります。バインド変数がOUTバインド変数であることを指定するには、BIND_OUT_VARIABLEプロシージャを使用します。

SQL文の実行後は、GET_VALUEプロシージャを使用してOUTバインド変数の値を取得できます。

3.3.3.1.4 IN OUTバインド変数の使用

1つのバインド変数でIN変数とOUT変数を兼ねることができます。つまり、SQL文の実行前にバインド変数の値がわかっている必要があります。また、SQL文の実行後に値を変更できます。

IN OUTバインド変数の場合は、BIND_INOUT_VARIABLEプロシージャを使用してSQL文の実行前に値を提供する必要があります。SQL文の実行後は、GET_VALUEプロシージャを使用してバインド変数の新規の値を取得します。

3.3.3.2 問合せの実行

問合せでは、非問合せとは異なり、SELECT文から結果セットが取得されます。結果セットは、カーソルの使用により取得されます。

図3-2に、パススルーSQL問合せのステップを示します。システムでSELECT文が解析された後、FETCH_ROWプロシージャで結果セットの各行を取得できます。行が取得された後、GET_VALUEプロシージャを使用してSELECT構文のリスト項目をプログラム変数に取り出します。すべての行が取得された後に、カーソルをクローズできます。

図3-2 問合せ用パススルーSQL

図3-2の説明が続きます
「図3-2 問合せ用パススルーSQL」の説明

すべての行を取得する必要はありません。カーソルのオープン後は、いつでもカーソルをクローズできます。


注意:

取得するのは一度に1行ですが、異機種間サービスでは、複数行をバッファに入れて1回のラウンドトリップでOracle以外のデータ・システムからフェッチすることで、Oracle DatabaseとOracle以外のシステム間のラウンドトリップが最適化されます。

次の例では、問合せが実行されます。

DECLARE
   val  VARCHAR2(100);
   c    INTEGER;
   nr   INTEGER;
BEGIN
  c := DBMS_HS_PASSTHROUGH.OPEN_CURSOR@salesdb; 
  DBMS_HS_PASSTHROUGH.PARSE@salesdb(c, 
    'select ENAME
     from   EMP
     where  DEPTNO=10');
  LOOP
    nr := DBMS_HS_PASSTHROUGH.FETCH_ROW@salesdb(c);
    EXIT WHEN nr = 0;
    DBMS_HS_PASSTHROUGH.GET_VALUE@salesdb(c, 1, val);
    DBMS_OUTPUT.PUT_LINE(val);
  END LOOP;  
  DBMS_HS_PASSTHROUGH.CLOSE_CURSOR@salesdb(c); 
END;

SELECT文の解析後は、FETCH_ROWファンクションが0(ゼロ)を戻すまで、ループ内で行がフェッチされて出力されます。

3.4 結果セットのサポート

各種リレーショナル・データベースでは、ストアド・プロシージャで結果セット(1つ以上の行セット)を戻すことができます。

従来、データベースのストアド・プロシージャの動作は、高水準プログラミング言語のプロシージャと同じでした。引数の数は一定で、INOUTまたはIN OUT型を使用できました。プロシージャにn引数が指定されている場合は、結果として最大n個の値が戻されます。ただし、ストアド・プロシージャでSELECT * FROM empなどの問合せを実行して結果を戻す必要がある場合があります。emp表の列数は固定ですが、プロシージャの作成時には行数を指示する手段がありません。このため、このような問合せの結果を戻す従来のストアド・プロシージャを作成できませんでした。その結果、複数のリレーショナル・データベース・ベンダーがストアド・プロシージャから結果セットを戻す機能を追加していますが、戻す方法はリレーショナル・データベースごとに異なっています。

Oracleには、REF CURSORというデータ型が用意されています。ストアド・プロシージャでは、他のすべてのOracleデータ型と同様に、このデータ型をINまたはOUT引数として使用できます。Oracle Databaseでは、ストアド・プロシージャにはREF CURSOR型の出力引数が必要です。次に、SQL文のカーソルをオープンし、その出力パラメータのそのカーソルにハンドルを置きます。これにより、コール元は他のカーソルの場合と同じ方法でREF CURSORから取得できます。

Oracle Databaseは、結果セットを戻す以外に多くの処理を行うことができます。REF CURSORデータ型をPL/SQLルーチンに入力引数として渡し、クライアント・プログラムとPL/SQLルーチン間、または複数のPL/SQLルーチン間でやり取りできます。

この項には、次の項目が含まれます。

3.4.1 Oracle以外のシステムでの結果セットのサポート

Oracle以外の複数のシステムで、ストアド・プロシージャにより結果セットを戻すことができますが、その方法は異なります。通常、Oracle以外のデータベースでの結果セットのサポートは次の2つのモデルのいずれかに基づいています。

  • モデル1: 結果セットのサポート

    ユーザーは、ストアド・プロシージャの作成時に、そのストアド・プロシージャが戻すことのできる結果セットの最大数を明示的に指定できます。実行時には、ストアド・プロシージャは0(ゼロ)から指定された最大数の範囲内で結果セットをオープンできます。ストアド・プロシージャの実行後に、クライアント・プログラムは埋込みSQLディレクティブを使用するか、クライアントのライブラリ・ファンクションをコールして、これらの結果セットへのハンドルを取得できます。その後、クライアント・プログラムは、通常のカーソルと同様に結果セットから取得できます。

  • モデル2: 結果セットのサポート

    このモデルでは、ストアド・プロシージャから戻される結果セット数の制限は指定されていません。モデル1とOracle Databaseにはどちらも制限があります。Oracle Databaseでは、ストアド・プロシージャから戻すことができる結果セットの数はREF CURSOR OUT引数の数以下です。モデル1では、ストアド・プロシージャ言語のディレクティブを使用して上限が指定されます。モデル2がOracle Databaseおよびモデル1と異なるもう1つの点は、これらでは結果セットに対するハンドルが戻されないことです。かわりに、これらはストアド・プロシージャから戻された結果セット全体を送信します。Oracle DatabaseではハンドルはREF CURSOR OUT引数です。モデル1では、これはストアド・プロシージャの実行後に別に取得されます。Oracle Databaseとモデル1の両方で、ハンドルが取得された後で、ハンドルに対するフェッチを実行して結果セットのデータが取得されます。複数のカーソルが開いており、任意の順序でフェッチすることができます。ただし、モデル2のケースでは、すべてのデータがすでに送信されています。ストアド・プロシージャによって決定された順序で結果セットが届き、プロシージャの出力引数が最後に届きます。最初の結果セット全体を取得してから2番目の結果セット全体を取得し、すべての結果セットを取得するまで続ける必要があります。最後に、ストアド・プロシージャのOUT引数が取得されます。

3.4.2 異機種間サービスでの結果セットのサポート

結果セットのサポートは、Oracle以外のデータベースではそれぞれ異なっています。これらすべてをOracleのREF CURSORモデルにマップする必要があります。Oracle以外のシステム間では動作が異なるため、異機種間サービスでの結果セットのサポートは、接続先となるOracle以外のシステムに応じて2つの方法のいずれかになります。

異機種間サービスでの結果セットのサポートについては、次の注意事項があります。

  • 結果セットのサポートは異機種間サービスの汎用コードに含まれますが、この機能をゲートウェイで動作させるには、ドライバもこれを実装する必要があります。すべてのドライバが結果セットのサポートを実装しているわけではありません。ゲートウェイがサポートされることを確認する必要があります。

  • 異機種間サービスでは、ストアド・プロシージャからのREF CURSOR OUT引数がサポートされます。INおよびIN OUT引数はサポートされません。

  • REF CURSOR OUT引数は、すべて匿名参照カーソルです。異機種間サービスで戻されるREF CURSORには型がありません。

3.4.2.1 結果セット: カーソル・モード

Oracle以外のシステムのストアド・プロシージャから戻される各結果セットは、OracleドライバによりREF CURSOR型のOUT引数にマップされます。クライアント・プログラムは、REF CURSOR型の複数のOUT引数を持つストアド・プロシージャを検知します。ストアド・プロシージャの実行後に、クライアント・プログラムはOracleストアド・プロシージャにより戻されるREF CURSORの場合と同じ方法で、そのREF CURSORからフェッチできます。3.4.1.1項で説明したように、異機種間サービスはゲートウェイへの接続時にカーソル・モードになります。

3.4.2.2 結果セット: 逐次モード

特定のストアド・プロシージャが戻すことのできる結果セットには最大数があります。戻される結果セットの数は、ストアド・プロシージャのREF CURSOR OUT引数の数以下です。戻される結果セットの数は、この上限より少なくてもかまいませんが、上限を超えることはできません。

3.4.1.2項で説明したシステムの場合、戻すことのできる結果セットの最大数はありません。モデル1(3.4.1.1項)の場合は、プロシージャが戻すことのできる結果セットの最大数、およびドライバが異機種間サービスに戻すことのできる結果セットの最大数は、REF CURSOR OUT引数の数により、ストアド・プロシージャに指定されています。ストアド・プロシージャの実行時に、戻される結果セットが最大数より少なければ、その他のREF CURSOR OUT引数はNULLに設定されます。

モデル2のデータベース・サーバーのもう1つの問題は、データベースによって送信された順序で結果セットを取得する必要があることです。このため、異機種間サービスがこれらのデータベースに接続するときにカーソル・モードで実行できません。これらのストアド・プロシージャによって戻される結果セットにアクセスするには、異機種間サービスを逐次モードにする必要があります。

逐次モードでは、ドライバから戻されるプロシージャ記述に次の情報が含まれます。

  • リモート・ストアド・プロシージャのすべての入力引数

  • 出力引数はなし

  • REF CURSOR型のOUT引数1つ(ストアド・プロシージャから戻される最初の結果セットに対応)

クライアントは、このREF CURSORからフェッチし、仮想パッケージ・ファンクションDBMS_HS_RESULT_SET.GET_NEXT_RESULT_SETをコールして、次の結果セットに対応するREF CURSORをフェッチします。すべての結果セットが取得されるまでこのファンクション・コールが繰り返されます。最後に戻される結果セットは、リモート・ストアド・プロシージャのOUT引数となります。

逐次モードの主な制限事項は、次のとおりです。

  • リモート・ストアド・プロシージャから戻された結果セットは、送信された順に取得される必要があります。

  • ストアド・プロシージャが実行されると、以前に実行されたストアド・プロシージャから戻された結果セットがすべて(データが取得されたかどうかに関係なく)クローズされます。


    関連項目:

    ゲートウェイを介した結果セットのサポート方法の詳細は、ご使用のゲートウェイ固有のマニュアルを参照してください。

3.5 データ・ディクショナリ変換

ほとんどのデータベース・システムには、なんらかの形式のデータ・ディクショナリがあります。データ・ディクショナリは、システムの各種ユーザーにより作成されたデータベース・オブジェクトに関する情報のコレクションです。リレーショナル・データベースの場合、データ・ディクショナリはデータベース内のデータに関する情報を含む表およびビューのセットです。この情報には、システムを使用するユーザーやユーザーが作成したオブジェクト(表、ビュー、トリガーなど)に関する情報が含まれます。ほとんどすべてのデータ・ディクショナリには(データベース・システムに関係なく)同じ情報が含まれていますが、情報の編成方法はデータベース・システムごとに異なります。

たとえば、Oracleのデータ・ディクショナリ・ビューALL_CATALOGには、データベース内の表、ビューおよび順序のリストが表示されます。これには3つの列があり、1列目はオブジェクトの所有者名を示すOWNER、2列目はオブジェクト名を示すTABLE_NAME、3列目はデータ型を示すTABLE_TYPEです。このフィールドの値は、オブジェクト型に応じてTABLEVIEWSEQUENCEなどです。ただし、Sybaseの場合、同じ情報がsysusersおよびsysobjectsという2つの表に格納され、その列名はOracleのALL_CATALOG表の列名とは異なります。また、Oracle Databaseでは、テーブルのタイプはTABLEまたはVIEWの値で始まります。たとえば、Sybaseでは、Uはユーザー表、Sはシステム表、Vはビューを意味します。

クライアント・プログラムがSybaseシステムにあるALL_CATALOG表からの情報を必要とする場合は、ALL_CATALOG@database_linkを参照する問合せをゲートウェイに送信します。この問合せは、異機種間サービスによりsystablesの該当する問合せに変換されてから、たとえば、Sybaseシステムに送信されます。

SELECT SU."name" OWNER, SO."name" TABLE_NAME,
   DECODE(SO."type", 'U ','TABLE', 'S ', 'TABLE', 'V ', 'VIEW')
TABLE_TYPE
FROM "dbo"."sysusers"@remote_db  SU, "dbo"."sysobjects"@remote_db SO
WHERE SU."uid" = SO."uid" AND
   (SO."type" = 'V' OR SO."type" = 'S' OR SO."type" = 'U');

Oracleデータ・ディクショナリ表に対する問合せの変換を、Oracle以外のシステムのデータ・ディクショナリ表に対する同等の問合せに反映するには、そのOracle以外のシステムのためのデータ・ディクショナリ変換が異機種間サービスで必要です。データ・ディクショナリ変換は、Oracle以外のシステムの1つ以上のデータ・ディクショナリ表(Oracleのデータ・ディクショナリ表と列名や形式が同じ)に対するビューの定義(すなわちSELECT文)です。ほとんどのデータ・ディクショナリ変換はこの例ほど単純ではありません。多くの場合、情報は多数の表に分散しているため、データ・ディクショナリ変換はそれらの表の複雑な結合になります。

場合によっては、Oracle以外のシステムに情報が存在していないため、Oracleデータ・ディクショナリ表に変換が含まれないこともあります。このような場合、ゲートウェイは変換をアップロードできないため、疑似実行と呼ばれる別のアプローチを実装することがあります。ゲートウェイがデータ・ディクショナリ表を疑似実行する場合、ゲートウェイは異機種間サービスに情報を提供し、異機種間サービスはローカル・データベースを問い合せてデータ・ディクショナリ表の説明を取得します。データの取得を求められると、行が選択されなかったとレポートします。

3.6 日時データ型

Oracle Databaseには次の5つの日時データ型があります。

異機種間サービスの汎用コードは、SQLおよびストアド・プロシージャにおいてはOracle日時データ型をサポートします。ただし、異機種間サービスでは、データ・ディクショナリ変換やデータ・ディクショナリ変換を伴う問合せでは、これらのデータ型がサポートされません。

異機種間サービスの汎用コードで日時データ型がサポートされていても、特定のゲートウェイに対するサポートは、Oracle以外のシステム用のドライバに日時のサポートが実装されているかどうかによって異なります。Oracle以外のシステムに制限があるため、サポートがドライバに実装されていても、サポートは部分的になる場合があります。詳細は、ご使用のゲートウェイのドキュメントを参照してください。

ユーザーは、Oracle以外のシステムのタイムスタンプ書式をゲートウェイ初期化ファイル内で設定する必要があります。設定するパラメータは、HS_NLS_TIMESTAMP_FORMATおよびHS_NLS_TIMESTAMP_TZ_FORMATです。また、ユーザーは初期化ファイル内でHS_TIME_ZONEを設定し、Oracle以外のシステムのローカル・タイム・ゾーンも設定する必要があります。


関連項目:

日時データ型の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

3.7 2フェーズ・コミット・プロトコル

異機種間サービスは、2フェーズ・コミット・プロトコルを実装するためのインフラストラクチャを提供します。そのサポート範囲はゲートウェイおよびリモート・システムに応じて異なります。詳細は、ご使用のゲートウェイのドキュメントを参照してください。


関連項目:

2フェーズ・コミット・プロトコルの詳細は、『Oracle Database管理者ガイド』を参照してください。

3.8 ピース単位のLONGデータ型

以前のバージョンのゲートウェイでは、LONGデータ型のサポートが限定されていました。LONGは、最大2GBの文字またはRAWデータ(LONG RAW)を格納するOracleのデータ型です。これらの旧バージョンでは、LONGデータは単一のピースとして扱われていたため、LONGデータのサイズが4MBに制限されていました。このため、処理できるデータのサイズにメモリーとネットワーク帯域幅という制限が課されていました。現行のゲートウェイの機能は、異機種間で2GBのLONGデータ全体をサポートするように拡張されました。ゲートウェイによって、データがエージェントとOracle Database間でピース単位で処理されるようになり、大容量のメモリーとネットワーク帯域幅の要件がなくなりました。

異機種間サービスの初期化パラメータHS_LONG_PIECE_TRANSFER_SIZEを使用すると、転送されるピースのサイズを設定できます。たとえば、異機種間ソースから2GBのLONGデータを取得する場合を考えます。ピースを小さくすると、必要なメモリーは少なくなりますが、すべてのデータを取得するために必要なラウンドトリップは増加します。ピースを大きくすると、ラウンドトリップ回数は減少しますが、内部的に中間ピースを格納するために必要なメモリー容量が増大します。そのため、初期化パラメータを使用して最適のパフォーマンス(つまり、ラウンドトリップ回数とメモリー所要量との最適なトレードオフ)が得られるようにシステムをチューニングできます。初期化パラメータを設定しない場合、デフォルトのピース・サイズとして64KBが使用されます。


注意:

この機能を、クライアント側のLONGデータに対するピース単位操作と混同しないでください。クライアント側でのピース単位のFETCHおよびINSERT操作は、旧バージョンのゲートウェイで動作しており、今後も動作します。クライアント側での唯一の違いは、旧バージョンのゲートウェイでフェッチできるLONGデータは最大4MBのみであったのに対して、このバージョンでは2GBのLONGデータを取得できることです。4MBはこのデータ型の最大容量のわずか0.2%であるため、これは大幅な改善です。

3.9 SQL*PlusのDESCRIBEコマンド

SQL*Plus DESCRIBEコマンドを使用してOracle以外のシステムのオブジェクトを記述できます。ただし、いくつかの制限事項があります。たとえば、異機種間リンクを使用した場合には、パッケージ、順序、シノニムまたは型を記述できません。

3.10 分散環境におけるSQLの制約

この項では、分散環境におけるSQLに対する制約について説明します。これらの制約は、Oracle以外のシステムまたはリモートOracleデータベースへのアクセスが行われる分散環境に適用されます。

この項には、次の項目が含まれます。

3.10.1 リモート参照と異機種間参照


注意:

異機種間アクセスに関するルールの多くは、リモート参照にも適用されます。詳細は、『Oracle Database管理者ガイド』の分散データベースに関する項を参照してください。

文は、制限付きではありますが、その文で参照されているデータベース・ノードまたはローカル・ノード上で実行できます。参照されるオブジェクトすべてが1つの参照先ノードに解決される場合、Oracleはそのノードで問合せの実行を試みます。/*+ REMOTE_MAPPED */または/*+ DRIVING_SITE */ヒントを使用すると、参照先ノードで強制的に実行できます。文が発行された場所とは異なるノードに転送される場合、その文をリモート・マップ文と呼びます。

リモート・マップ文に対しては、完全なデータ型チェックのサポートがあります。チェックの結果により、一貫したデータ型チェックと完全なデータ型の強制が提供されます。


関連項目:

4.5項「Oracleデータベース・サーバーのSQL構文の処理」

文のリモート・マップを可能にする方法には、特定のルールまたは制限が適用されます。これらのルールが遵守されていない場合、エラーが発生します。発行される文にこれらのルールすべてとの一貫性があるかぎり、ルールの適用順序は関係ありません。ルールや制限については、3.10.2項を参照してください。

分散環境でのリモート・マッピングにSQLを使用する場合は、異なる制約が存在します。この分散環境には、Oracle Database Gatewayを介してアクセスされるOracle以外のデータベースのみでなく、リモートのOracleデータベースも含めることができます。

3.10.2 重要な制限事項

次の項では、分散環境でリモート・マッピングにSQLを使用する場合に存在する様々なルールまたは制限について説明します。


注意:

以降の例では、remote_dbはOracle以外のリモート・システム、remote_oracle_dbはリモートのOracle Databaseを指します。

ルールA: データ定義言語文はリモート・マップできません。

Oracleのデータ定義言語では、ターゲット・オブジェクトの構文にはリモート参照の位置がありません。リモート参照を含むデータ定義言語文は常にローカルに実行されます。異機種間サービスの場合、これは、SQLを使用してOracle以外のデータベースにデータベース・オブジェクトを直接作成できないことを意味します。

ただし、パススルーSQLを使用して間接的に作成する方法があります。次にその例を示します。

DECLARE
  num_rows INTEGER;
BEGIN 
  num_rows := DBMS_HS_PASSTHROUGH.EXECUTE_IMMEDIATE@remote_db 
  (
     'create table x1 (c1 char, c2 int)'
  ); 
END; 

ルールB: リモート・ターゲット表を使用するINSERT、UPDATEおよびDELETE文はリモート・マップする必要があります。

このルールは、リモートのOracleデータベースよりもOracle以外のリモート・データベースの場合に限定的です。これは、Oracle以外のシステムの表に対するデータ操作言語(DML)文の実行中は、リモート・システムで元のOracleデータベースからデータをフェッチできないためです。

たとえば、ローカルのemp表からローカルの全従業員をOracle以外のリモートのemp表に挿入するには、次の文を使用します。

INSERT INTO emp@remote_db SELECT * FROM emp;

この文は、リモート・データベースにリモート・マップされます。リモート・データベースに送信されるリモート・マップ文には、empに関する元のデータベースへのリモート参照が含まれます。このようにリモート・データベースが受信するリモート・リンクを、コールバック・リンクと呼びます。


注意:

コールバック・リンクは、汎用の異機種間サービスでサポートされていても、すべての異機種間サービス・エージェントに実装されているとはかぎりません。使用中のデータベース・ゲートウェイでコールバック・リンクが動作するかどうかは、データベース・ゲートウェイのマニュアルを参照して判断してください。

特定のゲートウェイにコールバック・リンクがサポートされていない場合、前述のINSERT文では次のエラーが戻されます。

ORA-02025: all tables in the SQL statement must be at the remote database

このエラーを回避するには、PL/SQLブロックを記述します。次に例を示します。

DECLARE 
CURSOR remote_insert IS SELECT * FROM emp;
BEGIN 
   FOR rec IN remote_insert LOOP
    INSERT INTO emp@remote_db (empno, ename, deptno) VALUES (
      rec.empno,
      rec.ename, 
      rec.deptno 
    );  
   END loop;
END;

もう1つの特殊な事例には、USERUSERENVおよびSYSDATEなど、セッション固有のSQL関数が関係します。これらの関数は、元のサイトで実行する必要があります。これらの関数を含むリモート・マップ文には、コールバック・リンクが含まれます。コールバックがサポートされていないOracle以外のデータベースの場合は、(デフォルトで)制限エラーになる可能性があります。

たとえば、次の文を考えてみます。

DELETE FROM emp@remote_db WHERE hiredate > sysdate;

この文は次のエラー・メッセージを戻します。

ORA-02070: database REMOTE_DB does not support special functions in this context 

このエラーを解決するには、次のように特殊関数をバインド変数で置き換える必要があります。次に例を示します。

DELETE FROM emp@remote_db WHERE hiredate > :1;

ルールC: NESTED TABLE型の列、ユーザー定義型の列、不透明型の列またはREF型の列を含む表などのオブジェクト機能は、リモート・マップできません。

現在、異機種間アクセスの場合、これらの列型はサポートされていません。したがって、この制限が直接発生することはありません。

ルールD: リモート・サイトでサポートされていない演算子および構成メンバーを含むSQL文は、リモート・マップできません。

つまり、INSERTUPDATEDELETEの場合、SQL文は実行できません(ルールBを参照)。ただし、サポートされていない演算子または構成メンバーが、コールバック・リンクで実行できる場合、SQL文を実行できる場合があります。

SELECTの場合は、その他のルールが対象の文をリモート・マップするように要求していないかぎり、このルールの影響を受ける文でも常に実行できます。このルールの影響を受けるSELECT文は、リモートのSELECT操作を介して必要なすべてのデータをフェッチし、サポートされない演算子を処理するか、ローカルSQLエンジンを使用してローカルに構成することにより実行されます。

リモートのSELECT操作とは、ローカル表データの行を取得する操作とは異なり、リモート表データの行を取得する操作です。リモートSELECTの場合の最悪のケースは、全表スキャンです。全表スキャンは、リモート表のすべてのデータをネットワークを介してフィルタせずにフェッチすることです(SELECT * FROM EMPなど)。

全表スキャンは高コストであるため、Oracleでは回避するよう試みます。リモート表に使用可能な索引がある場合は、ネットワークでフェッチされる行の数を減らすために、これらの索引をWHERE句の条件で使用します。

Oracle Databaseにより生成されたSQL文をチェックするには、その文を記述し、REMOTE操作ごとにEXPLAIN PLAN表のOTHER列を問い合せます。


関連項目:

リモート参照を含むEXPLAIN PLANを解析する方法の詳細は、3.11.1項を参照してください。

たとえば、次の文を考えてみます。

SELECT COUNT(*) FROM emp@remote_db WHERE hiredate < sysdate;

この文では次の出力が戻されます。

COUNT(*)  
----------
        14
1 row selected.

リモート表スキャンは次のとおりです。

SELECT hiredate FROM emp;

sysdateremote_dbまたは評価ルールでサポートされていないため、フィルタに変換される条件を生成してリモート操作に渡すことはできません。そのため、sysdateはローカルに実行する必要があります。


注意:

リモート表スキャン操作は元の問合せについては一部のみ関連するため、受信行数が予想より大幅に多くなり、パフォーマンスが大幅に低下する場合があります。

ルールE: 表の式を含むSQL文はリモート・マップできません。

異機種間アクセス・モジュールでは表の式がサポートされていないため、この制限が直接発生することはありません。

ルールF: SQL文でLONGデータが選択される場合は、その文をLONGを含む表が常駐するノードにマップする必要があります。

次のタイプの文を考えてみます。

SELECT long1 FROM table_with_long@remote_db, dual; 

(コールバック・リンクがサポートされていない場合)前述の文は次のエラー・メッセージを戻します。

ORA-02025: all tables in the SQL statement must be at the remote database

ルールG: SQL文がSELECT...FOR UPDATE OF...形式の場合、その文はFOR UPDATE OF句で参照される列を持つ表が常駐するノードにマップする必要があります。

SQL文がSELECT...FOR UPDATE OF...形式の場合、その文はFOR UPDATE OF句で参照される列を持つ表が常駐するノードにマップする必要があります。

たとえば、次の文を考えてみます。

SELECT ename FROM emp@remote_db WHERE hiredate < sysdate FOR UPDATE OF empno;

前述の文は、リモート・マップが不可能な場合、次のエラー・メッセージを戻します。

ORA-02070: database REMOTE_DB does not support special functions in this context 

ルールH: SQL文にSEQUENCEまたは順序が含まれている場合は、その文を各順序が常駐するサイトにマップする必要があります。

リモートではOracle以外の順序はサポートされないため、このルールが異機種間アクセス・モジュールに適用されることはありません。

ルールI: 文に1つ以上のユーザー定義演算子が含まれている場合は、その文を各演算子が定義されているノードにマップする必要があります。

文にユーザー定義演算子が含まれている場合は、その文全体をその演算子が定義されているデータベース・ノードにリモート・マップする必要があります。

ルールJ: 重複するバインド変数を含む文はリモート・マップできません。

この制限を回避するには、一意のバインド変数を使用して数値でバインドします。

3.11 Oracleのオプティマイザと異機種間サービス

Oracleのオプティマイザを異機種間サービスと併用できます。異機種間サービスは、Oracle以外のシステムのそれぞれの表について特定の表および索引統計情報を収集し、この情報をOracle Databaseに渡します。Oracleのコストベース・オプティマイザは、この情報を問合せ計画の作成時に使用します。

その他にも、コストベース・オプティマイザでは複数の最適化が実行されます。最も重要な最適化は、リモート・ソートの排除とリモート結合です。

この項には、次の項目が含まれます。

3.11.1 例: 索引統計と表統計の使用

Oracleデータベースに10行の表を作成する次の文を考えてみます。

CREATE TABLE T1 (C1 number);

DBMS_STATSパッケージを使用して表を分析します。次に例を示します。

DBMS_STATS.GATHER_TABLE_STATS ('SCOTT','T1');
DBMS_STATS.GENERATE_STATS ('SCOTT','T1');

前述の例では、スキーマ名をSCOTTとし、表名をT1としています。DBMS_STATSパッケージの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

Oracle以外のシステムに1000行を含む表を作成します。

次のSQL文を発行します。

SELECT a.* FROM remote_t1@remote_db a, T1 b 
    WHERE a.C1 = b.C1;

Oracleオプティマイザは、エージェントに対して次のSQL文を発行します。

SELECT C1 FROM remote_t1@remote_db;

この文は、Oracle以外のシステムから1000行すべてをフェッチし、Oracleデータベース内で結合を実行します。

remote_t1表のC1列に一意の索引を追加して同じSQL文を再発行すると、エージェントはローカルt1C1の値ごとに次のSQL文を受信します。

...
SELECT C1 FROM remote_t1@remote_db WHERE C1 = ?;
...

注意:

?はバインド・パラメータ・マーカーです。また、Oracleにより生成されたバインド変数を含む結合条件は、ネステッド・ループ結合方法についてのみ生成されます。

SQL実行計画を確認するには、SQL文のEXPLAIN PLANを生成します。最初に、adminディレクトリにutlxplanをロードします。

次のように入力します。

EXPLAIN PLAN FOR SELECT a.* FROM remote_t1@remote_db a, T1 b 
    WHERE a.C1 = b.C1;

次の文を入力してutlxplsユーティリティ・スクリプトを実行します。

@utlxpls

OPERATION REMOTEは、リモートSQLが参照されていることを示します。

どの文が送信されるかを確認するには、次の文を入力します。

SELECT ID, OTHER FROM PLAN_TABLE WHERE OPERATION = 'REMOTE';

3.11.2 例: リモート結合の最適化

ここでは、Oracleデータベースのリモート結合最適化機能の例を示します。


注意:

Oracle以外のシステムからの表を使用するEXPLAIN PLANは、ローカルまたはリモートのOracle表スキャンを使用する同様の文とは異なる場合があります。これは、Oracle以外の表についてOracleで使用可能な統計に制限があるためです。最も重要なのは、Oracle以外の表の非一意索引には列を選択できないことです。使用可能な統計に制限があるため、次の例はリモート結合を実際に実行したときの内容とは異なる場合があり、あくまでも一例にすぎません。

次の例を考えてみます。

EXPLAIN PLAN FOR
SELECT e.ename, d.dname, f.ename, f.deptno FROM
   dept d,
   emp@remote_db e,
   emp@remote_db f
 WHERE e.mgr = f.empno
  AND e.deptno = d.deptno 
  AND e.empno = f.empno;
  
@utlxpls

次のような出力が表示されます。

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------

---------------------------------------------------------------------------
| Id    | Operation                           | Name  | Rows  | Bytes  | Cost
| Inst  |IN-OUT|
---------------------------------------------------------------------------
|   0   | SELECT STATEMENT   |                |  2000   |   197K|   205 |
|*  1   | HASH JOIN          |                |  2000   |   197K|
205 |
|   2   | TABLE ACCESS FULL  | DEPT           |  21     |   462 |     2 |
|*  3   | HASH JOIN          |                |  2000   |   154K|
201 |
|   4   | REMOTE             |                |  2000   | 66000 
|    52 |
|   5   | REMOTE             |                |  2000   | 92000
|    52 |
---------------------------------------------------------------------------

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------

Query Block Name / Hint Alias (identified by operation id):
-----------------------------------------------------------

   1 - sel$1 / D
   2 - sel$1 / D
   3 - sel$1 / F
   4 - sel$1 / F
   5 - sel$1 / E

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------

---------------------------------------------------

   1 - access("E"."DEPTNO"="D"."DEPTNO")
   3 - access("E"."MGR"="F"."EMPNO" AND "E"."EMPNO"="F"."EMPNO")

次の文を発行します。

SET long 300
SELECT other FROM plan_table WHERE operation = 'REMOTE'; 

次のような出力が表示されます。

OTHER
--------------------------------------------------------------------------------

SELECT "EMPNO","ENAME","DEPTNO" FROM "EMP"
SELECT "EMPNO","ENAME","MGR","DEPTNO" FROM "EMP"
SELECT "EMPNO","ENAME","DEPTNO" FROM "EMP"
SELECT "EMPNO","ENAME","MGR","DEPTNO" FROM "EMP"

3.11.3 Oracle以外のアクセスに対するオプティマイザの制限

次に、Oracle以外のシステムへのアクセスに対するオプティマイザの制限を示します。

  • リモート・オブジェクトに関する列統計情報はありません。このため、適切な実行計画が得られない場合があります。実行計画を検証し、ヒントを使用して最適化してください。

  • リモート結合を強制するオプティマイザ・ヒントはありません。ただし、リモート問合せブロック最適化を使用すると、問合せをわずかにリライトしてリモート結合を実現することができます。

    前項の例の記述は、次の形式にリライトできます。

        SELECT v.ename, d.dname, d.deptno FROM dept d,
            (SELECT /*+ NO_MERGE */ 
             e.deptno deptno, e.ename ename emp@remote_db e, emp@remote_db f
                 WHERE e.mgr = f.empno
                 AND e.empno = f.empno;
            )
          WHERE v.deptno = d.deptno;
    
    
    

この例では、リモート結合が保証されています。これは、NO_MERGEヒントを使用してネストした問合せ内に分離されるためです。