|
注意: 式の索引付けを使用できるのは、Oracle Database Enterprise Editionのみです。 |
式を格納する列に索引を定義すると、データ項目に対する評価がTRUEとなる式をすばやく検索できます。この索引付けが最も役立つのは、データ項目について大きい式セットが評価される場合です。SQLのEVALUATE演算子では、索引を使用するかどうかがアクセス・コストに基づいて決定されます。索引の作成とメンテナンスには、索引タイプEXFSYS.EXPFILTERが使用されます。
Expression列に索引が付いていない場合、SQLのEVALUATE演算子はその列に格納されている式ごとに動的問合せを作成し、データ項目として渡された値を使用して実行します。
この章では、索引表現(第12.3項)、索引処理(第12.4項)および索引の作成とチューニングに使用するユーザー・コマンド(第12.6項)など、基本的な索引付け方法について説明します。
大きい式セットに含まれる式は、それぞれの述語に一定の共通性があります。式セットに対して定義される式フィルタ索引により、述語が共通性別にグループ化されて処理コストが削減されます。たとえば、Year=1998とYear=1999のように共通の左辺を持つ2つの述語があると、ほとんどの場合、一方の述語がFALSEであるかTRUEであるかは、他方の述語の結果に基づいて判断できます。述語の左辺には、HORSEPOWER(model, year)のように、1つ以上の要素属性とユーザー定義関数を含む算術式が含まれます。HORSEPOWER(model, year)>=150のように、右辺(RHS)の演算子と定数により述語が完成します。
式セットに対して定義された式フィルタ索引は、複数の述語を左辺の共通性に基づいてグループ化することで、各述語間の論理的関係を利用します。これらの左辺は、HORSEPOWER(model,year)のように、1つ以上の要素属性とユーザー定義関数からなる算術式です。
式フィルタの索引付けメカニズムで索引付けできる述語には、右辺に定数を持つ述語が含まれ、次の述語演算子のいずれかを使用します。=、!=、>、<、>=、<=、BETWEEN、IS NULL、IS NOT NULL、LIKEおよびNVLです。
索引付けできない述語は元の形式に保たれ、式の評価の最終段階で値を置換することにより評価されます。次のような述語には索引付けできません。
右辺に変数を持つ述語。
INリスト述語。
ワイルドカード文字で始まるLIKE述語。
同じ左辺を持つ式の中で重複する述語。ほとんどの場合、Year>1995とYear<2000のように重複する左辺を持つ2つの述語は、索引がBETWEEN演算子に対して構成されていれば索引付けできます。BETWEEN演算子を含む述語は、単項演算子を含む2つの述語として扱われます。一方は'>='演算子を含む述語、他方は'<='演算子を含む述語です。BETWEEN演算子の詳細は、「EXF$INDEXOPER」を参照してください。
式フィルタ索引では、永続的なデータベース・オブジェクトを内部的に使用して式セットの索引情報がメンテナンスされます。式セットに含まれるすべての述語のグループ情報は、述語表と呼ばれるリレーショナル表で取得されます。通常、述語表には式セット内の式ごとに1行が含まれます。ただし、1つ以上の選言(ORで結合された2つの単純な式)を含む式は選言標準形(論理積の選言)に変換され、この標準形による各選言は元の式と同じ識別子を持つ別個の式として扱われます。述語表には、このような選言ごとに1行が含まれます。
式フィルタ索引は、式セットに含まれる述語のうち最も共通性の高い左辺(または特異な述語グループ)を識別することにより、チューニングしてパフォーマンスを改善できます。式セット(または式を格納する表)の所有者は、述語の左辺を識別するか、または式セットの統計を収集することでこの処理を自動化できます。共通する左辺ごとに、式セット内で対応するすべての述語を使用して述語グループが形成されます。たとえば、式セット内でModel、PriceおよびHorsePower(Model, Year)属性を持つ述語が共通している場合は、この3つの属性について3つの述語グループが形成されます。述語表では、図12-1に示すように述語グループ情報が取得されます。
述語表には述語グループごとに2つの列があります。一方の列には述語の演算子が格納され、他方の列には述語の右辺の定数が格納されます。式内の述語の場合は、演算子と右辺の定数が述語グループの対応する列の下に格納されます。事前構成済グループのいずれにも該当しない述語は元の形式に保たれ、述語表のVARCHAR2列にまばらな述語として格納されます。(図12-1の例では、MileageおよびYearの述語がこのカテゴリに該当します。)INリストを持つ述語および(定数ではなく)可変の右辺を持つ述語は、暗黙的にまばらな述語として扱われます。ネイティブの索引は、第12.4項のように述語表に対して作成されます。
式セットに対してデータ項目を評価するために、データ項目にある各述語グループの左辺が計算され、適切な演算子を使用して、その値が述語表に格納された対応する定数と比較されます。たとえば、述語表を使用すると、HORSEPOWER('TAURUS',2001)が153を戻す場合、この値を満たす述語は、対象馬力153または対象馬力153未満の値以上などとなります。前述のグループの演算子と右辺の定数が述語表(図12-1)のG3_OP列とG3_RHS列に格納されている場合、この述語表に対する次の問合せでは、この述語グループを満たす行が識別されます。
SELECT Rid FROM predicate_table WHERE
G3_OP = '=' AND G3_RHS = :rhs_val or
G3_OP = '>' AND G3_RHS < :rhs_val or
...
-- where :rhs_val is the value from the computation of the left-hand side --
式フィルタでは、より小さい(<)、以上(>=)、以下(<=)、等しくない(!=、<>)、LIKE、IS NULLおよびIS NOT NULLの各述語に同様のテクニックが使用されます。BETWEEN演算子を持つ述語は、以上演算子と以下演算子を持つ2つの述語に分割されます。Year >= 1996やYear <= 2000など、1つの式に頻繁に2回以上使用される場合は、左辺に重複する述語グループを構成できます。
WHERE句(前述の問合せを参照)は述語表内の述語グループごとに繰り返され、述語グループはすべて論理積で結合されます。述語表に対して完全な問合せ(次の例を参照)を発行すると、事前構成済グループ内のすべての述語でTRUEに評価される式のROWIDが戻されます。このような結果となる式の場合、述語表に格納された対応するまばらな述語が動的問合せを使用して評価され、式が特定のデータ項目についてTRUEであるかどうかが判別されます。
SELECT Rid, Sparse_predicate FROM predicate_table
WHERE --- predicates in group 1
(G1_OP IS NULL OR --- no predicate involving this LHS
((:g1_val IS NOT NULL AND
(G1_OP = '=' AND G1_RHS = :g1_val or
G1_OP = '>' AND G1_RHS < :g1_val or
G1_OP = '<' AND G1_RHS > :g1_val or
...) or
(:g1_val IS NULL AND G1_OP = 'IS NULL')))
AND --- predicates in group 2
(G2_OP IS NULL OR
((:g2_val IS NOT NULL AND
(G2_OP = '=' AND G2_RHS = :g2_val or
G2_OP = '>' AND G2_RHS < :g2_val or
G2_OP = '<' AND G2_RHS > :g2_val or
...) or
(:g2_val IS NULL AND G2_OP = 'IS NULL')))
AND
...
述語表の問合せ(前述)を効率的に実行するために、選択されたグループの{Operator, RHS constant}列に対して連結ビットマップ索引が作成されます。これらのグループは、ユーザー指定により識別されるか、式セット内で(グループに属する)述語の頻度に関する統計に基づいて識別されます。事前構成済の述語グループに定義されている索引を使用して、式セットからの述語が次の3つのクラスに分割されます。
索引付き述語: 最も特異であるとして識別された事前構成済の述語グループのサブセットに属している述語です。これらの述語グループにはビットマップ索引が作成されるため、これらの述語を索引付き述語とも呼びます。前述の問合せでは、対応する索引のレンジ・スキャンが実行され、グループ内の述語がすべて評価されて、その述語でのみTRUEに評価される式が戻されます。他の索引付き述語のビットマップ索引にも同様のスキャンが実行され、索引スキャンの結果がBITMAP AND操作を使用して結合され、すべての索引付き述語でTRUEに評価される式がすべて判別されます。これにより、1つ以上のビットマップ索引を使用して同時に複数の述語グループをフィルタできます。
ストアド述語: 索引付けされていないグループに属する述語です。この種の述語は、述語表のうち対応する{Operator, RHS constant}列で取得され、ビットマップ索引は定義されません。前述の問合せでは、索引付き述語でTRUEに評価されるすべての式について、これらの述語グループの左辺の値が述語表に格納されている値と比較されます。選択された数のグループに対するビットマップ索引は作成されますが、オプティマイザではアクセス・コストに基づいて1つ以上の索引を使用しないように選択される場合があります。これらのグループは、ストアド述語グループとして扱われます。述語表に対して発行された問合せは、異なる索引を選択できるようにそのまま残ります。
まばらな述語: 事前構成済のどの述語グループにも属さない述語です。索引付きグループとストアド・グループの全述語についてTRUEに評価される式の場合、まばらな述語は(存在する場合は)最後に評価されます。まばらな述語を持つ式がTRUEに評価される場合、その式はデータ項目についてTRUEとみなされます。
オプションで、左辺で述語とともに使用する共通演算子を指定して、ビットマップ索引に対して実行されるレンジ・スキャン数を減らすことができます。詳細は、「EXF$INDEXOPER」を参照してください。前述の例では、Model属性が等価性述語に共通して使用されており、式フィルタ索引は索引付き述語グループの処理中に等価性述語のみをチェックするように構成できます。まばらな述語は、Model属性の他の形式の述語とともに同時に処理および評価されます。
式セットの述語グループが決定されると、述語表の構造と述語表に対して発行される問合せが固定になります。索引付き述語グループまたはストアド述語グループが選択されても、問合せは変化しません。式フィルタ索引の作成中に述語表の問合せが決定され、この問合せ用の関数が動的に生成されます。式セットの評価用に渡されるデータ項目には、すべて同じ問合せ(バインド変数付き)が使用されます。これにより、確実に述語表の問合せが1度コンパイルされ、必要な数のデータ項目を評価するために再利用されます。
式セットに含まれる述語の評価コストは、その述語が属しているグループに応じて異なります。式セットの索引は、適切な述語グループを索引パラメータとして識別することでチューニングできます。
索引付き述語グループに含まれる述語は、次の手順で評価されます。
述語グループの左辺が1度計算されます。
計算された値を使用してビットマップ索引のレンジ・スキャンが1度以上実行されます。
ストアド述語グループに含まれる述語は、次の手順で評価されます。
述語グループの左辺が1度計算されます。
計算された値が、作業セットに(索引付き述語に基づいてフィルタされた後に)残っているすべての述語の演算子および右辺の定数と比較されます。
まばらな述語グループに含まれる述語は、次の手順で評価されます。
作業セットに残っているすべての式について、まばらな述語を表す副次式が解析されます。
データ値の置換(動的問合せを使用)を介して副次式が評価されます。
スキーマ内では1つの属性セットを1つ以上の式セットに使用でき、デフォルトの索引パラメータを属性セットに関連付けて、これらの式セット用に述語グループを構成できます。共通する左辺と予測データの選択性を知ることで(特異な)述語グループを選択できます。
次のコマンドでは、DBMS_EXPFIL.DEFAULT_INDEX_PARAMETERSプロシージャを使用し、Car4Sale属性セットを指定してデフォルトの索引パラメータを構成しています。
BEGIN
DBMS_EXPFIL.DEFAULT_INDEX_PARAMETERS('Car4Sale',
exf$attribute_list (
exf$attribute (attr_name => 'Model', --- LHS for predicate group
attr_oper => exf$indexoper('='),
attr_indexed => 'TRUE'), --- indexed predicate group
exf$attribute (attr_name => 'Price',
attr_oper => exf$indexoper('all'),
attr_indexed => 'TRUE'),
exf$attribute (attr_name => 'HorsePower(Model, Year)',
attr_oper => exf$indexoper('=','<','>','>=','<='),
attr_indexed => 'FALSE') --- stored predicate group
)
);
END;
/
CREATE INDEX InterestIndex ON Consumer (Interest)
INDEXTYPE IS EXFSYS.EXPFILTER;
索引は、すべてのパラメータを対応する属性セットに関連付けられているデフォルト(Model、PriceおよびHorsePower(Model, Year))から導出します。デフォルトが指定されていない場合は、属性セット内のすべてのスカラー要素属性(Model、Year、PriceおよびMileage)をストアド属性および索引付き属性として暗黙的に使用します。
索引の作成時にPARAMETERS句を使用するか、索引パラメータを式セットに直接関連付けて、式セットごとに属性セットから導出されるデフォルト・パラメータを詳細にチューニングできます。次のCREATE INDEX文ではPARAMETERS句が指定されており、追加のストアド述語を使用して索引が構成されます。
CREATE INDEX InterestIndex ON Consumer (Interest)
INDEXTYPE IS exfsys.ExpFilter
PARAMETERS ('ADD TO DEFAULTS STOREATTRS (CrashTestRating(Model, Year))');
デフォルト・パラメータから索引を作成する方法の詳細は、「DEFAULT_INDEX_PARAMETERSプロシージャ」および第16章の「CREATE INDEX」を参照してください。
共通属性セットに関連付けられている各式セットの索引パラメータの詳細なチューニングが必要な場合は、DBMS_EXPFIL.INDEX_PARAMETERSプロシージャを使用して式セットに完全索引パラメータを直接割り当てることができます。
次のコマンドでは、索引パラメータがデフォルト・パラメータからコピーされ、指定の式セットにあわせて詳細にチューニングされます。式セット用に作成された式フィルタ索引では、これらのパラメータを使用して索引付き述語グループとストアド述語グループが構成されます。
BEGIN
-- Derive index parameters from defaults --
DBMS_EXPFIL.INDEX_PARAMETERS(expr_tab => 'Consumer',
expr_col => 'Interest',
attr_list => null,
operation => 'DEFAULT');
-- Fine-tune the parameters by adding another stored attribute --
DBMS_EXPFIL.INDEX_PARAMETERS(expr_tab => 'Consumer',
expr_col => 'Interest',
attr_list =>
exf$attribute_list (
exf$attribute (
attr_name => 'CrashTestRating(Model, Year)',
attr_oper => exf$indexoper('all'),
attr_indexed => 'FALSE')),
operation => 'ADD');
END;
/
CREATE INDEX InterestIndex ON Consumer (Interest)
INDEXTYPE IS EXFSYS.EXPFILTER;
完全パラメータから索引を作成する方法の詳細は、「INDEX_PARAMETERSプロシージャ」および第16章の「CREATE INDEX」を参照してください。
XPath述語を使用した式の索引付けについては、第13章を参照してください。
典型的な式セットがすでに表に格納されている場合、表の所有者はDBMS_EXPFIL.GET_EXPRSET_STATSプロシージャを使用して式セットの統計を収集し、これらの統計から索引を作成して、索引チューニング処理を自動化できます。次に例を示します。
BEGIN
DBMS_EXPFIL.GET_EXPRSET_STATS (expr_tab => 'Consumer',
expr_col => 'Interest');
END;
/
CREATE INDEX InterestIndex ON Consumer (Interest)
INDEXTYPE IS EXFSYS.EXPFILTER
PARAMETERS ('STOREATTRS TOP 4 INDEXATTRS TOP 2');
前述の索引では、式セット内で対応する述語左辺の頻度に基づいて4つのストアド属性が選択され、その中から上位2つが索引付き属性として選択されます。TOP n句を使用すると、対応する属性セットに関連付けられているデフォルトは無視されます。索引用に選択された属性は、USER_EXPFIL_PREDTAB_ATTRIBUTESビューを問い合せて表示できます。
統計から索引を作成する方法の詳細は、「GET_EXPRSET_STATSプロシージャ」および第16章の「CREATE INDEX」を参照してください。
Expression列でSQLのEVALUATE演算子を使用する問合せでは、この種の列に定義されている索引をオプティマイザ・ヒントと併用させることができます。(『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照。)それ以外の場合、オプティマイザでは式フィルタ索引ベース・スキャンのコストが判別され、代替実行計画のコストと比較されます。
SELECT * FROM Consumer WHERE
EVALUATE (Consumer.Interest,
Car4Sale.getVarchar('Mustang',2000,18000,22000)) = 1 and
Consumer.Zipcode BETWEEN 03060 and 03070;
前述の問合せでは、Consumer表のInterest列に式フィルタ索引が定義されており、Zipcode列にネイティブ索引が定義されていると、オプティマイザではそれぞれの選択性とアクセス・コストに基づいて適切な索引が選択されます。10g リリース2以降、式フィルタ索引の選択性とコストは、Expression列、索引または式の格納表で統計を収集したときに計算されます。これらの統計は、式フィルタ・ディクショナリに格納され、EVALUATE演算子を使用した問合せに対する最適な実行計画(オプション)の決定に使用されます。
EXPLAIN PLAN文を使用すると、オプティマイザで問合せに式フィルタ索引が選択されたかどうかを確認できます。
式フィルタ索引では、永続的なデータベース・オブジェクトを使用して式を格納する列の索引がメンテナンスされます。これらのセカンダリ・オブジェクトはすべて、式フィルタ索引が作成されるスキーマ内に作成されます。式フィルタ索引ごとに3タイプのセカンダリ・オブジェクトがあり、次のネーミング規則が使用されます。
従来型の表(述語表): EXF$PTAB_n
述語表の1つ以上の索引: EXF$PTAB_n_IDX_m
アクセス関数パッケージと呼ばれるパッケージ: EXF$AFUN_n
式の評価が確実に有効になるように、Expression列を持つ表とExpression列の式フィルタ索引は同じスキーマに属している必要があります。表に対してCREATE INDEX権限を持つユーザーが式フィルタ索引を作成できるのは、表の所有者である場合のみです。デフォルトでは、述語表はユーザーのデフォルト表領域に作成されます。PREDSTORAGEパラメータ句を使用すると、索引の作成時に述語表に対する代替STORAGE句を指定できます。(第16章の「CREATE INDEX」文を参照。)述語表の索引は、常にその表と同じ表領域に作成されます。
Expression列に対して作成された式フィルタ索引は、式に対する(SQLのINSERT、UPDATE、DELETE文またはSQL*Loaderによる)変更を反映するように自動的にメンテナンスされます。述語表に定義されたビットマップ索引は、多数の式が変更されたり式セットに追加または削除されると断片化される場合があります。このような索引は、次の例に示すようにDBMS_EXPFIL.DEFRAG_INDEXプロシージャを使用してオンラインで再作成し、断片化を減少させることができます。
BEGIN DBMS_EXPFIL.DEFRAG_INDEX (idx_name => 'InterestIndex'); END; /
このプロシージャの詳細は、「DEFRAG_INDEXプロシージャ」を参照してください。
ALTER INDEX...REBUILD文を使用すると、式フィルタ索引全体をオフラインで再作成できます。この方法は、表のメンテナンス操作後に索引にUNUSABLEマークが設定される場合に役立ちます。属性セットに関連付けられているデフォルトの索引パラメータに変更があった場合は、DEFAULTパラメータ句を指定してALTER INDEX...REBUILD文を使用すると、変更内容を既存の索引に取り込むことができます。第16章の「ALTER INDEX REBUILD」文を参照してください。