この章では、このマニュアル全体で使用している電力需要サンプル・データ・カートリッジについて説明します。電力需要カートリッジには、ユーザー定義のオブジェクト型、拡張可能索引付けおよび最適化が含まれています。カートリッジ全体の定義は、Oracleデモ・ディレクトリにあるextdemo1.sql
ファイルからオンラインで参照できます。
この章の内容は、次のとおりです。
関連項目
|
電力会社Power-To-The-Peopleは、リソースのデプロイ方法を決定するために洗練されたモデルを開発しています。この電力会社が電力を供給している地域は、地理上の区域にまたがるグリッドで表されます。このグリッドを図15-1に示します。
この地域の周辺地域には、他の電力会社からの電力供給を必要とするところがあります。図のように、各地域は10x10のグリッド上でセルと呼ばれる地理上の象限で構成されています。セルを識別するには、空間座標(緯度/経度)、マトリックス番号(1,1、1,2など)および図15-2のような連番など、様々な方法があります。
各セルで表される区域では、その区域内の消費者による消費電力が1時間ごとに記録されています。たとえば、特定の時間の電力需要測定値が表15-1のようになるとします(ここでは、セルがマトリックスで表されています)。
表15-1 1時間当たりの電力需要測定値のサンプル
- | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
1 |
|
|
|
|
|
|
|
|
|
|
2 |
|
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|
|
|
|
|
|
4 |
|
|
|
|
|
|
|
|
|
|
5 |
|
|
|
|
|
|
|
|
|
|
6 |
|
|
|
|
|
|
|
|
|
|
7 |
|
|
|
|
|
|
|
|
|
|
8 |
|
|
|
|
|
|
|
|
|
|
9 |
|
|
|
|
|
|
|
|
|
|
10 |
|
|
|
|
|
|
|
|
|
|
発電所は、他の2つのソースからもレポートを受け取ります。
地上のセンサーは、各セルの気温の測定値を提供します。
セルからの電力需要履歴とその地域の気温の測定値との相関関係を分析することで、電力会社は特定の気温における需要量の近似値を判断できます。
衛星カメラは現在の状態に関する画像を提供し、それが図15-3に示すグリッドと一致するグレースケール・イメージに変換されます。
これらの画像は、明度が高いほど気温が低いことを示すように設計されています。したがって、この画像は、この地域に南西から寒冷前線が移動しつつあることを示しています。グレースケール・イメージで得られるデータを同時に測定した気温値と相関付けることで、電力会社は成層圏から見た気象条件に基づいて電力需要を判断できるようになりました。
このことが重要なのは、気象の変化と電力の供給につれて送られてくるレポートが示す変化の速度と大きさを認識する作業が、このモデル作成に大きく関係しているためです。図15-4に、第2の記録時における同じ寒冷前線を示します。
図15-5のように、寒冷前線の範囲と速度を分析することで、電力会社は条件が短期的であるか中期的であるかを予想できます。
電力会社は、これらの条件と他の変則的な状況(変電所の障害など)に関するデータを組み合せて、リソースの最適のデプロイメントを編成できる必要があります。図15-6は、地域全体における変電所の分布を反映したものです。
発電所の分布は、電力会社が最も需要の大きい地域に電力供給先を変更できることを意味しています。図15-7に、3つの発電所間の重複部分を示します。
電力会社は、変動要件に応じてリソースのデプロイ方法を決定し、供給不足が生じた場合に他の電力会社から電力を購入するかどうかも決定する必要があります。
この項には、技術上およびビジネス上の使用例が含まれます。図15-8のクラス・ダイアグラムは、Unified Modelling Language(UML)表記法を使用してアプリケーション・オブジェクトを記述したものです。
この方法でアプリケーション・モデルを作成すると、次の特定の問合せを実行できるようになります。
指定した期間中の需要が最も大きいセル(地理的象限)の検索
総需要が最も大きい期間の検索
需要が指定値よりも大きい全セルの検索
いずれかの時点で需要が指定値と一致するセルの検索
3つ以上のセルの需要が指定値を超えていたか超えている期間の検索
最小需要を持つセルと最大需要を持つセルとの格差(差異)が最大だった期間の検索
10個以上のセルの需要が指定値以上になっていた時間の検索
セルの平均需要が指定値よりも大きかった時間の検索(注意: 平均をTotalPowerDemand/100で容易に計算可能であると仮定)
セルの需要中央値が指定値よりも大きかった期間の検索(注意: 中央値が容易に計算できないと仮定)
直前時間の総需要からの総需要上昇率が10%以上だった全期間の検索
前述の問合せは、システムから収集可能な情報のリストの一部にすぎません。たとえば、この種のアプリケーションの開発者は、前の問合せから導出された情報に基づく問合せを作成する必要があることが明らかです。
前の期間と比較した特定セルの需要の変動率
需要の急増または急減を示すセル(指定値からの増加率/減少率として測定)
図15-9のクラス・ダイアグラムに、実装される電力需要カートリッジを示します。
電力会社は気象センターから現況レポートを受け取り、発電所から特定地域(10x10グリッド上のセルで表現)の消費電力レポートを受け取ります。次に、この情報を履歴データと比較し、特定の期間における各地域の電力需要を予想します。
電力会社の各サービス・エリアはセルで構成される10x10のグリッドとみなされ、各セルの境界は空間座標(緯度/経度)に関連付けられています。セルで表される地理的区域は、形状や面積が同一の場合も異なる場合もあります。各セルで表される区域では、その区域内の消費者による消費電力が1時間ごとに記録されています。例として、表15-2に特定時間の電力需要測定値を示します。
表15-2 1時間当たりの電力需要測定値のサンプル
- | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
1 |
|
|
|
|
|
|
|
|
|
|
2 |
|
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|
|
|
|
|
|
4 |
|
|
|
|
|
|
|
|
|
|
5 |
|
|
|
|
|
|
|
|
|
|
6 |
|
|
|
|
|
|
|
|
|
|
7 |
|
|
|
|
|
|
|
|
|
|
8 |
|
|
|
|
|
|
|
|
|
|
9 |
|
|
|
|
|
|
|
|
|
|
10 |
|
|
|
|
|
|
|
|
|
|
各セルの数値には、その区域における特定時間の(電力会社が決定した測定単位による)電力需要が反映されています。たとえば、第1セル(1,1)の需要は23、第2セル(1,2)の需要は21などとなっています。最終セル(10,10)の需要は32でした。
電力会社は、このデータを多数のモニタリングおよび分析アプリケーションに使用します。各セルの測定値が監視され、異常な需要増や需要減がないかどうかが調べられます。たとえば、(6,3)の測定値98と(8,1)の測定値87は異常に高い値であり、(4,7)の測定値19と(10,4)の測定値12は異常に低い値の場合があります。発電所別と地域全体について、期間における隣接地の需要の急増や急減などの傾向も分析されます。
この項では、ドメイン索引によりメリットが得られる問合せの種類について説明します。拡張可能索引付けを使用するかどうかは、標準のOracle索引を使用する場合、またはまったく索引を使用しない場合に、問合せを効率的に実行できるかどうかに応じて異なります。
次の両方の条件に該当する場合、問合せにドメイン索引は不要です。
必要な情報を表の属性(列)に使用し、その列に標準索引を定義できる場合。
データに対する問合せの操作が、Bツリー索引に対するequals
、lessthan
、greaterthan
、max
およびmin
など、標準索引でサポートされている操作に限定されている場合。
PowerDemand_Typ
オブジェクト型のカートリッジの例では、3つの列(TotGridDemand
、MaxCellDemand
およびMinCellDemand
)の値はファンクションにより設定され、その後は変化しません。(たとえば、1998年1月1日午後1時のグリッドの総需要は、計算後は変化しません。)これらの列を使用する問合せの場合は、各列の標準Bツリー索引で十分であり、equals
、lessthan
、greaterthan
、max
およびmin
などの操作にお薦めします。
拡張可能索引付けによるメリットが得られない問合せの例(電力需要カートリッジを使用)を次に示します。
特定の時点で最大の電力需要を持つセルの検索
グリッド全体の電力需要が最大だった時刻の検索
電力需要が指定値よりも大きい全セルの検索
セルの平均需要または中央値が指定値よりも大きかった時間の検索
この問合せを効率的に実行するには、PowerDemand_Typ
オブジェクト型にさらに2つの列(AverageCellDemand
およびMedianCellDemand
)を定義し、これらの列の値を設定するファンクションを作成します。(たとえば、AverageCellDemand
はTotGridDemand
を100で除算した値です。)次に、AverageCellDemand
およびMedianCellDemand
列にBツリー索引を作成します。
問合せでドメイン索引のメリットが得られるのは、問い合せるデータを表の単純属性に使用できない場合、またはデータに対して実行する操作がOracle索引でサポートされている標準操作でない場合です。
拡張可能索引付けによるメリットが得られる問合せの例(電力需要カートリッジを使用)を次に示します。
指定時間に電力需要が指定値と一致していた第1セルの検索
第1セルを問い合せることで、問合せは単純なTRUE-FALSEチェック(指定時間に需要が指定値と一致していたanyセルの有無の検索など)の範囲を超えるため、ドメイン索引によるメリットが得られます。
最小需要を持つセルと最大需要を持つセルとの格差または差異が最大だった時間の検索
3
個以上のセルの需要が指定値を超えていた全時間の検索
10個以上のセルの需要が指定値以上になっていた全時間の検索
直前時間のグリッドの総需要からの上昇率が10%以上だった全時間の検索
この項では、電力需要カートリッジのうち、拡張可能索引付けに関連する部分について説明します。コード・セグメントを示しながら説明していきます。
カートリッジ全体の定義は、標準Oracleデモ・ディレクトリ(場所はプラットフォームに依存)にあるextdemo1.sqlとしてオンラインで使用可能です。
ドメイン索引を作成する前に、索引を所有するデータベース・ユーザーまたはスキーマを作成します。電力需要の例では、ユーザーPowerCartUser
が作成され、適切な権限が付与されています。カートリッジに関連するデータベース構造はすべて、例15-1で示されるように、このユーザーとして(つまり、カートリッジ開発者またはDBAがデータベースにPowerCartUser
として接続している間に)作成されます。
例15-1 電力需要カートリッジのデータベース・ユーザーの作成方法
set echo on connect sys/knl_test7 as sysdba; drop user PowerCartUser cascade; create user PowerCartUser identified by PowerCartUser; ------------------------------------------------------------------- -- INITIAL SET-UP ------------------------------------------------------------------- -- grant privileges -- grant connect, resource to PowerCartUser; -- do we need to grant these privileges -- grant create operator to PowerCartUser; grant create indextype to PowerCartUser; grant create table to PowerCartUser;
オブジェクト型PowerDemand_Typ
は、1時間当たりの電力グリッド測定値を格納するために使用されます。この型を使用して、測定値を格納する表の列を定義します。
最初に、例15-2で示されるように、後で使用できるように2つの型を定義します。
PowerGrid_Typ
。PowerDemand_Typ
のセルを定義します。
NumTab_Typ
。索引エントリが格納される表で使用します。
例15-2 電力需要カートリッジのPowerGrid_Typ型およびNumTab_Typ型の作成方法
CREATE OR REPLACE TYPE PowerGrid_Typ as VARRAY(100) of NUMBER; CREATE OR REPLACE TYPE NumTab_Typ as TABLE of NUMBER;
例15-3で示されるように、PowerDemand_Typ
型には次が含まれます。
3つのメンバー・プロシージャにより設定される3つの属性(TotGridDemand
、MaxCellDemand
、MinCellDemand
)
電力需要測定値(グリッドの100
個のセル)
電力需要測定値の日時(毎時、100
の区域が電力需要測定値を送信)
例15-3 電力需要カートリッジのPowerDemand_Typ型の作成方法
CREATE OR REPLACE TYPE PowerDemand_Typ AS OBJECT ( -- Total power demand for the grid TotGridDemand NUMBER, -- Cell with maximum/minimum power demand for the grid MaxCellDemand NUMBER, MinCellDemand NUMBER, -- Power grid: 10X10 array represented as Varray(100) -- using previously defined PowerGrid_Typ CellDemandValues PowerGrid_Typ, -- Date/time for power-demand samplings: Every hour, -- 100 areas transmit their power demand readings. SampleTime DATE, -- -- Methods (Set...) for this type: -- Total demand for the entire power grid for a -- SampleTime: sets the value of TotGridDemand. Member Procedure SetTotalDemand, -- Maximum demand for the entire power grid for a -- SampleTime: sets the value of MaxCellDemand. Member Procedure SetMaxDemand, -- Minimum demand for the entire power grid for a -- SampleTime: sets the value of MinCellDemand. Member Procedure SetMinDemand ); /
PowerDemand_Typ
オブジェクト型には、次のように型定義の最初の3つの属性を設定するメソッドがあります。
TotGridDemand
。指定した時間(SampleTime
で識別)の電力グリッド全体の総需要。
MaxCellDemand
。SampleTime
における全セルで最大の電力需要値。
MinCellDemand
。SampleTime
における全セルで最小の電力需要値。
各プロシージャの論理は簡潔です。SetTotDemand
は、セル値をループして合計を作成します。SetMaxDemand
は、最初の2つのセル値を比較し、大きい方の値を現在の最大値として保存します。以降、セル値の終わりに達するまで連続する各セルを検査して現在の最大値と比較し、大きい方の値を現在の最大値として保存します。例15-4で示すように、SetMinDemand
はSetMaxDemand
と同じアプローチを使用しますが、2つの値を比較して小さい方の値を継続的に保存し、全体の最小値を導出します。
例15-4 電力需要カートリッジのPowerDemand_Typ型の実装方法
CREATE OR REPLACE TYPE BODY PowerDemand_Typ IS -- -- Methods (Set...) for this type: -- Total demand for the entire power grid for a -- SampleTime: sets the value of TotGridDemand. Member Procedure SetTotalDemand IS I BINARY_INTEGER; Total NUMBER; BEGIN Total :=0; I := CellDemandValues.FIRST; WHILE I IS NOT NULL LOOP Total := Total + CellDemandValues(I); I := CellDemandValues.NEXT(I); END LOOP; TotGridDemand := Total; END; -- Maximum demand for the entire power grid for a -- SampleTime: sets the value of MaxCellDemand. Member Procedure SetMaxDemand IS I BINARY_INTEGER; Temp NUMBER; BEGIN I := CellDemandValues.FIRST; Temp := CellDemandValues(I); WHILE I IS NOT NULL LOOP IF Temp < CellDemandValues(I) THEN Temp := CellDemandValues(I); END IF; I := CellDemandValues.NEXT(I); END LOOP; MaxCellDemand := Temp; END; -- Minimum demand for the entire power grid for a -- SampleTime: sets the value of MinCellDemand. Member Procedure SetMinDemand IS I BINARY_INTEGER; Temp NUMBER; BEGIN I := CellDemandValues.FIRST; Temp := CellDemandValues(I); WHILE I IS NOT NULL LOOP IF Temp > CellDemandValues(I) THEN Temp := CellDemandValues(I); END IF; I := CellDemandValues.NEXT(I); END LOOP; MinCellDemand := Temp; END; END; /
電力需要カートリッジは、ユーザーが電力グリッドにequality
、greaterthan
またはlessthan
の関係を問い合せることができるように設計されています。ただし、セルの需要データの格納方法の関係で、標準演算子(=
、>
、<
)は使用できません。かわりに、新しい演算子を作成し、ファンクションを作成して、新しい各演算子の実装(つまり、Oracleによる演算子の解析方法)を定義する必要があります。
このカートリッジの場合、3つの関係をそれぞれ2つの方法でチェックできます。
グリッドの特定のセルが関係を満たしているかどうか。(たとえば、セル(3,7)
の需要が25
のグリッドがあるかどうか)
これらの演算子の名前はPower_EqualsSpecific()
などのPower_XxxxxSpecific()
形式で、実装用ファンクションの名前はPower_XxxxxSpecific_Func()
形式です。
グリッドに関係を満たしているセルがあるかどうか。たとえば、需要が25
のセルを含むグリッドがあるかどうか。
これらの演算子の名前はPower_EqualsAny()
などのPower_XxxxxAny()
形式で、実装用ファンクションの名前はPower_XxxxxAny_Func()
形式です。
演算子とファンクションのペアごとに、最初にファンクションを定義し、そのファンクションを使用して演算子を定義します。ファンクションは、索引が定義されていない場合に使用される実装です。この実装は、Oracleオプティマイザでコストを判別し、索引の使用が必要かどうかを決定し、実行計画を作成できるように指定する必要があります。
表15-3に、演算子と実装用ファンクションを示します。
表15-3 演算子と実装用ファンクション
演算子 | 実装用ファンクション |
---|---|
Power_EqualsSpecific() |
Power_EqualsSpecific_Func() |
Power_EqualsAny() |
Power_EqualsAny_Func() |
Power_LessThanSpecific() |
Power_LessThanSpecific_Func() |
Power_LessThanAny() |
Power_LessThanAny_Func() |
Power_GreaterThanSpecific() |
Power_GreaterThanSpecific_Func() |
Power_GreaterThanAny() |
Power_GreaterThanAny_Func() |
各ファンクションと演算子は、条件がTRUEの場合(指定したセルが指定した値と等しい場合など)は数値1
を戻し、条件がTRUEでない場合は0
(ゼロ)を戻し、指定したセル値が無効な場合はNULL
を戻します。
例15-5で説明する文では、実装するファンクションPower_xxx_Func()
を最初はspecific
実装、次はany
実装用に作成します。
例15-5 電力需要カートリッジのPower_XXX_Func()ファンクションの実装方法
CREATE FUNCTION Power_EqualsSpecific_Func( object PowerDemand_Typ, cell NUMBER, value NUMBER) RETURN NUMBER AS BEGIN IF cell <= object.CellDemandValues.LAST THEN IF (object.CellDemandValues(cell) = value) THEN RETURN 1; ELSE RETURN 0; END IF; ELSE RETURN NULL; END IF; END; / CREATE FUNCTION Power_GreaterThanSpecific_Func( object PowerDemand_Typ, cell NUMBER, value NUMBER) RETURN NUMBER AS BEGIN IF cell <= object.CellDemandValues.LAST THEN IF (object.CellDemandValues(cell) > value) THEN RETURN 1; ELSE RETURN 0; END IF; ELSE RETURN NULL; END IF; END; / CREATE FUNCTION Power_LessThanSpecific_Func( object PowerDemand_Typ, cell NUMBER, value NUMBER) RETURN NUMBER AS BEGIN IF cell <= object.CellDemandValues.LAST THEN IF (object.CellDemandValues(cell) < value) THEN RETURN 1; ELSE RETURN 0; END IF; ELSE RETURN NULL; END IF; END; / CREATE FUNCTION Power_EqualsAny_Func( object PowerDemand_Typ, value NUMBER) RETURN NUMBER AS idx NUMBER; BEGIN FOR idx IN object.CellDemandValues.FIRST..object.CellDemandValues.LAST LOOP IF (object.CellDemandValues(idx) = value) THEN RETURN 1; END IF; END LOOP; RETURN 0; END; / CREATE FUNCTION Power_GreaterThanAny_Func( object PowerDemand_Typ, value NUMBER) RETURN NUMBER AS idx NUMBER; BEGIN FOR idx IN object.CellDemandValues.FIRST..object.CellDemandValues.LAST LOOP IF (object.CellDemandValues(idx) > value) THEN RETURN 1; END IF; END LOOP; RETURN 0; END; / CREATE FUNCTION Power_LessThanAny_Func( object PowerDemand_Typ, value NUMBER) RETURN NUMBER AS idx NUMBER; BEGIN FOR idx IN object.CellDemandValues.FIRST..object.CellDemandValues.LAST LOOP IF (object.CellDemandValues(idx) < value) THEN RETURN 1; END IF; END LOOP; RETURN 0; END; /
例15-6で説明する文では、演算子(Power_xxx
)を作成します。それぞれの文で実装用ファンクションを1つ指定しています。
例15-6 電力需要カートリッジのPower_XXX()ファンクションの実装方法
CREATE OPERATOR Power_Equals BINDING(PowerDemand_Typ, NUMBER, NUMBER) RETURN NUMBER USING Power_EqualsSpecific_Func; CREATE OPERATOR Power_GreaterThan BINDING(PowerDemand_Typ, NUMBER, NUMBER) RETURN NUMBER USING Power_GreaterThanSpecific_Func; CREATE OPERATOR Power_LessThan BINDING(PowerDemand_Typ, NUMBER, NUMBER) RETURN NUMBER USING Power_LessThanSpecific_Func; CREATE OPERATOR Power_EqualsAny BINDING(PowerDemand_Typ, NUMBER) RETURN NUMBER USING Power_EqualsAny_Func; CREATE OPERATOR Power_GreaterThanAny BINDING(PowerDemand_Typ, NUMBER) RETURN NUMBER USING Power_GreaterThanAny_Func; CREATE OPERATOR Power_LessThanAny BINDING(PowerDemand_Typ, NUMBER) RETURN NUMBER USING Power_LessThanAny_Func;
電力需要カートリッジでは、ドメイン索引用のメソッドを指定する索引タイプのオブジェクト型が作成されます。これらのメソッドはODCIIndex
(Oracle Data Cartridge Interface Index)インタフェースの一部であり、索引の定義、操作、スキャンおよびエクスポートに使用するメソッドについて、索引の動作をまとめて定義します。
表15-4に、電力需要カートリッジ用に作成されるメソッドのファンクションを示します(1つを除きすべてODCIIndex
で始まります)。
表15-4 索引タイプ・メソッド
メソッド | 説明 |
---|---|
|
型により実装されるインタフェースの名前のリストを戻します。 |
|
索引データを格納するための表を作成します。索引付けするデータを含む実表が空でない場合は、既存のデータの索引が作成されます。 このメソッドは、索引タイプを参照する |
|
索引データを格納する表を削除します。このメソッドは、 |
|
演算子述語に関する索引のスキャンを初期化します。このメソッドは、ドメイン索引を使用して実行できる演算子関連の問合せの発行時にコールされます。 |
|
演算子述語を満たす各行の |
|
索引の現在の使用を終了します。このメソッドでは、必要なクリーン・アップを実行できます。 |
|
索引タイプにより索引付けされる列またはオブジェクト属性を含んだ表にレコードが挿入されるときに、索引構造をメンテナンスします。 |
|
索引タイプにより索引付けされる列またはオブジェクト属性を含んだ表からレコードが削除されるときに、索引構造をメンテナンスします。 |
|
索引タイプにより索引付けされる列またはオブジェクト属性を含んだ表のレコードが更新(変更)されるときに、索引構造をメンテナンスします。 |
|
索引に関連付けられている実装固有のメタデータのエクスポートとインポートを可能にします。 |
例15-7では、power_idxtype_im
オブジェクト型を作成します。この型のメソッドは、ドメイン索引を定義、操作およびスキャンするためのODCIメソッドです。curnum
属性は、ODCIIndexStart()、ODCIIndexFetch()、およびODCIIndexClose()というスキャン・ルーチンのコンテキストとして使用されるカーソル番号です。
例15-7 電力需要カートリッジのpower_idxtype_imオブジェクト型の作成方法
CREATE OR REPLACE TYPE power_idxtype_im AS OBJECT ( curnum NUMBER, STATIC FUNCTION ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) RETURN NUMBER, STATIC FUNCTION ODCIIndexCreate (ia sys.ODCIIndexInfo, parms VARCHAR2, env sys.ODCIEnv) RETURN NUMBER, STATIC FUNCTION ODCIIndexDrop(ia sys.ODCIIndexInfo, env sys.ODCIEnv) RETURN NUMBER, STATIC FUNCTION ODCIIndexStart(sctx IN OUT power_idxtype_im, ia sys.ODCIIndexInfo, op sys.ODCIPredInfo, qi sys.ODCIQueryInfo, strt NUMBER, stop NUMBER, cmppos NUMBER, cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER, STATIC FUNCTION ODCIIndexStart(sctx IN OUT power_idxtype_im, ia sys.ODCIIndexInfo, op sys.ODCIPredInfo, qi sys.ODCIQueryInfo, strt NUMBER, stop NUMBER, cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER, MEMBER FUNCTION ODCIIndexFetch(nrows NUMBER, rids OUT sys.ODCIRidList, env sys.ODCIEnv) RETURN NUMBER, MEMBER FUNCTION ODCIIndexClose (env sys.ODCIEnv) RETURN NUMBER, STATIC FUNCTION ODCIIndexInsert(ia sys.ODCIIndexInfo, rid VARCHAR2, newval PowerDemand_Typ, env sys.ODCIEnv) RETURN NUMBER, STATIC FUNCTION ODCIIndexDelete(ia sys.ODCIIndexInfo, rid VARCHAR2, oldval PowerDemand_Typ, env sys.ODCIEnv) RETURN NUMBER, STATIC FUNCTION ODCIIndexUpdate(ia sys.ODCIIndexInfo, rid VARCHAR2, oldval PowerDemand_Typ, newval PowerDemand_Typ, env sys.ODCIEnv) RETURN NUMBER, STATIC FUNCTION ODCIIndexGetMetadata(ia sys.ODCIIndexInfo, expversion VARCHAR2, newblock OUT PLS_INTEGER, env sys.ODCIEnv) RETURN VARCHAR2 ); /
CREATE
TYPE
文の後に、各メンバー・ファンクションの実装を指定するCREATE
TYPE
BODY
文があります。
CREATE OR REPLACE TYPE BODY power_idxtype_im IS ...
それぞれの型のメソッドについては別の項で説明しますが、メソッドの定義(VARCHAR2
文字列を戻すODCIIndexGetMetadata()以外)の一般的な書式は次のとおりです。
STATIC FUNCTION function-name (...) RETURN NUMBER IS ... END;
ODCIGetInterfaces()ファンクションは、型により実装されるインタフェースの名前のリストを戻します。これらのインタフェースの現行のバージョンを指定するには、例15-8で示されるように、ODCIGetInterfaces()ルーチンによってOUT
パラメータの'SYS.ODCIINDEX2'
に戻される必要があります。
例15-8 電力需要カートリッジのODCIIndexXXX()ファンクション用ODCIGetInterfaces()の実装の登録方法
STATIC FUNCTION ODCIGetInterfaces( ifclist OUT sys.ODCIObjectList) RETURN NUMBER IS BEGIN ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCIINDEX2')); return ODCIConst.Success; END ODCIGetInterfaces;
注意: ルーチンに対する以降の変更について更新されない既存のOracle8iコードを引き続き使用するには、ファンクションODCIGetInterfaces でSYS.ODCIINDEX1 を指定し、ODCIObjectList パラメータでODCIIndex ルーチンのOracle8iバージョンを指定するようにします。 |
ODCIIndexCreate()ファンクションでは、索引データを格納する表を作成します。索引付けするデータを含む実表が空でない場合は、既存のデータの索引データ・エントリが挿入されます。
このファンクションは、SYS
.ODCIINDEXINFO
型のオブジェクト・パラメータとして索引情報を取ります。型の属性は、索引名、所有者名などです。CREATE
INDEX
文に指定されているPARAMETERS
文字列も、例15-9で示されるように、このファンクションにパラメータとして渡されます。
例15-9 電力需要カートリッジのODCIIndexCreate()の実装の登録方法
STATIC FUNCTION ODCIIndexCreate ( ia sys.ODCIIndexInfo, parms VARCHAR2, env sys.ODCIEnv) RETURN NUMBER IS i INTEGER; r ROWID; p NUMBER; v NUMBER; stmt1 VARCHAR2(1000); stmt2 VARCHAR2(1000); stmt3 VARCHAR2(1000); cnum1 INTEGER; cnum2 INTEGER; cnum3 INTEGER; junk NUMBER;
索引データの表を作成するためのSQL文が構成され、実行されます。表には、実表r
のROWID
、グリッド内のセルの位置を示す1〜100の番号(cpos
)およびそのセル内の電力需要値(cval
)が含まれます。
BEGIN -- Construct the SQL statement. stmt1 := 'CREATE TABLE ' || ia.IndexSchema || '.' || ia.IndexName ||'_pidx' || '( r ROWID, cpos NUMBER, cval NUMBER)'; -- Dump the SQL statement. dbms_output.put_line('ODCIIndexCreate>>>>>'); sys.ODCIIndexInfoDump(ia); dbms_output.put_line('ODCIIndexCreate>>>>>'||stmt1); -- Execute the statement. cnum1 := dbms_sql.open_cursor; dbms_sql.parse(cnum1, stmt1, dbms_sql.native); junk := dbms_sql.execute(cnum1); dbms_sql.close_cursor(cnum1);
このファンクションにより表に行が挿入され、索引が移入されます。また、VARRAY
属性のネストが解除され、セルごとに表に1行が挿入されます。そのため、10x10の各グリッド(10行で行ごとに10個の値)が、表の100行(セルごとに1行)になります。
-- Now populate the table. stmt2 := ' INSERT INTO '|| ia.IndexSchema || '.' || ia.IndexName || '_pidx' || ' SELECT :rr, ROWNUM, column_value FROM THE' || ' (SELECT CAST (P.'|| ia.IndexCols(1).ColName||'.CellDemandValues AS NumTab_Typ)'|| ' FROM ' || ia.IndexCols(1).TableSchema || '.' || ia.IndexCols(1).TableName || ' P' || ' WHERE P.ROWID = :rr)'; -- Execute the statement. dbms_output.put_line('ODCIIndexCreate>>>>>'||stmt2); -- Parse the statement. cnum2 := dbms_sql.open_cursor; dbms_sql.parse(cnum2, stmt2, dbms_sql.native); stmt3 := 'SELECT ROWID FROM '|| ia.IndexCols(1).TableSchema || '.' || ia.IndexCols(1).TableName; dbms_output.put_line('ODCIIndexCreate>>>>>'||stmt3); cnum3 := dbms_sql.open_cursor; dbms_sql.parse(cnum3, stmt3, dbms_sql.native); dbms_sql.define_column_rowid(cnum3, 1, r); junk := dbms_sql.execute(cnum3); WHILE dbms_sql.fetch_rows(cnum3) > 0 LOOP -- Get column values of the row. -- dbms_sql.column_value_rowid(cnum3, 1, r); -- Bind the row into the cursor for the next insert. -- dbms_sql.bind_variable_rowid(cnum2, ':rr', r); junk := dbms_sql.execute(cnum2); END LOOP;
最後に、このファンクションはカーソルをクローズし、成功ステータスを戻して終了します。
dbms_sql.close_cursor(cnum2); dbms_sql.close_cursor(cnum3); RETURN ODCICONST.SUCCESS; END ODCIInexCreate;
ODCIIndexDrop()ファンクションは、例15-10で示されるように、索引データを格納する表を削除します。このメソッドは、DROP
INDEX
文の発行時にコールされます。
例15-10 電力需要カートリッジのODCIIndexDrop()の実装の登録方法
STATIC FUNCTION ODCIIndexDrop(ia sys.ODCIIndexInfo, env sys.ODCIEnv) RETURN NUMBER IS stmt VARCHAR2(1000); cnum INTEGER; junk INTEGER; BEGIN -- Construct the SQL statement. stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || '_pidx'; dbms_output.put_line('ODCIIndexDrop>>>>>'); sys.ODCIIndexInfoDump(ia); dbms_output.put_line('ODCIIndexDrop>>>>>'||stmt); -- Execute the statement. cnum := dbms_sql.open_cursor; dbms_sql.parse(cnum, stmt, dbms_sql.native); junk := dbms_sql.execute(cnum); dbms_sql.close_cursor(cnum); RETURN ODCICONST.SUCCESS; END ODCIIndexDrop;
ODCIIndexStart()ファンクションの最初の定義により、演算子述語を満たす行をすべて戻すように索引のスキャンが初期化されます。たとえば、問合せでセル(3,7)
の値が25
であるインスタンスをすべて要求すると、このファンクションはセル(3,7)
が25
である索引構成表の行をすべて戻すようにスキャンを初期化します。ODCIIndexStart()のこの定義は、Any問合せのODCIIndexStart()メソッドに関する項に示した定義とは、セルの位置を示すcmppos
パラメータを含むという点で異なります。
self
パラメータは、ODCIIndexFetch()およびODCIIndexClose()ファンクションと共有されるコンテキストです。ia
パラメータには索引情報としてSYS
.ODCIINDEXINFO
型のオブジェクト・インスタンスが含まれ、op
パラメータには演算子情報としてSYS
.ODCIOPERINFO
型のオブジェクト・インスタンスが含まれています。strt
およびstop
パラメータは、演算子の戻り値の上限と下限の境界ポイントです。cmppos
パラメータはセル位置で、cmpval
は演算子Power_XxxxxSpecific()
で指定されたセルの値です。これは例15-11で示されています。
例15-11 電力需要カートリッジのSpecific問合せのODCIIndexStart()の実装の登録方法
STATIC FUNCTION ODCIIndexStart( sctx IN OUT power_idxtype_im, ia sys.ODCIIndexInfo, op sys.ODCIPredInfo, qi sys.ODCIQueryInfo, strt NUMBER, stop NUMBER, cmppos NUMBER, cmpval NUMBER, env sys.ODCIEnv ) RETURN NUMBER IS cnum INTEGER; rid ROWID; nrows INTEGER; relop VARCHAR2(2); stmt VARCHAR2(1000); BEGIN dbms_output.put_line('ODCIIndexStart>>>>>'); sys.ODCIIndexInfoDump(ia); sys.ODCIPredInfoDump(op); dbms_output.put_line('start key : '||strt); dbms_output.put_line('stop key : '||stop); dbms_output.put_line('compare position : '||cmppos); dbms_output.put_line('compare value : '||cmpval);
このファンクションは、述語のエラーをチェックします。
-- Take care of some error cases. -- The only predicates in which btree operators can appear are -- op() = 1 OR op() = 0 if (strt != 1) and (strt != 0) then raise_application_error(-20101, 'Incorrect predicate for operator'); END if; if (stop != 1) and (stop != 0) then raise_application_error(-20101, 'Incorrect predicate for operator'); END if;
次に、実行するSQL文が生成されます。演算子名と索引値の上限および下限(開始キーと終了キー)が判別されます。開始キーと終了キーは、両方とも1(= TRUE
)または両方とも0(ゼロ)(= FALSE
)に設定できます。
-- Generate the SQL statement to be executed. -- First, figure out the relational operator needed for the statement. -- Take into account the operator name and the start and stop keys. For now, -- the start and stop keys can both be 1 (= TRUE) or both be 0 (= FALSE). if op.ObjectName = 'POWER_EQUALS' then if strt = 1 then relop := '='; else relop := '!='; end if; elsif op.ObjectName = 'POWER_LESSTHAN' then if strt = 1 then relop := '<'; else relop := '>='; end if; elsif op.ObjectName = 'POWER_GREATERTHAN' then if strt = 1 then relop := '>'; else relop := '<='; end if; else raise_application_error(-20101, 'Unsupported operator'); end if; stmt := 'select r from '||ia.IndexSchema||'.'||ia.IndexName||'_pidx'|| ' where cpos '|| '=' ||''''||cmppos||''''|| ' and cval ' ||relop||''''|| cmpval||''''; dbms_output.put_line('ODCIIndexStart>>>>>' || stmt); cnum := dbms_sql.open_cursor; dbms_sql.parse(cnum, stmt, dbms_sql.native); dbms_sql.define_column_rowid(cnum, 1, rid); nrows := dbms_sql.execute(cnum);
カーソル番号がODCIIndexFetch
ファンクションで使用されるコンテキストに格納され、成功を示す戻りステータスが設定されます。
-- Set context as the cursor number. stcx := power_idxtype_im(cnum); -- Return success. RETURN ODCICONST.SUCCESS; END ODCIIndexStart;
ODCIIndexStart()ファンクションのこの定義により、演算子述語を満たす行をすべて戻すように索引のスキャンが初期化されます。たとえば、問合せで任意のセルの値が25
であるインスタンスをすべて要求すると、ファンクションは指定の値であるセルの索引構成表の行をすべて戻すようにスキャンを初期化します。ODCIIndexStart()のこの定義はSpecific問合せのODCIIndexStart()メソッドに関する項に示した定義とは、cmppos
パラメータを含まないという点で異なります。
self
パラメータは、ODCIIndexFetch()およびODCIIndexClose()ファンクションと共有されるコンテキストです。ia
パラメータには索引情報としてSYS
.ODCIINDEXINFO
型のオブジェクト・インスタンスが含まれ、op
パラメータには演算子情報としてSYS
.ODCIOPERINFO
型のオブジェクト・インスタンスが含まれています。strt
およびstop
パラメータは、演算子の戻り値の上限と下限の境界ポイントです。cmpval
パラメータは、演算子Power_Xxxx()
で指定されたセルの値です。
例15-12 電力需要カートリッジのAny問合せのODCIIndexStart()の実装の登録方法
STATIC FUNCTION ODCIIndexStart( sctx IN OUT power_idxtype_im, ia sys.ODCIIndexInfo, op sys.ODCIPredInfo, qi sys.ODCIQueryInfo, strt NUMBER, stop NUMBER, cmpval NUMBER, env sys.ODCIEnv ) RETURN NUMBER IS cnum INTEGER; rid ROWID; nrows INTEGER; relop VARCHAR2(2); stmt VARCHAR2(1000); BEGIN dbms_output.put_line('ODCIIndexStart>>>>>'); sys.ODCIIndexInfoDump(ia); sys.ODCIPredInfoDump(op); dbms_output.put_line('start key : '||strt); dbms_output.put_line('stop key : '||stop); dbms_output.put_line('compare value : '||cmpval);
このファンクションは、述語のエラーをチェックします。
-- Take care of some error cases. -- The only predicates in which btree operators can appear are -- op() = 1 OR op() = 0 if (strt != 1) and (strt != 0) then raise_application_error(-20101, 'Incorrect predicate for operator'); END if; if (stop != 1) and (stop != 0) then raise_application_error(-20101, 'Incorrect predicate for operator'); END if;
次に、実行するSQL文が生成されます。演算子名と索引値の上限および下限(開始キーと終了キー)が判別されます。開始キーと終了キーは、両方とも1(= TRUE
)または両方とも0(ゼロ)(= FALSE
)に設定できます。
-- Generate the SQL statement to be executed. -- First, figure out the relational operator needed for the statement. -- Take into account the operator name and the start and stop keys. For now, -- the start and stop keys can both be 1 (= TRUE) or both be 0 (= FALSE). if op.ObjectName = 'POWER_EQUALSANY' then relop := '='; elsif op.ObjectName = 'POWER_LESSTHANANY' then relop := '<'; elsif op.ObjectName = 'POWER_GREATERTHANANY' then relop := '>'; else raise_application_error(-20101, 'Unsupported operator'); end if; -- This statement returns the qualifying rows for the TRUE case. stmt := 'select distinct r from '||ia.IndexSchema||'.'||ia.IndexName||'_pidx'||' where cval '||relop||''''||cmpval||''''; -- In the FALSE case, we need to find the complement of the rows. if (strt = 0) then stmt := 'select distinct r from '||ia.IndexSchema||'.'||ia.IndexName|| '_pidx'||' minus '||stmt; end if; dbms_output.put_line('ODCIIndexStart>>>>>' || stmt); cnum := dbms_sql.open_cursor; dbms_sql.parse(cnum, stmt, dbms_sql.native); dbms_sql.define_column_rowid(cnum, 1, rid); nrows := dbms_sql.execute(cnum);
カーソル番号がODCIIndexFetch()ファンクションで使用されるコンテキストに格納され、成功を示す戻りステータスが設定されます。
-- Set context as the cursor number. self := power_idxtype_im(cnum); -- Return success. RETURN ODCICONST.SUCCESS; END ODCIIndexStart;
ODCIIndexFetch()ファンクションは、例15-13で示されるように、演算子述語を満たす行に対してROWID
のバッチを戻します。ODCIIndexFetch()がコールされるたびに、演算子述語を満たす行(rids
パラメータ、SYS
.ODCIRIDLIST
型のコレクション)の次のバッチが戻されます。各コールで戻すことのできる最大行数は、nrows
パラメータで指定されます。
Oracleは、演算子述語を満たす行がすべて戻されるまで、ODCIIndexFetch()を繰り返しコールします。
例15-13 電力需要カートリッジのODCIIndexFetch()の実装の登録方法
MEMBER FUNCTION ODCIIndexFetch( nrows NUMBER, rids OUT sys.ODCIRidList, env sys.ODCIEnv) RETURN NUMBER IS cnum INTEGER; idx INTEGER := 1; rlist sys.ODCIRidList := sys.ODCIRidList(); done boolean := FALSE;
このファンクションは、ODCIIndexStart()ファンクションと同じカーソル番号(cnum
)を使用して、ODCIIndexStart()ファンクションで選択された行のコレクションをループし、ROWID
を戻します。
BEGIN dbms_output.put_line('ODCIIndexFetch>>>>>'); dbms_output.put_line('Nrows : '||round(nrows)); cnum := self.curnum; WHILE not done LOOP if idx > nrows then done := TRUE; else rlist.extEND; if dbms_sql.fetch_rows(cnum) > 0 then dbms_sql.column_value_rowid(cnum, 1, rlist(idx)); idx := idx + 1; else rlist(idx) := null; done := TRUE; END if; END if; END LOOP; rids := rlist; RETURN ODCICONST.SUCCESS; END ODCIIndexFetch;
ODCIIndexClose()ファンクションは、例15-14に示されるように、ODCIIndexStart()およびODCIIndexFetch()ファンクションで使用されたカーソルをクローズします。
ODCIIndexInsert()ファンクションは、例15-15に示されるように、索引タイプによって索引付けられたOBJECT
属性または列を含む表にレコードが挿入されるときにコールされます。索引列の新規の値が、対応するROWIDとともに引数として渡されます。
例15-15 電力需要カートリッジのODCIIndexInsert()の実装の登録方法
STATIC FUNCTION ODCIIndexInsert( ia sys.ODCIIndexInfo, rid VARCHAR2, newval PowerDemand_Typ, env sys.ODCIEnv) RETURN NUMBER AS cid INTEGER; i BINARY_INTEGER; nrows INTEGER; stmt VARCHAR2(1000); BEGIN dbms_output.put_line(' '); dbms_output.put_line('ODCIIndexInsert>>>>>'||' TotGridDemand= '|| newval.TotGridDemand ||' MaxCellDemand= '||newval.MaxCellDemand || ' MinCellDemand= '||newval.MinCellDemand) ; sys.ODCIIndexInfoDump(ia); -- Construct the statement. stmt := ' INSERT INTO '|| ia.IndexSchema || '.' || ia.IndexName || '_pidx' || ' VALUES (:rr, :pos, :val)'; -- Execute the statement. dbms_output.put_line('ODCIIndexInsert>>>>>'||stmt); -- Parse the statement. cid := dbms_sql.open_cursor; dbms_sql.parse(cid, stmt, dbms_sql.native); dbms_sql.bind_variable_rowid(cid, ':rr', rid); -- Iterate over the rows of the Varray and insert them. i := newval.CellDemandValues.FIRST; WHILE i IS NOT NULL LOOP -- Bind the row into the cursor for insert. dbms_sql.bind_variable(cid, ':pos', i); dbms_sql.bind_variable(cid, ':val', newval.CellDemandValues(i)); -- Execute. nrows := dbms_sql.execute(cid); dbms_output.put_line('ODCIIndexInsert>>>>>('||'RID'||' , '||i|| ' , '|| newval.CellDemandValues(i)|| ')'); i := newval.CellDemandValues.NEXT(i); END LOOP; dbms_sql.close_cursor(cid); RETURN ODCICONST.SUCCESS; END ODCIIndexInsert;
ODCIIndexDelete()ファンクションは、例15-16に示されるように、索引タイプにより索引付けされる列またはオブジェクト属性を含んだ表からレコードが削除されるときにコールされます。索引列の古い値が、対応するROWIDとともに引数として渡されます。
例15-16 電力需要カートリッジのODCIIndexDelete()の実装の登録方法
STATIC FUNCTION ODCIIndexDelete( ia sys.ODCIIndexInfo, rid VARCHAR2, oldval PowerDemand_Typ, env sys.ODCIEnv) RETURN NUMBER AS cid INTEGER; stmt VARCHAR2(1000); nrows INTEGER; BEGIN dbms_output.put_line(' '); dbms_output.put_line('ODCIIndexDelete>>>>>'||' TotGridDemand= '|| oldval.TotGridDemand ||' MaxCellDemand= '||oldval.MaxCellDemand || ' MinCellDemand= '||oldval.MinCellDemand) ; sys.ODCIIndexInfoDump(ia); -- Construct the statement. stmt := ' DELETE FROM '|| ia.IndexSchema || '.' ||ia.IndexName|| '_pidx' || ' WHERE r=:rr'; dbms_output.put_line('ODCIIndexDelete>>>>>'||stmt); -- Parse and execute the statement. cid := dbms_sql.open_cursor; dbms_sql.parse(cid, stmt, dbms_sql.native); dbms_sql.bind_variable_rowid(cid, ':rr', rid); nrows := dbms_sql.execute(cid); dbms_sql.close_cursor(cid); RETURN ODCICONST.SUCCESS; END ODCIIndexDelete;
ODCIIndexUpdate()ファンクションは、例15-17に示されるように、索引タイプにより索引付けされる列またはオブジェクト属性を含んだ表のレコードが更新されるときにコールされます。索引列の古い値と新しい値が、ROWIDとともに引数として渡されます。
例15-17 電力需要カートリッジのODCIIndexUpdate()の実装の登録方法
STATIC FUNCTION ODCIIndexUpdate( ia sys.ODCIIndexInfo, rid VARCHAR2, oldval PowerDemand_Typ, newval PowerDemand_Typ, env sys.ODCIEnv) RETURN NUMBER AS cid INTEGER; cid2 INTEGER; stmt VARCHAR2(1000); stmt2 VARCHAR2(1000); nrows INTEGER; i NUMBER; BEGIN dbms_output.put_line(' '); dbms_output.put_line('ODCIIndexUpdate>>>>> Old'||' TotGridDemand= '|| oldval.TotGridDemand||' MaxCellDemand= '||oldval.MaxCellDemand || ' MinCellDemand= '||oldval.MinCellDemand) ; dbms_output.put_line('ODCIIndexUpdate>>>>> New'||' TotGridDemand= '|| newval.TotGridDemand ||' MaxCellDemand= '||newval.MaxCellDemand || ' MinCellDemand= '||newval.MinCellDemand) ; sys.ODCIIndexInfoDump(ia); -- Delete old entries. stmt := ' DELETE FROM '||ia.IndexSchema ||'.'||ia.IndexName||'_pidx'|| ' WHERE r=:rr'; dbms_output.put_line('ODCIIndexUpdate>>>>>'||stmt); -- Parse and execute the statement. cid := dbms_sql.open_cursor; dbms_sql.parse(cid, stmt, dbms_sql.native); dbms_sql.bind_variable_rowid(cid, ':rr', rid); nrows := dbms_sql.execute(cid); dbms_sql.close_cursor(cid); -- Insert new entries. stmt2 := ' INSERT INTO '||ia.IndexSchema||'.'||ia.IndexName||'_pidx'|| ' VALUES (:rr, :pos, :val)'; dbms_output.put_line('ODCIIndexUpdate>>>>>'||stmt2); -- Parse and execute the statement. cid2 := dbms_sql.open_cursor; dbms_sql.parse(cid2, stmt2, dbms_sql.native); dbms_sql.bind_variable_rowid(cid2, ':rr', rid); -- Iterate over the rows of the Varray and insert them. i := newval.CellDemandValues.FIRST; WHILE i IS NOT NULL LOOP -- Bind the row into the cursor for insert. dbms_sql.bind_variable(cid2, ':pos', i); dbms_sql.bind_variable(cid2, ':val', newval.CellDemandValues(i)); nrows := dbms_sql.execute(cid2); dbms_output.put_line('ODCIIndexUpdate>>>>>('||'RID'||' , '||i ||' , '|| newval.CellDemandValues(i)|| ')'); i := newval.CellDemandValues.NEXT(i); END LOOP; dbms_sql.close_cursor(cid2); RETURN ODCICONST.SUCCESS; END ODCIIndexUpdate;
ODCIIndexUpdate
は、次のように終了するCREATE
TYPE
BODY
文で定義されている最後のメソッドです。
END; /
オプションのODCIIndexGetMetadata
ファンクションが存在する場合は、例15-18で示されるように、実装固有の(システム・カタログに格納されない)メタデータをエクスポート・ダンプ・ファイルに書き込むために、エクスポート・ユーティリティによりコールされます。このメタデータは、ポリシー情報、バージョン情報、ユーザー設定などです。このメタデータは、関連索引が作成される直前のインポート時に実行される無名PL/SQLブロックとしてダンプ・ファイルに書き込まれます。
このメソッドは、PL/SQLブロックのコードで構成されるエクスポート・ユーティリティに文字列を戻します。エクスポート・ユーティリティは、長さ0(ゼロ)の文字列が戻されるまで、このメソッドを繰り返しコールするため、任意の複雑度を持つ必要な数のPL/SQLブロックを作成できます。通常、このメソッドは、カーソルや反復カウンタなど、エクスポート・ユーティリティによる複数のコール間で状態を維持するパッケージ・レベルの変数を使用するために、PL/SQLパッケージ内のファンクションをコールします。
関連項目 エクスポート・ユーティリティとインポート・ユーティリティの詳細は、『Oracle Databaseユーティリティ』を参照してください。 |
電力需要カートリッジでは、渡されるメタデータはバージョン文字列V1.0
のみです。この文字列は、ドメイン索引の基礎となる索引構成表の現行の書式を識別します。power_pkg
.getversion
ファンクションにより、power_pkg
.checkversion
プロシージャへのコールが生成されます。このプロシージャは、インポート時に実行され、バージョン文字列がV1.0
であるかどうかをチェックします。
例15-18 電力需要カートリッジのODCIIndexGetMetadata()の実装の登録方法
STATIC FUNCTION ODCIIndexGetMetadata( ia sys.ODCIIndexInfo, expversion VARCHAR2, newblock OUT PLS_INTEGER, env sys.ODCIEnv) RETURN VARCHAR2 IS BEGIN -- Let getversion do all the work since it has to maintain state across calls. RETURN power_pkg.getversion (ia.IndexSchema, ia.IndexName, newblock); EXCEPTION WHEN OTHERS THEN RAISE; END ODCIIndexGetMetaData;
power_pkg
パッケージの定義は次のとおりです。
例15-19 電力需要カートリッジのpower_pkgの作成方法
CREATE OR REPLACE PACKAGE power_pkg AS FUNCTION getversion( idxschema IN VARCHAR2, idxname IN VARCHAR2, newblock OUT PLS_INTEGER) RETURN VARCHAR2; PROCEDURE checkversion ( version IN VARCHAR2); END power_pkg; / SHOW ERRORS; CREATE OR REPLACE PACKAGE BODY power_pkg AS -- iterate is a package-level variable used to maintain state across calls -- by Export in this session. iterate NUMBER := 0; FUNCTION getversion( idxschema IN VARCHAR2, idxname IN VARCHAR2, newblock OUT PLS_INTEGER) RETURN VARCHAR2 IS BEGIN -- We are generating only one PL/SQL block consisting of one line of code. newblock := 1; IF iterate = 0 THEN -- Increment iterate so we'll know we're done next time we're called. iterate := iterate + 1; -- Return a string that calls checkversion with a version 'V1.0' -- Note that export adds the surrounding BEGIN/END pair to form the anon. -- block... we don't have to. RETURN 'power_pkg.checkversion(''V1.0'');'; ELSE -- reset iterate for next index iterate := 0; -- Return a 0-length string; we won't be called again for this index. RETURN ''; END IF; END getversion; PROCEDURE checkversion (version IN VARCHAR2) IS wrong_version EXCEPTION; BEGIN IF version != 'V1.0' THEN RAISE wrong_version; END IF; END checkversion; END power_pkg;
電力需要カートリッジでは、ドメイン索引の索引タイプが作成されます。指定には、例15-20で示されるように、索引タイプでサポートされている演算子のリストが含まれます。また、OCDI索引ルーチンを含む実装タイプも識別されます。
例15-20 電力需要カートリッジの索引タイプpower_idxtypeの作成方法
CREATE OR REPLACE INDEXTYPE power_idxtype FOR Power_Equals(PowerDemand_Typ, NUMBER, NUMBER), Power_GreaterThan(PowerDemand_Typ, NUMBER, NUMBER), Power_LessThan(PowerDemand_Typ, NUMBER, NUMBER), Power_EqualsAny(PowerDemand_Typ, NUMBER), Power_GreaterThanAny(PowerDemand_Typ, NUMBER), Power_LessThanAny(PowerDemand_Typ, NUMBER) USING power_idxtype_im;
この項では、電力需要カートリッジのうち、拡張可能最適化に関連する部分について説明します。コード・セグメントを示しながら説明していきます。
表PowerCartUserStats
を使用して、例15-21で示されるように、1時間当たりの電力グリッドの測定値に関する統計が格納されます。これらの統計は、メソッドODCIStatsSelectivity()で演算子述語の選択性を見積もるために使用されます。収集される統計のタイプの関係で、Oracleに統計を格納させるよりも個別の表を使用する方が便利です。
PowerCartUserStats
表には、次の列が含まれています。
統計が収集される表および列
統計が収集されるセル
すべての電力グリッドの測定値にわたる特定のセルの最小および最大電力需要
すべての電力グリッドの測定値にわたる特定のセルのNULL
以外の測定値の数
例15-21 電力需要カートリッジの統計表のPowerCartUserStat作成方法
CREATE TABLE PowerCartUserStats ( -- Table for which statistics are collected tab VARCHAR2(30), -- Column for which statistics are collected col VARCHAR2(30), -- Cell position cpos NUMBER, -- Minimum power demand for the given cell lo NUMBER, -- Maximum power demand for the given cell hi NUMBER, -- Number of (non-null) power demands for the given cell nrows NUMBER ); /
電力需要カートリッジでは、拡張可能オプティマイザにより使用されるメソッドを指定するオブジェクト型が作成されます。これらのメソッドはODCIStats
(Oracle Data Cartridge Interface STATisticS)インタフェースの一部であり、DBMS_STATS
パッケージのメソッドによりコールされるメソッドを集合的に定義するか、または、オプティマイザが問合せに最適の実行計画を決定するときに集合的に定義します。
表15-5に、電力需要カートリッジ用に作成されるメソッドのファンクションを示します。1つを除くすべてのファンクション名は文字列ODCIStats
で始まります。
表15-5 拡張可能オプティマイザ・メソッド
メソッド | 説明 |
---|---|
|
型により実装されるインタフェースの名前のリストを戻します。 |
|
PowerDemand_Typ型の列または索引タイプpower_idxtypeのドメイン索引の統計を収集します。 このメソッドは、 |
|
このメソッドは、該当する型の列または該当する索引タイプの索引の統計を削除する文の発行時にコールされます。 |
|
演算子またはファンクション実装に関係する述語の選択性を計算します。 問合せの |
|
ドメイン索引のアクセス・パスのコストを計算します。 索引を問合せに使用できる場合にドメイン索引のアクセス・パスのコストを取得するために、オプティマイザによりコールされます。 |
|
ファンクションのコストを計算します。 ファンクション実行のコストを取得するために、オプティマイザによりコールされます。ファンクションは、演算子の実装でない場合もあります。 |
例15-22では、power_statistics
オブジェクト型を作成します。このオブジェクト型のODCIメソッドは、列および索引に関する統計の収集および削除、演算子またはファンクションによる述語の選択性の計算、ドメイン索引およびファンクションのコストの計算に使用されます。curnum
属性は使用されません。
例15-22 電力需要カートリッジのpower_statisticsオブジェクト型定義の作成方法
CREATE OR REPLACE TYPE power_statistics AS OBJECT ( curnum NUMBER, STATIC FUNCTION ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) RETURN NUMBER, STATIC FUNCTION ODCIStatsCollect(col sys.ODCIColInfo, options sys.ODCIStatsOptions, rawstats OUT RAW, env sys.ODCIEnv) RETURN NUMBER, STATIC FUNCTION ODCIStatsDelete(col sys.ODCIColInfo, env sys.ODCIEnv) RETURN NUMBER, STATIC FUNCTION ODCIStatsCollect(ia sys.ODCIIndexInfo, options sys.ODCIStatsOptions, rawstats OUT RAW, env sys.ODCIEnv) RETURN NUMBER, STATIC FUNCTION ODCIStatsDelete(ia sys.ODCIIndexInfo, env sys.ODCIEnv) RETURN NUMBER, STATIC FUNCTION ODCIStatsSelectivity(pred sys.ODCIPredInfo, sel OUT NUMBER, args sys.ODCIArgDescList, strt NUMBER, stop NUMBER, object PowerDemand_Typ, cell NUMBER, value NUMBER, env sys.ODCIEnv) RETURN NUMBER, PRAGMA restrict_references(ODCIStatsSelectivity, WNDS, WNPS), STATIC FUNCTION ODCIStatsSelectivity(pred sys.ODCIPredInfo, sel OUT NUMBER, args sys.ODCIArgDescList, strt NUMBER, stop NUMBER, object PowerDemand_Typ, value NUMBER, env sys.ODCIEnv) RETURN NUMBER, PRAGMA restrict_references(ODCIStatsSelectivity, WNDS, WNPS), STATIC FUNCTION ODCIStatsIndexCost(ia sys.ODCIIndexInfo, sel NUMBER, cost OUT sys.ODCICost, qi sys.ODCIQueryInfo, pred sys.ODCIPredInfo, args sys.ODCIArgDescList, strt NUMBER, stop NUMBER, cmppos NUMBER, cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER, PRAGMA restrict_references(ODCIStatsIndexCost, WNDS, WNPS), STATIC FUNCTION ODCIStatsIndexCost(ia sys.ODCIIndexInfo, sel NUMBER, cost OUT sys.ODCICost, qi sys.ODCIQueryInfo, pred sys.ODCIPredInfo, args sys.ODCIArgDescList, strt NUMBER, stop NUMBER, cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER, PRAGMA restrict_references(ODCIStatsIndexCost, WNDS, WNPS), STATIC FUNCTION ODCIStatsFunctionCost(func sys.ODCIFuncInfo, cost OUT sys.ODCICost, args sys.ODCIArgDescList, object PowerDemand_Typ, cell NUMBER, value NUMBER, env sys.ODCIEnv) RETURN NUMBER, PRAGMA restrict_references(ODCIStatsFunctionCost, WNDS, WNPS), STATIC FUNCTION ODCIStatsFunctionCost(func sys.ODCIFuncInfo, cost OUT sys.ODCICost, args sys.ODCIArgDescList, object PowerDemand_Typ, value NUMBER, env sys.ODCIEnv) RETURN NUMBER, PRAGMA restrict_references(ODCIStatsFunctionCost, WNDS, WNPS) STATIC FUNCTION ODCIStatsFunctionCost(func sys.ODCIFuncInfo, cost OUT sys.ODCICost, args sys.ODCIArgDescList, object PowerDemand_Typ, cell NUMBER, value NUMBER, env sys.ODCIEnv) RETURN NUMBER ); /
CREATE TYPE
文の後に、各メンバー・ファンクションの実装を指定するCREATE TYPE BODY
文があります。
CREATE OR REPLACE TYPE BODY power_statistics IS ...
各メンバー・ファンクションについては個別の項で説明しますが、ファンクション定義の一般的な書式は次のとおりです。
STATIC FUNCTION function-name (...) BEGIN RETURN NUMBER IS END;
ODCIGetInterfaces()ファンクションは、例15-23で示されるように、型により実装されるインタフェースの名前のリストを戻します。拡張可能オプティマイザ・インタフェース・ルーチンはSYS.ODCISTATS
の1組のみですが、サーバーでは下位互換性を維持するために複数のバージョンがサポートされます。ルーチンの現行バージョンを指定するには、ファンクションODCIGetInterfaces()のOUT
、ODCIObjectList
パラメータでSYS.ODCISTATS2
を指定する必要があります。
注意: ルーチンに対するOracle9iでの変更にあわせて更新されない既存のOracle8iコードを引き続き使用するには、引き続きファンクションODCIGetInterfaces でSYS.ODCISTATS1 を指定します。 |
ODCIStatsCollect()ファンクションは、例15-24で示されるように、データ型がPowerDemand_Typ
オブジェクト型である列の統計を収集します。統計は、すべての電力グリッド測定値にわたって列のセルごとに収集されます。特定のセルについて統計として収集されるのは、電力グリッドの最小および最大測定値と、NULL以外の測定値の数です。
このファンクションは、SYS.ODCICOLINFO
型のオブジェクト・パラメータとして列情報を取ります。型の属性は、表名、列名などです。列統計の収集に使用するDBMS_STATS
パッケージのコマンドで指定されたオプションも、パラメータとして渡されます。電力需要カートリッジでは統計が表に格納されるため、出力パラメータrawstats
は使用されません。
例15-24 電力需要カートリッジのPowerDemamnd_Type列のODCIStatsCollect()の実装の登録方法
STATIC FUNCTION ODCIStatsCollect( col sys.ODCIColInfo, options sys.ODCIStatsOptions, rawstats OUT RAW, env sys.ODCIEnv) RETURN NUMBER IS cnum INTEGER; stmt VARCHAR2(1000); junk INTEGER; cval NUMBER; colname VARCHAR2(30) := rtrim(ltrim(col.colName, '"'), '"'); statsexists BOOLEAN := FALSE; pdemands PowerDemand_Tab%ROWTYPE; user_defined_stats PowerCartUserStats%ROWTYPE; CURSOR c1(tname VARCHAR2, cname VARCHAR2) IS SELECT * FROM PowerCartUserStats WHERE tab = tname AND col = cname; CURSOR c2 IS SELECT * FROM PowerDemand_Tab; BEGIN sys.ODCIColInfoDump(col); sys.ODCIStatsOptionsDump(options); IF (col.TableSchema IS NULL OR col.TableName IS NULL OR col.ColName IS NULL) THEN RETURN ODCIConst.Error; END IF; dbms_output.put_line('ODCIStatsCollect>>>>>'); dbms_output.put_line('**** Analyzing column '||col.TableSchema|| '.' || col.TableName|| '.' || col.ColName); -- Check if statistics exist for this column FOR user_defined_stats IN c1(col.TableName, colname) LOOP statsexists := TRUE; EXIT; END LOOP;
ファンクションでは、この列の統計が存在するかどうかがチェックされます。存在する場合は統計がNULL
に初期化され、存在しない場合は100個のセルについて統計が個別に作成され、NULL
に初期化されます。
IF not statsexists THEN -- column statistics don't exist; create entries for each of the 100 cells cnum := dbms_sql.open_cursor; FOR i in 1..100 LOOP stmt := 'INSERT INTO PowerCartUserStats VALUES( '||''''|| col.TableName || ''', '||''''||colname||''', '||to_char(i)||', '||'NULL, NULL, NULL)'; dbms_sql.parse(cnum, stmt, dbms_sql.native); junk := dbms_sql.execute(cnum); END LOOP; dbms_sql.close_cursor(cnum); ELSE -- column statistics exist; initialize to NULL cnum := dbms_sql.open_cursor; stmt := 'UPDATE PowerCartUserStats'|| ' SET lo = NULL, hi = NULL, nrows = NULL'||' WHERE tab = '|| col.TableName||' AND col = '||colname; dbms_sql.parse(cnum, stmt, dbms_sql.native); junk := dbms_sql.execute(cnum); dbms_sql.close_cursor(cnum); END IF;
ファンクションにより分析対象の表から行が読み取られ、列の統計が収集されます。そのために、SQL文が構成されて実行されます。
-- For each cell position, the following statistics are collected: -- maximum value -- minimum value -- number of rows (excluding NULLs) cnum := dbms_sql.open_cursor; FOR i in 1..100 LOOP FOR pdemands IN c2 LOOP IF i BETWEEN pdemands.sample.CellDemandValues.FIRST AND pdemands.sample.CellDemandValues.LAST THEN cval := pdemands.sample.CellDemandValues(i); stmt := 'UPDATE PowerCartUserStats SET '|| 'lo = least(' || 'NVL(' || to_char(cval)||', lo), '||'NVL('||'lo, '||to_char(cval)||')), '|| 'hi = greatest('||'NVL('||to_char(cval)||', hi), '||'NVL('|| 'hi, '||to_char(cval)||')), '|| 'nrows = decode(nrows, NULL, decode('||to_char(cval)|| ', NULL, NULL, 1), decode('||to_char(cval)|| ', NULL, nrows, nrows+1)) '||'WHERE cpos = '||to_char(i)|| ' AND tab = '''||col.TableName||''''||' AND col = '''||colname|| ''''; dbms_sql.parse(cnum, stmt, dbms_sql.native); junk := dbms_sql.execute(cnum); END IF; END LOOP; END LOOP;
最後に、このファンクションはカーソルをクローズし、成功ステータスを戻して終了します。
dbms_sql.close_cursor(cnum); rawstats := NULL; return ODCIConst.Success; END ODCIStatsCollect;
ODCIStatsDelete()ファンクションは、例15-25で示されるように、データ型がPowerDemand_Typ
オブジェクト型である列の統計を削除します。このファンクションは、SYS.ODCICOLINFO
型のオブジェクト・パラメータとして列情報を取ります。型の属性は、表名、列名などです。
例15-25 電力需要カートリッジのPowerDemand_Typ列のODCIStatsDelete()の実装の登録方法
STATIC FUNCTION ODCIStatsDelete( col sys.ODCIColInfo, env sys.ODCIEnv) RETURN NUMBER IS cnum INTEGER; stmt VARCHAR2(1000); junk INTEGER; colname VARCHAR2(30) := rtrim(ltrim(col.colName, '"'), '"'); statsexists BOOLEAN := FALSE; user_defined_stats PowerCartUserStats%ROWTYPE; CURSOR c1(tname VARCHAR2, cname VARCHAR2) IS SELECT * FROM PowerCartUserStats WHERE tab = tname AND col = cname; BEGIN sys.ODCIColInfoDump(col); IF (col.TableSchema IS NULL OR col.TableName IS NULL OR col.ColName IS NULL) THEN RETURN ODCIConst.Error; END IF; dbms_output.put_line('ODCIStatsDelete>>>>>'); dbms_output.put_line('**** Analyzing (delete) column '|| col.TableSchema|| '.' ||col.TableName||'.'||col.ColName);
このファンクションは、統計表をチェックして列の統計が存在することを確認します。統計が収集されていない場合は、何も実行されません。ただし、統計が存在する場合は、SQL文が構成されて実行され、統計表から関連する行が削除されます。
-- Check if statistics exist for this column FOR user_defined_stats IN c1(col.TableName, colname) LOOP statsexists := TRUE; EXIT; END LOOP; -- If user-defined statistics exist, delete them IF statsexists THEN stmt := 'DELETE FROM PowerCartUserStats'||' WHERE tab = '''||col.TableName|| ''''|| ' AND col = ''' || colname || ''''; cnum := dbms_sql.open_cursor; dbms_output.put_line('ODCIStatsDelete>>>>>'); dbms_output.put_line('ODCIStatsDelete>>>>>' || stmt); dbms_sql.parse(cnum, stmt, dbms_sql.native); junk := dbms_sql.execute(cnum); dbms_sql.close_cursor(cnum); END IF; RETURN ODCIConst.Success; END ODCStatsDelete;
ODCIStatsCollect()ファンクションは、例15-26で示されるように、索引タイプがpower_idxtype
であるドメイン索引の統計を収集します。電力需要カートリッジの場合、このファンクションは単に索引データを格納する索引構成表を分析します。
このファンクションは、SYS.ODCIINDEXINFO
型のオブジェクト・パラメータとして索引情報を取ります。型の属性は、索引名、所有者名などです。索引統計の収集に使用するDBMS_STATS
パッケージで指定されたオプションも、パラメータとして渡されます。出力パラメータrawstats
は使用されません。
例15-26 電力需要カートリッジのpower_idxtypeドメイン索引のODCIStatsCollect()の実装の登録方法
STATIC FUNCTION ODCIStatsCollect ( ia sys.ODCIIndexInfo, options sys.ODCIStatsOptions, rawstats OUT RAW, env sys.ODCIEnv) RETURN NUMBER IS stmt VARCHAR2(1000); BEGIN -- To analyze a domain index, analyze the table that implements the index sys.ODCIIndexInfoDump(ia); sys.ODCIStatsOptionsDump(options); stmt := 'dbms_stats.gather_table_stats(' || '''' || ia.IndexSchema || ''', ' || '''' || ia.IndexName || '_pidx' || ''');'; dbms_output.put_line('**** Analyzing index ' || ia.IndexSchema || '.' || ia.IndexName); dbms_output.put_line('SQL Statement: ' || stmt); EXECUTE IMMEDIATE 'BEGIN ' || stmt || ' END;'; rawstats := NULL; RETURN ODCIConst.Success; END ODCIStatsCollect;
ODCIStatsDelete()ファンクションは、例15-27で示されるように、索引タイプがpower_idxtype
であるドメイン索引の統計を削除します。電力需要カートリッジの場合、このファンクションは単に索引データを格納する索引構成表の統計を削除します。
このファンクションは、SYS.ODCIINDEXINFO
型のオブジェクト・パラメータとして索引情報を取ります。型の属性は、索引名、所有者名などです。
例15-27 電力需要カートリッジのドメイン索引power_idxtypeのODCIStatsDelete()の実装の登録方法
STATIC FUNCTION ODCIStatsDelete( ia sys.ODCIIndexInfo, env sys.ODCIEnv) RETURN NUMBER IS stmt VARCHAR2(1000); BEGIN -- To delete statistics for a domain index, delete the statistics for the -- table implementing the index sys.ODCIIndexInfoDump(ia); stmt := 'dbms_stats.delete_table_stats('|| '''' || ia.IndexSchema || ''', ' || '''' || ia.IndexName || '_pidx' || ''');'; dbms_output.put_line('**** Analyzing (delete) index '||ia.IndexSchema||'.'|| ia.IndexName); dbms_output.put_line('SQL Statement: ' || stmt); EXECUTE IMMEDIATE 'BEGIN ' || stmt || ' END;'; RETURN ODCIConst.Success; END ODCIStatsDelete;
ODCIStatsSelectivity()ファンクションの最初の定義では、Specific
問合せに対する演算子またはファンクションの述語の選択性が見積られます。たとえば、問合せでセル(3,7)
の値が25
であるインスタンスをすべて要求すると、このファンクションはセル(3,7)
が25
である行の割合を見積ります。
pred
パラメータには、ファンクション情報(演算子述語に含まれる演算子のファンクション実装)が含まれています。このパラメータは、SYS.ODCIPREDINFO
型のオブジェクト・インスタンスです。選択性は、sel
出力パラメータでパーセンテージとして戻されます。args
パラメータ(SYS.ODCIARGDESCLIST
型のオブジェクト・インスタンス)には、ファンクションの各引数のディスクリプタと、ファンクションの開始値および終了値が含まれています。たとえば、引数に列を使用すると、引数のディスクリプタには表名、列名などが含まれます。strt
およびstop
パラメータは、ファンクション戻り値の上限と下限の境界ポイントです。述語内のファンクションにPowerDemand_Typ
型のリテラルが含まれている場合、object
パラメータにはオブジェクト・コンストラクタ形式の値が含まれます。cell
パラメータはセル位置で、value
パラメータはファンクション(PowerXxxxxSpecific_Func
)で指定されたセルの値です。
選択性は、単純な範囲述語に使用されるものと同様の方法で見積られます。たとえば、述語の選択性の単純な見積りは次のようになります。
c > v
これが(M-v)/(M-m)
であるとします。m
およびM
は、それぞれ値v
がm
〜M
の場合の列c
(列統計から判別)の最小値と最大値です。
get_selectivity
ファンクションは、例15-28で示されるように、述語で指定された列の最小値と最大値について、単純な範囲述語の選択性を計算します。この場合、表の列値は最小値と最大値の間に均一に分布しているものとみなされます。
例15-28 電力需要カートリッジのget_selectivity()ファンクションの実装方法
CREATE FUNCTION get_selectivity(relop VARCHAR2, value NUMBER, lo NUMBER, hi NUMBER, ndv NUMBER) RETURN NUMBER AS sel NUMBER := NULL; ndv NUMBER; BEGIN -- This function computes the selectivity (as a percentage) -- of a predicate -- col <relop> <value> -- where <relop> is one of: =, !=, <, <=, >, >= -- <value> is one of: 0, 1 -- lo and hi are the minimum and maximum values of the column in -- the table. This function performs a simplistic estimation of the -- selectivity by assuming that the range of distinct values of -- the column is distributed uniformly in the range lo..hi and that -- each distinct value occurs nrows/(hi-lo+1) times (where nrows is -- the number of rows). IF ndv IS NULL OR ndv <= 0 THEN RETURN 0; END IF; -- col != <value> IF relop = '!=' THEN IF value between lo and hi THEN sel := 1 - 1/ndv; ELSE sel := 1; END IF; -- col = <value> ELSIF relop = '=' THEN IF value between lo and hi THEN sel := 1/ndv; ELSE sel := 0; END IF; -- col >= <value> ELSIF relop = '>=' THEN IF lo = hi THEN IF value <= lo THEN sel := 1; ELSE sel := 0; END IF; ELSIF value between lo and hi THEN sel := (hi-value)/(hi-lo) + 1/ndv; ELSIF value < lo THEN sel := 1; ELSE sel := 0; END IF; -- col < <value> ELSIF relop = '<' THEN IF lo = hi THEN IF value > lo THEN sel := 1; ELSE sel := 0; END IF; ELSIF value between lo and hi THEN sel := (value-lo)/(hi-lo); ELSIF value < lo THEN sel := 0; ELSE sel := 1; END IF; -- col <= <value> ELSIF relop = '<=' THEN IF lo = hi THEN IF value >= lo THEN sel := 1; ELSE sel := 0; END IF; ELSIF value between lo and hi THEN sel := (value-lo)/(hi-lo) + 1/ndv; ELSIF value < lo THEN sel := 0; ELSE sel := 1; END IF; -- col > <value> ELSIF relop = '>' THEN IF lo = hi THEN IF value < lo THEN sel := 1; ELSE sel := 0; END IF; ELSIF value between lo and hi THEN sel := (hi-value)/(hi-lo); ELSIF value < lo THEN sel := 1; ELSE sel := 0; END IF; END IF; RETURN least(100, ceil(100*sel)); END; /
ODCIStatsSelectivity()ファンクションは、例15-29で示されるように、一定の開始値と終了値を持つファンクションの述語の選択性を見積ります。さらに、述語内のファンクションの最初の因数にはPowerDemand_Typ
型の列を指定し、残りの引数を指定する必要があります。
例15-29 電力需要カートリッジのSpecific問合せのODCIStatsSelectivity()の実装の登録方法
STATIC FUNCTION ODCIStatsSelectivity(pred sys.ODCIPredInfo, sel OUT NUMBER, args sys.ODCIArgDescList, strt NUMBER, stop NUMBER, object PowerDemand_Typ, cell NUMBER, value NUMBER, env sys.ODCIEnv) RETURN NUMBER IS fname varchar2(30); relop varchar2(2); lo NUMBER; hi NUMBER; nrows NUMBER; colname VARCHAR2(30); statsexists BOOLEAN := FALSE; stats PowerCartUserStats%ROWTYPE; CURSOR c1(cell NUMBER, tname VARCHAR2, cname VARCHAR2) IS SELECT * FROM PowerCartUserStats WHERE cpos = cell AND tab = tname AND col = cname; BEGIN -- compute selectivity only when predicate is of the form: -- fn(col, <cell>, <value>) <relop> <val> -- In all other cases, return an error and let the optimizer -- make a guess. We also assume that the function "fn" has -- a return value of 0, 1, or NULL. -- start value IF (args(1).ArgType != ODCIConst.ArgLit AND args(1).ArgType != ODCIConst.ArgNull) THEN RETURN ODCIConst.Error; END IF; -- stop value IF (args(2).ArgType != ODCIConst.ArgLit AND args(2).ArgType != ODCIConst.ArgNull) THEN RETURN ODCIConst.Error; END IF; -- first argument of function IF (args(3).ArgType != ODCIConst.ArgCol) THEN RETURN ODCIConst.Error; END IF; -- second argument of function IF (args(4).ArgType != ODCIConst.ArgLit AND args(4).ArgType != ODCIConst.ArgNull) THEN RETURN ODCIConst.Error; END IF; -- third argument of function IF (args(5).ArgType != ODCIConst.ArgLit AND args(5).ArgType != ODCIConst.ArgNull) THEN RETURN ODCIConst.Error; END IF; colname := rtrim(ltrim(args(3).colName, '"'), '"');
述語にあるファンクションの最初の(列)引数は、収集済の統計を指定する必要があります。統計が収集されていない場合、ODCIStatsSelectivity()はエラー・ステータスを戻します。
-- Check if the statistics table exists (we are using a -- user-defined table to store the user-defined statistics). -- Get user-defined statistics: MIN, MAX, NROWS FOR stats IN c1(cell, args(3).TableName, colname) LOOP -- Get user-defined statistics: MIN, MAX, NROWS lo := stats.lo; hi := stats.hi; nrows := stats.nrows; statsexists := TRUE; EXIT; END LOOP; -- If no user-defined statistics were collected, return error IF not statsexists THEN RETURN ODCIConst.Error; END IF;
各Specific
ファンクションは、等価の範囲述語に対応する述語を指定します。たとえば、引数Power_EqualsSpecific_Func(col, 21, 25) = 0
は、セル21
の読取りが25
に等しくないことをチェックし、等価の範囲述語col[21] != 25
に対応します。
ODCIStatsSelectivity()ファンクションは、Specific
ファンクションの述語ごとに、対応する範囲述語を検索します。選択性を即時に判断できる複数の境界事例があります。
-- selectivity is 0 for "fn(col, <cell>, <value>) < 0" IF (stop = 0 AND bitand(pred.Flags, ODCIConst.PredIncludeStop) = 0) THEN sel := 0; RETURN ODCIConst.Success; END IF; -- selectivity is 0 for "fn(col, <cell>, <value>) > 1" IF (strt = 1 AND bitand(pred.Flags, ODCIConst.PredIncludeStart) = 0) THEN sel := 0; RETURN ODCIConst.Success; END IF; -- selectivity is 100% for "fn(col, <cell>, <value>) >= 0" IF (strt = 0 AND bitand(pred.Flags, ODCIConst.PredExactMatch) = 0 AND bitand(pred.Flags, ODCIConst.PredIncludeStart) > 0) THEN sel := 100; RETURN ODCIConst.Success; END IF; -- selectivity is 100% for "fn(col, <cell>, <value>) <= 1" IF (stop = 1 AND bitand(pred.Flags, ODCIConst.PredExactMatch) = 0 AND bitand(pred.Flags, ODCIConst.PredIncludeStop) > 0) THEN sel := 100; RETURN ODCIConst.Success; END IF; -- get function name IF bitand(pred.Flags, ODCIConst.PredObjectFunc) > 0 THEN fname := pred.ObjectName; ELSE fname := pred.MethodName; END IF; -- convert prefix relational operator to infix: -- "Power_EqualsSpecific_Func(col, <cell>, <value>) = 1" -- becomes "col[<cell>] = <value>" -- Power_EqualsSpecific_Func(col, <cell>, <value>) = 0 -- Power_EqualsSpecific_Func(col, <cell>, <value>) <= 0 -- Power_EqualsSpecific_Func(col, <cell>, <value>) < 1 -- can be transformed to -- col[<cell>] != <value> IF (fname LIKE upper('Power_Equals%') AND (stop = 0 OR (stop = 1 AND bitand(pred.Flags, ODCIConst.PredIncludeStop) = 0))) THEN relop := '!='; -- Power_LessThanSpecific_Func(col, <cell>, <value>) = 0 -- Power_LessThanSpecific_Func(col, <cell>, <value>) <= 0 -- Power_LessThanSpecific_Func(col, <cell>, <value>) < 1 -- can be transformed to -- col[<cell>] >= <value> ELSIF (fname LIKE upper('Power_LessThan%') AND (stop = 0 OR (stop = 1 AND bitand(pred.Flags, ODCIConst.PredIncludeStop) = 0))) THEN relop := '>='; -- Power_GreaterThanSpecific_Func(col, <cell>, <value>) = 0 -- Power_GreaterThanSpecific_Func(col, <cell>, <value>) <= 0 -- Power_GreaterThanSpecific_Func(col, <cell>, <value>) < 1 -- can be transformed to -- col[<cell>] <= <value> ELSIF (fname LIKE upper('Power_GreaterThan%') AND (stop = 0 OR (stop = 1 AND bitand(pred.Flags, ODCIConst.PredIncludeStop) = 0))) THEN relop := '<='; -- Power_EqualsSpecific_Func(col, <cell>, <value>) = 1 -- Power_EqualsSpecific_Func(col, <cell>, <value>) >= 1 -- Power_EqualsSpecific_Func(col, <cell>, <value>) > 0 -- can be transformed to -- col[<cell>] = <value> ELSIF (fname LIKE upper('Power_Equals%') AND (strt = 1 OR (strt = 0 AND bitand(pred.Flags, ODCIConst.PredIncludeStart) = 0))) THEN relop := '='; -- Power_LessThanSpecific_Func(col, <cell>, <value>) = 1 -- Power_LessThanSpecific_Func(col, <cell>, <value>) >= 1 -- Power_LessThanSpecific_Func(col, <cell>, <value>) > 0 -- can be transformed to -- col[<cell>] < <value> ELSIF (fname LIKE upper('Power_LessThan%') AND (strt = 1 OR (strt = 0 AND bitand(pred.Flags, ODCIConst.PredIncludeStart) = 0))) THEN relop := '<'; -- Power_GreaterThanSpecific_Func(col, <cell>, <value>) = 1 -- Power_GreaterThanSpecific_Func(col, <cell>, <value>) >= 1 -- Power_GreaterThanSpecific_Func(col, <cell>, <value>) > 0 -- can be transformed to -- col[<cell>] > <value> ELSIF (fname LIKE upper('Power_GreaterThan%') AND (strt = 1 OR (strt = 0 AND bitand(pred.Flags, ODCIConst.PredIncludeStart) = 0))) THEN relop := '>'; ELSE RETURN ODCIConst.Error; END IF;
Specific
ファンクションの述語が単純な範囲述語に変換された後、ODCIStatsSelectivity()はget_selectivity
をコールして範囲述語(つまりSpecific
ファンクションの述語)の選択性を計算します。次のように成功ステータスが戻されます。
sel := get_selectivity(relop, value, lo, hi, nrows); RETURN ODCIConst.Success; END;
ODCIStatsIndexCost()ファンクションの最初の定義では、例15-30で示されるように、Specific
問合せに対するドメイン索引のコストが見積られます。たとえば、問合せでセル(3,7)
の値が25
であるインスタンスをすべて要求すると、このファンクションはドメイン索引のアクセス・パスのコストを見積って、この問合せを評価します。ODCIStatsIndexCost()のこの定義は、Any問合せのODCIStatsIndexCost()メソッドに関する項に示した定義とは、セルの位置を示すcmppos
パラメータを含むという点で異なります。
ia
パラメータには、索引情報としてSYS.ODCIINDEXINFO
型のオブジェクト・インスタンスが含まれています。sel
パラメータは、Specific
問合せに関してODCIStatsSelectivity()ファンクションにより見積られた演算子述語の選択性です。見積られたコストはcost
出力パラメータで戻されます。qi
パラメータには、オプティマイザ・モードALL_ROWS
およびFIRST_ROWS
のどちらが使用されているかなどの問合せとその環境に関する情報が含まれています。pred
パラメータには、演算子情報としてSYS.ODCIPREDINFO
型のオブジェクト・インスタンスが含まれています。args
パラメータには、演算子の値引数のディスクリプタおよび開始値と終了値が含まれています。strt
およびstop
パラメータは、演算子の戻り値の上限と下限の境界ポイントです。cmppos
パラメータはセル位置で、cmpval
は演算子Power_XxxxxSpecific()
で指定されたセルの値です。
電力需要カートリッジの場合、Specific
問合せに対するドメイン索引のコストはAny
問合せに対するドメイン索引のコストと同じです。そのため、Any問合せのODCIStatsIndexCost()メソッドに関する項で説明されるように、このバージョンのODCIStatsIndexCost()ファンクションは単にファンクションの第2の定義をコールします。
例15-30 電力需要カートリッジのSpecific問合せのODCISIndexCost()の実装の登録方法
STATIC FUNCTION ODCIStatsIndexCost(ia sys.ODCIIndexInfo, sel NUMBER, cost OUT sys.ODCICost, qi sys.ODCIQueryInfo, pred sys.ODCIPredInfo, args sys.ODCIArgDescList, strt NUMBER, stop NUMBER, cmppos NUMBER, cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER IS BEGIN -- This is the cost for queries on a specific cell; simply -- use the cost for queries on any cell. RETURN ODCIStatsIndexCost(ia, sel, cost, qi, pred, args, strt, stop, cmpval, env); END;
ODCIStatsIndexCost()ファンクションの最初の定義では、例15-31で示されるように、Any
問合せに対するドメイン索引のコストが見積られます。たとえば、問合せで任意のセルの値が25であるインスタンスをすべて要求すると、このファンクションはドメイン索引のアクセス・パスのコストを見積って、この問合せを評価します。ODCIStatsIndexCost()のこの定義はSpecific問合せのODCIStatsIndexCost()メソッドに関する項に示した定義とは、cmppos
パラメータを含まないという点で異なります。
ia
パラメータには、索引情報としてSYS.ODCIINDEXINFO
型のオブジェクト・インスタンスが含まれています。sel
パラメータは、Any
問合せに関してODCIStatsSelectivity()ファンクションにより見積られた演算子述語の選択性です。見積られたコストはcost
出力パラメータで戻されます。qi
パラメータには、オプティマイザ・モードALL_ROWS
およびFIRST_ROWS
のどちらが使用されているかなどの問合せとその環境に関する情報が含まれています。pred
パラメータには、演算子情報としてSYS.ODCIPREDINFO
型のオブジェクト・インスタンスが含まれています。args
パラメータには、演算子の値引数のディスクリプタおよび開始値と終了値が含まれています。strt
およびstop
パラメータは、演算子の戻り値の上限と下限の境界ポイントです。cmpval
パラメータは、演算子Power_XxxxxAny()
で指定されたセルの値です。
索引のコストは、演算子述語の選択性を定数の係数で乗算し、その値で索引を実装する索引構成表のブロック数を乗算した値として見積られます。
例15-31 電力需要カートリッジのAny問合せのODCIStatsIndexCost()の実装の登録方法
STATIC FUNCTION ODCIStatsIndexCost(ia sys.ODCIIndexInfo, sel NUMBER, cost OUT sys.ODCICost, qi sys.ODCIQueryInfo, pred sys.ODCIPredInfo, args sys.ODCIArgDescList, strt NUMBER, stop NUMBER, cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER IS ixtable VARCHAR2(40); numblocks NUMBER := NULL; get_table user_tables%ROWTYPE; CURSOR c1(tab VARCHAR2) IS SELECT * FROM user_tables WHERE table_name = tab; BEGIN -- This is the cost for queries on any cell. -- To compute the cost of a domain index, multiply the -- number of blocks in the table implementing the index -- with the selectivity -- Return if we don't have predicate selectivity IF sel IS NULL THEN RETURN ODCIConst.Error; END IF; cost := sys.ODCICost(NULL, NULL, NULL, NULL); -- Get name of table implementing the domain index ixtable := ia.IndexName || '_pidx'; -- Get number of blocks in domain index FOR get_table IN c1(upper(ixtable)) LOOP numblocks := get_table.blocks; EXIT; END LOOP; IF numblocks IS NULL THEN -- Exit if there are no user-defined statistics for the index RETURN ODCIConst.Error; END IF; cost.CPUCost := ceil(400*(sel/100)*numblocks); cost.IOCost := ceil(1.5*(sel/100)*numblocks); RETURN ODCIConst.Success; END;
ODCIStatsFunctionCost()ファンクションは、例15-32で示されるように、Power_XxxxxSpecific_Func()
ファンクションまたはPower_XxxxxAny_Func()
ファンクションの評価コストを見積ります。
func
パラメータには、ファンクション情報が含まれています。このパラメータは、SYS.ODCIFUNCINFO
型のオブジェクト・インスタンスです。見積られたコストはcost
出力パラメータで戻されます。args
パラメータであるSYS.ODCIARGDESCLIST
型のオブジェクト・インスタンスには、ファンクションの各引数のディスクリプタが含まれています。ファンクションに最初の引数であるPowerDemand_Typ
型のリテラルが含まれている場合、object
パラメータにはオブジェクト・コンストラクタ形式の値が含まれます。value
パラメータは、PowerXxxxxSpecific_Func()
ファンクションまたはPower_XxxxxAny_Func()
ファンクションで指定されたセルの値です。
ファンクションのコストは、ファンクション名に応じて単にデフォルト値として見積られます。ファンクションはディスクからデータを読み取らないため、I/Oコストは0(ゼロ)に設定されます。
例15-32 電力需要カートリッジのODCIStatsFunctionCost()の実装の登録方法
STATIC FUNCTION ODCIStatsFunctionCost(func sys.ODCIFuncInfo, cost OUT sys.ODCICost, args sys.ODCIArgDescList, object PowerDemand_Typ, value NUMBER, env sys.ODCIEnv) RETURN NUMBER IS fname VARCHAR2(30); BEGIN cost := sys.ODCICost(NULL, NULL, NULL, NULL); -- Get function name IF bitand(func.Flags, ODCIConst.ObjectFunc) > 0 THEN fname := func.ObjectName; ELSE fname := func.MethodName; END IF; IF fname LIKE upper('Power_LessThan%') THEN cost.CPUCost := 5000; cost.IOCost := 0; RETURN ODCIConst.Success; ELSIF fname LIKE upper('Power_Equals%') THEN cost.CPUCost := 7000; cost.IOCost := 0; RETURN ODCIConst.Success; ELSIF fname LIKE upper('Power_GreaterThan%') THEN cost.CPUCost := 5000; cost.IOCost := 0; RETURN ODCIConst.Success; ELSE RETURN ODCIConst.Error; END IF; END;
power_statistics
オブジェクト型で定義されたメソッドをオプティマイザで使用するには、例15-33で示されるように、適切なデータベース・オブジェクトに関連付ける必要があります。
例15-33 電力需要カートリッジのデータベース・オブジェクトとODCIStatsXXX()メソッドの関連付け方法
Associate statistics type with types, indextypes, and functions ASSOCIATE STATISTICS WITH TYPES PowerDemand_Typ USING power_statistics; ASSOCIATE STATISTICS WITH INDEXTYPES power_idxtype USING power_statistics WITH SYSTEM MANAGED STORAGE TABLES; ASSOCIATE STATISTICS WITH FUNCTIONS Power_EqualsSpecific_Func, Power_GreaterThanSpecific_Func, Power_LessThanSpecific_Func, Power_EqualsAny_Func, Power_GreaterThanAny_Func, Power_LessThanAny_Func USING power_statistics;
表、列および索引の分析により、各種アクセス・パスのコストを正確に見積って適切な計画を選択するための関連統計がオプティマイザに存在することを確認できます。また、power_statistics
オブジェクト型で定義されている選択性ファンクションとコスト・ファンクションも、統計の存在に依存します。例15-34に、データベース・オブジェクトを分析し、統計が実際に収集されたかどうかを検証する文を示します。
例15-34 電力需要カートリッジのデータベース・オブジェクトの分析方法
-- Analyze the table EXECUTE dbms_stats.gather_table_stats( 'POWERCARTUSER', 'POWERDEMAND_TAB', cascade => TRUE); -- Verify that user-defined statistics were collected SELECT tab tablename, col colname, cpos, lo, hi, nrows FROM PowerCartUserStats WHERE nrows IS NOT NULL ORDER BY cpos; -- Delete the statistics EXECUTE dbms_stats.delete_table_stats('POWERCARTUSER', 'POWERDEMAND_TAB'); -- Verify that user-defined statistics were deleted SELECT tab tablename, col colname, cpos, lo, hi, nrows FROM PowerCartUserStats WHERE nrows IS NOT NULL ORDER BY cpos; -- Re-analyze the table EXECUTE dbms_stats.gather_table_stats( 'POWERCARTUSER', 'POWERDEMAND_TAB',cascade => TRUE); -- Verify that user-defined statistics were re-collected SELECT tab tablename, col colname, cpos, lo, hi, nrows FROM PowerCartUserStats WHERE nrows IS NOT NULL ORDER BY cpos;
この項では、電力需要の例のうち、ドメイン索引の簡単なテストを実行する場合について説明し、また、索引を使用しない場合よりも問合せが効率的に実行されるかどうかを確認する方法について説明します。これらのテストは、次の操作で構成されます。
電力需要表(PowerDemand_Tab
)を作成し、少量のデータを移入します。
索引の作成前になんらかの問合せを実行(および、索引を使用しない実行計画を表示)します。
実行計画は、それぞれのケースで全表スキャンが実行されることを示します。
グリッドに索引を作成します。
索引の作成後に同じ問合せを実行(および、索引を使用した実行計画を表示)します。
実行計画は、Oracleが索引を使用しており、全表スキャンを実行していないため、実行効率が高いことを示します。
この項で説明する文は、サンプル・ファイル(tkqxpwr.sql)内でオンラインで使用可能です。
次の2列を使用して、例15-35で示されるように、電力需要表を作成します。
region
。電力会社が複数の区域または州でグリッド方式を使用できるようにします。ニューヨーク、ニュージャージー、ペンシルバニアなどの各地域は、10x10
のグリッドで表されます。
sample
。PowerDemand_Typ
オブジェクト型を使用して定義されたサンプリング、またはグリッドの各セルからの電力需要測定値のコレクションです。
例15-35 電源需要カートリッジのPowerDemand_Tab表の作成方法
CREATE TABLE PowerDemand_Tab ( -- Region for which these power demand readings apply region NUMBER, -- Values for each "sampling" time (for a given hour) sample PowerDemand_Typ );
数時間のタイムスタンプについて、2つの地域(1
および2
)の電力需要データを表す数行が挿入されます。単純化するために、値は各グリッドの最初の5
つの位置にのみ挿入され、例15-36で示されるように、残りの95
個の値はNULL
に設定されます。
例15-36 電源需要カートリッジのPowerDemand_Tab表の移入方法
-- The next INSERT statements "cheats" by supplying only 5 grid values -- First 5 INSERT statements are for region 1 (1 AM to 5 AM on 01-Feb-1998). INSERT INTO PowerDemand_Tab VALUES(1, PowerDemand_Typ(NULL, NULL, NULL, PowerGrid_Typ(55,8,13,9,5), to_date('02-01-1998 01','MM-DD-YYYY HH')) ); INSERT INTO PowerDemand_Tab VALUES(1, PowerDemand_Typ(NULL, NULL, NULL, PowerGrid_Typ(56,8,13,9,3), to_date('02-01-1998 02','MM-DD-YYYY HH')) ); INSERT INTO PowerDemand_Tab VALUES(1, PowerDemand_Typ(NULL, NULL, NULL, PowerGrid_Typ(55,8,13,9,3), to_date('02-01-1998 03','MM-DD-YYYY HH')) ); INSERT INTO PowerDemand_Tab VALUES(1, PowerDemand_Typ(NULL, NULL, NULL, PowerGrid_Typ(54,8,13,9,3), to_date('02-01-1998 04','MM-DD-YYYY HH')) ); INSERT INTO PowerDemand_Tab VALUES(1, PowerDemand_Typ(NULL, NULL, NULL, PowerGrid_Typ(54,8,12,9,3), to_date('02-01-1998 05','MM-DD-YYYY HH')) ); -- Also insert some rows for region 2. INSERT INTO PowerDemand_Tab VALUES(2, PowerDemand_Typ(NULL, NULL, NULL, PowerGrid_Typ(9,8,11,16,5), to_date('02-01-1998 01','MM-DD-YYYY HH')) ); INSERT INTO PowerDemand_Tab VALUES(2, PowerDemand_Typ(NULL, NULL, NULL, PowerGrid_Typ(9,8,11,20,5), to_date('02-01-1998 02','MM-DD-YYYY HH')) );
最後に、例15-37で示されるように、TotGridDemand
、MaxCellDemand
およびMinCellDemand
の値が計算され、新規に挿入された各行に設定され、これらの値が表示されます。
例15-37 電力需要カートリッジのグリッドの総需要、セルの最大需要および最小需要の計算方法
DECLARE CURSOR c1 IS SELECT Sample, Region FROM PowerDemand_Tab FOR UPDATE; s PowerDemand_Typ; r NUMBER; BEGIN OPEN c1; LOOP FETCH c1 INTO s,r; EXIT WHEN c1%NOTFOUND; s.SetTotalDemand; s.SetMaxDemand; s.SetMinDemand; dbms_output.put_line(s.TotGridDemand); dbms_output.put_line(s.MaxCellDemand); dbms_output.put_line(s.MinCellDemand); UPDATE PowerDemand_Tab SET Sample = s WHERE CURRENT OF c1; END LOOP; CLOSE c1; END; / -- Examine the values. SELECT region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, P.Sample.MinCellDemand, to_char(P.sample.sampletime, 'MM-DD-YYYY HH') FROM PowerDemand_Tab P;
この項では、問合せは表の各行に基礎となるファンクションPowerEqualsSpecific_Func()
を適用することで実行されます。これは、索引が未定義であるためです。
サンプル・ファイルには、特定のセル番号、および指定した値と等しいセル番号、それより大きいセル番号、それより小さいセル番号についてチェックする問合せが含まれています。たとえば、等価の問合せについては、例15-38で説明しています。
例15-38 電力需要カートリッジの索引を使用しない等価の問合せの作成方法
SET SERVEROUTPUT ON ------------------------------------------------------------------- -- Query, referencing the operators (without index) ------------------------------------------------------------------- explain plan for SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, P.Sample.MinCellDemand FROM PowerDemand_Tab P WHERE Power_Equals(P.Sample,2,10) = 1; @tkoqxpll SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, P.Sample.MinCellDemand FROM PowerDemand_Tab P WHERE Power_Equals(P.Sample,2,10) = 1; explain plan for SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, P.Sample.MinCellDemand FROM PowerDemand_Tab P WHERE Power_Equals(P.Sample,1,25) = 1; @tkoqxpll SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, P.Sample.MinCellDemand FROM PowerDemand_Tab P WHERE Power_Equals(P.Sample,1,25) = 1; explain plan for SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, P.Sample.MinCellDemand FROM PowerDemand_Tab P WHERE Power_Equals(P.Sample,2,8) = 1; @tkoqxpll SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, P.Sample.MinCellDemand FROM PowerDemand_Tab P WHERE Power_Equals(P.Sample,2,8) = 1; explain plan for SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, P.Sample.MinCellDemand FROM PowerDemand_Tab P WHERE Power_EqualsAny(P.Sample,9) = 1; @tkoqxpll SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, P.Sample.MinCellDemand FROM PowerDemand_Tab P WHERE Power_EqualsAny(P.Sample,9) = 1;
実行計画は、それぞれのケースで全表スキャンが実行されることを示します。
OPERATIONS OPTIONS OBJECT_NAME --------------- --------------- --------------- SELECT STATEMENT TABLE ACCESS FULL POWERDEMAND_TAB
この項の問合せは、「索引を使用しない問合せ」の問合せと同じですが、今回は索引が使用されています。
実行計画は、例15-40で示されるように、Oracleがドメイン索引を使用しており、全表スキャンを実行していないため、実行効率が高いことを示します。
例15-40 電力需要カートリッジの索引を使用する等価の問合せの作成方法
SQLPLUS> ------------------------------------------------------------------- SQLPLUS> -- Query, referencing the operators (with index) SQLPLUS> ------------------------------------------------------------------- SQLPLUS> explain plan for 2> SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, 3> P.Sample.MinCellDemand 4> FROM PowerDemand_Tab P 5> WHERE Power_Equals(P.Sample,2,10) = 1; Statement processed. SQLPLUS> @tkoqxpll SQLPLUS> set echo off Echo OFF Charwidth 15 OPERATIONS OPTIONS OBJECT_NAME --------------- --------------- --------------- SELECT STATEMEN TABLE ACCESS BY ROWID POWERDEMAND_TAB DOMAIN INDEX POWERINDEX 3 rows selected. Statement processed. Echo ON SQLPLUS> SQLPLUS> SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, 2> P.Sample.MinCellDemand 3> FROM PowerDemand_Tab P 4> WHERE Power_Equals(P.Sample,2,10) = 1; REGION SAMPLE.TOT SAMPLE.MAX SAMPLE.MIN ---------- ---------- ---------- ---------- 0 rows selected. ODCIIndexStart>>>>> ODCIIndexInfo Index owner : POWERCARTUSER Index name : POWERINDEX Table owner : POWERCARTUSER Table name : POWERDEMAND_TAB Indexed column : "SAMPLE" Indexed column type :POWERDEMAND_TYP Indexed column type schema:POWERCARTUSER ODCIPredInfo Object owner : POWERCARTUSER Object name : POWER_EQUALS Method name : Predicate bounds flag : Exact Match Include Start Key Include Stop Key start key : 1 stop key : 1 compare position : 2 compare value : 10 ODCIIndexStart>>>>>select r from POWERCARTUSER.POWERINDEX_pidx where cpos ='2' and cval ='10' ODCIIndexFetch>>>>> Nrows : 2000 ODCIIndexClose>>>>> SQLPLUS> SQLPLUS> explain plan for 2> SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, 3> P.Sample.MinCellDemand 4> FROM PowerDemand_Tab P 5> WHERE Power_Equals(P.Sample,2,8) = 1; Statement processed. SQLPLUS> @tkoqxpll SQLPLUS> set echo off Echo OFF Charwidth 15 OPERATIONS OPTIONS OBJECT_NAME --------------- --------------- --------------- SELECT STATEMEN TABLE ACCESS BY ROWID POWERDEMAND_TAB DOMAIN INDEX POWERINDEX 3 rows selected. Statement processed. Echo ON SQLPLUS> SQLPLUS> SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, 2> P.Sample.MinCellDemand 3> FROM PowerDemand_Tab P 4> WHERE Power_Equals(P.Sample,2,8) = 1; REGION SAMPLE.TOT SAMPLE.MAX SAMPLE.MIN ---------- ---------- ---------- ---------- 1 90 55 5 1 89 56 3 1 88 55 3 1 87 54 3 1 86 54 3 2 49 16 5 2 53 20 5 7 rows selected. ODCIIndexStart>>>>> ODCIIndexInfo Index owner : POWERCARTUSER Index name : POWERINDEX Table owner : POWERCARTUSER Table name : POWERDEMAND_TAB Indexed column : "SAMPLE" Indexed column type :POWERDEMAND_TYP Indexed column type schema:POWERCARTUSER ODCIPredInfo Object owner : POWERCARTUSER Object name : POWER_EQUALS Method name : Predicate bounds flag : Exact Match Include Start Key Include Stop Key start key : 1 stop key : 1 compare position : 2 compare value : 8 ODCIIndexStart>>>>>select r from POWERCARTUSER.POWERINDEX_pidx where cpos ='2' and cval ='8' ODCIIndexFetch>>>>> Nrows : 2000 ODCIIndexClose>>>>> SQLPLUS> SQLPLUS> explain plan for 2> SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, 3> P.Sample.MinCellDemand 4> FROM PowerDemand_Tab P 5> WHERE Power_EqualsAny(P.Sample,9) = 1; Statement processed. SQLPLUS> @tkoqxpll SQLPLUS> set echo off Echo OFF Charwidth 15 OPERATIONS OPTIONS OBJECT_NAME --------------- --------------- --------------- SELECT STATEMEN TABLE ACCESS BY ROWID POWERDEMAND_TAB DOMAIN INDEX POWERINDEX 3 rows selected. Statement processed. Echo ON SQLPLUS> SQLPLUS> SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, 2> P.Sample.MinCellDemand 3> FROM PowerDemand_Tab P 4> WHERE Power_EqualsAny(P.Sample,9) = 1; REGION SAMPLE.TOT SAMPLE.MAX SAMPLE.MIN ---------- ---------- ---------- ---------- 1 90 55 5 1 89 56 3 1 88 55 3 1 87 54 3 1 86 54 3 2 49 16 5 2 53 20 5 7 rows selected. ODCIIndexStart>>>>> ODCIIndexInfo Index owner : POWERCARTUSER Index name : POWERINDEX Table owner : POWERCARTUSER Table name : POWERDEMAND_TAB Indexed column : "SAMPLE" Indexed column type :POWERDEMAND_TYP Indexed column type schema:POWERCARTUSER ODCIPredInfo Object owner : POWERCARTUSER Object name : POWER_EQUALSANY Method name : Predicate bounds flag : Exact Match Include Start Key Include Stop Key start key : 1 stop key : 1 compare value : 9 ODCIIndexStart>>>>>select distinct r from POWERCARTUSER.POWERINDEX_pidx where cval ='9' ODCIIndexFetch>>>>> Nrows : 2000 ODCIIndexClose>>>>> SQLPLUS> SQLPLUS> explain plan for 2> SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, 3> P.Sample.MinCellDemand 4> FROM PowerDemand_Tab P 5> WHERE Power_GreaterThanAny(P.Sample,50) = 1; Statement processed. SQLPLUS> @tkoqxpll SQLPLUS> set echo off Echo OFF Charwidth 15 OPERATIONS OPTIONS OBJECT_NAME --------------- --------------- --------------- SELECT STATEMEN TABLE ACCESS BY ROWID POWERDEMAND_TAB DOMAIN INDEX POWERINDEX 3 rows selected. Statement processed. Echo ON SQLPLUS> SQLPLUS> SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, 2> P.Sample.MinCellDemand 3> FROM PowerDemand_Tab P 4> WHERE Power_GreaterThanAny(P.Sample,50) = 1; REGION SAMPLE.TOT SAMPLE.MAX SAMPLE.MIN ---------- ---------- ---------- ---------- 1 90 55 5 1 89 56 3 1 88 55 3 1 87 54 3 1 86 54 3 5 rows selected. ODCIIndexStart>>>>> ODCIIndexInfo Index owner : POWERCARTUSER Index name : POWERINDEX Table owner : POWERCARTUSER Table name : POWERDEMAND_TAB Indexed column : "SAMPLE" Indexed column type :POWERDEMAND_TYP Indexed column type schema:POWERCARTUSER ODCIPredInfo Object owner : POWERCARTUSER Object name : POWER_GREATERTHANANY Method name : Predicate bounds flag : Exact Match Include Start Key Include Stop Key start key : 1 stop key : 1 compare value : 50 ODCIIndexStart>>>>>select distinct r from POWERCARTUSER.POWERINDEX_pidx where cv al >'50' ODCIIndexFetch>>>>> Nrows : 2000 ODCIIndexClose>>>>> SQLPLUS> SQLPLUS> explain plan for 2> SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, 3> P.Sample.MinCellDemand 4> FROM PowerDemand_Tab P 5> WHERE Power_LessThanAny(P.Sample,50) = 0; Statement processed. SQLPLUS> @tkoqxpll SQLPLUS> set echo off Echo OFF Charwidth 15 OPERATIONS OPTIONS OBJECT_NAME --------------- --------------- --------------- SELECT STATEMEN TABLE ACCESS BY ROWID POWERDEMAND_TAB DOMAIN INDEX POWERINDEX 3 rows selected. Statement processed. Echo ON SQLPLUS> SQLPLUS> SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, 2> P.Sample.MinCellDemand 3> FROM PowerDemand_Tab P 4> WHERE Power_LessThanAny(P.Sample,50) = 0; REGION SAMPLE.TOT SAMPLE.MAX SAMPLE.MIN ---------- ---------- ---------- ---------- 0 rows selected. ODCIIndexStart>>>>> ODCIIndexInfo Index owner : POWERCARTUSER Index name : POWERINDEX Table owner : POWERCARTUSER Table name : POWERDEMAND_TAB Indexed column : "SAMPLE" Indexed column type :POWERDEMAND_TYP Indexed column type schema:POWERCARTUSER ODCIPredInfo Object owner : POWERCARTUSER Object name : POWER_LESSTHANANY Method name : Predicate bounds flag : Exact Match Include Start Key Include Stop Key start key : 0 stop key : 0 compare value : 50 ODCIIndexStart>>>>>select distinct r from POWERCARTUSER.POWERINDEX_pidx minus se lect distinct r from POWERCARTUSER.POWERINDEX_pidx where cval <'50' ODCIIndexFetch>>>>> Nrows : 2000 ODCIIndexClose>>>>>