9.5 メソッドの設計上の考慮点

メソッドを使用した作業時に検討する特別な考慮点があります。

内容は次のとおりです。

9.5.1 メソッド・ファンクションに対する言語の選択

メソッド・ファンクションは、Oracleでサポートされる任意の言語(PL/SQL、Java、Cなど)で実装できます。

特定のアプリケーション用に言語を選択する場合は、次の要因を考慮してください。

  • 使いやすさ

  • SQLコール

  • 実行速度

  • 同一/異なるアドレス空間

一般に、アプリケーションで主に計算を実行する場合には、Cが適していますが、比較的多くのデータベース・コールを実行する場合は、PL/SQLまたはJavaが適しています。

Cで実装されるメソッドは、外部プロシージャを使用して、サーバーとは別のプロセスで実行されます。それに対して、JavaまたはPL/SQLで実装されるメソッドは、サーバーと同じプロセスで実行されます。

メソッドの実装例

この項で説明する例では、異なる言語で実装されたメソッドを持つオブジェクト型が関係しています。この例では、オブジェクト型ImageTypeは、ID属性(一意に識別されるNUMBER)およびIMG属性(イメージを格納するBLOB)を持ちます。オブジェクト型ImageTypeは、次のメソッドを持ちます。

  • get_nameメソッド: データベース内でイメージの名前を検索してフェッチします。このメソッドは、PL/SQLで実装されています。

  • rotateメソッド: イメージを回転します。このメソッドは、Cで実装されています。

  • clearメソッド: 指定された色の新しいイメージを戻します。このメソッドは、Javaで実装されています。

Cでメソッドを実装する場合は、外部Cルーチンが含まれるライブラリを指す、LIBRARYオブジェクトを定義する必要があります。Javaでメソッドを実装する場合を想定して、この例では、メソッドを持つJavaクラスがコンパイルされ、Oracleにアップロードされていると仮定しています。

例9-12に、オブジェクト型の定義およびそのメソッドを示します。

注意:

タイプ・メソッドは、Javaの静的メソッドのみにマップできます。

関連項目:

例9-12 様々な言語で実装されたメソッドを持つオブジェクト型の作成

CREATE LIBRARY myCfuncs TRUSTED AS STATIC
/

CREATE TYPE ImageType AS OBJECT (
   id   NUMBER, 
   img  BLOB, 
   MEMBER FUNCTION get_name return VARCHAR2,
   MEMBER FUNCTION rotate return BLOB,
   STATIC FUNCTION clear(color NUMBER) return BLOB);/

CREATE TYPE BODY ImageType AS 
   MEMBER FUNCTION get_name RETURN VARCHAR2 
   IS 
    imgname  VARCHAR2(100);
    sqlstmt VARCHAR2(200);
   BEGIN 
      sqlstmt := 'SELECT name INTO imgname FROM imgtab WHERE imgid = id'; 
      EXECUTE IMMEDIATE sqlstmt;
      RETURN imgname;
   END; 
 
   MEMBER FUNCTION rotate RETURN BLOB
   AS LANGUAGE C 
   NAME "Crotate" 
   LIBRARY myCfuncs;
   
   STATIC FUNCTION clear(color NUMBER) RETURN BLOB 
   AS LANGUAGE JAVA 
   NAME 'myJavaClass.clear(oracle.sql.NUMBER) return oracle.sql.BLOB'; 
 
END;
/

9.5.2 静的メソッド

静的メソッドは、SELF値が第1パラメータとして渡されない点で、メンバー・メソッドと異なります。SELFの値が問題ではないメソッドは、静的メソッドとして実装する必要があります。静的メソッドは、ユーザー定義コンストラクタに使用できます。

例9-13では、コンストラクタに類似したメソッドで、明示的な入力パラメータに基づいてその型のインスタンスを作成し、指定された表にそのインスタンスを挿入します。

例9-13 静的メソッドを持つオブジェクト型の作成

CREATE TYPE atype AS OBJECT(
   a1 NUMBER,
   STATIC PROCEDURE newa (
      p1        NUMBER, 
      tabname   VARCHAR2, 
      schname   VARCHAR2));
/
CREATE TYPE BODY atype AS
    STATIC PROCEDURE newa (p1 NUMBER, tabname VARCHAR2, schname VARCHAR2)
      IS
      sqlstmt VARCHAR2(100);
    BEGIN
      sqlstmt := 'INSERT INTO '||schname||'.'||tabname|| ' VALUES (atype(:1))';
      EXECUTE IMMEDIATE sqlstmt USING p1;
    END;
END;
/

CREATE TABLE atab OF atype;

BEGIN
   atype.newa(1, 'atab', 'HR');
END;
/

9.5.3 メンバー・プロシージャでのSELF IN OUT NOCOPYの使用について

メンバー・プロシージャにSELFが宣言されていない場合、そのパラメータ・モードはデフォルトでIN OUTに設定されます。ただし、デフォルトの動作には、NOCOPYコンパイラ・ヒントは含まれません。メンバー・メソッドを参照してください。

IN OUT実パラメータの値が対応する仮パラメータにコピーされるため、パラメータがラージ・オブジェクト型のインスタンスなどの大きなデータ構造を保持している場合、コピーによって実行速度が遅くなります。

パフォーマンスを改善するために、パラメータとしてラージ・オブジェクト型を渡す場合、SELF IN OUT NOCOPYを含められます。次に例を示します。

MEMBER PROCEDURE my_proc (SELF IN OUT NOCOPY my_LOB)

関連項目:

9.5.4 タイプ・メソッドの戻り値に基づくファンクション索引

ファンクション索引は、式またはファンクションの戻り値に基づいた索引です。このファンクションは、オブジェクト型のメソッド・ファンクションの場合もあります。

メソッド・ファンクションに基づくファンクション索引は、索引付けの対象となっている列または表の各オブジェクト・インスタンスに対するファンクションの戻り値をあらかじめ計算しておいて、それらの値を索引に格納します。この索引では、ファンクションを評価しなおすことなく列や表が参照されます。

ファンクション索引は、WHERE句にファンクションを含む問合せのパフォーマンスを向上させる場合に役立ちます。たとえば、次のコードにはオブジェクト表empsの問合せが含まれています。

CREATE TYPE emp_t AS OBJECT(
  name   VARCHAR2(36),
  salary NUMBER,
  MEMBER FUNCTION bonus RETURN NUMBER DETERMINISTIC);
/
CREATE TYPE BODY emp_t IS
 MEMBER FUNCTION bonus RETURN NUMBER DETERMINISTIC IS
 BEGIN
  RETURN self.salary * .1;
 END;
END;
/

CREATE TABLE emps OF emp_t ;

SELECT e.name
  FROM emps e
  WHERE e.bonus() > 2000;

この問合せを評価するためには、この表の各行オブジェクトに対するbonus()を評価する必要があります。bonus()の戻り値に対してファンクション索引がある場合は、この評価の作業はすでに実行済なので、Oracleの動作としては、索引内にある問合せ結果を検索するのみですみます。これによって、Oracleが問合せを実行した結果を戻す速度が向上します。

ファンクションの戻り値の索引付けが効果的に実行できるのは、戻り値が一定である場合、つまり、ファンクションが各オブジェクト・インスタンスに対して常に同じ値を戻す場合のみです。このため、ファンクション索引でユーザー定義ファンクションを使用する場合は、前述の例のように、DETERMINISTICキーワードを使用してそのファンクションを宣言しておく必要があります。このキーワードによって、各オブジェクト・インスタンスの入力引数値の集合に対して、このファンクションから常に一定の値が戻されることが保証されます。

次の例では、表empsのメソッドbonus()に対するファンクション索引を作成します。

例9-14 メソッドに対するファンクション索引の作成

CREATE INDEX emps_bonus_idx ON emps x (x.bonus()) ;