TimesTenおよびTimesTen Cacheはコスト・ベースの問合せオプティマイザを備えています。オプティマイザは、最適な方法を自動的に検索して問合せに応答することで、効率的なデータ・アクセスを保証します。最適化はコンパイル・プロセスの第3段階目で行われます。図5-1に、コンパイルの段階を示します。
オプティマイザの役割は、問合せの実行に対して最も低コストの計画を判断することです。最も低コストの計画とは、データへの到達時間が最短となるアクセス・パスを意味します。複数の実行計画が可能な場合、TimesTenによってSQL文用のオプティマイザが起動されます。オプティマイザは、最適と判断した計画を選択します。この計画は、文がアプリケーションによって無効にされるか削除されるまで保持されます。
オプティマイザでは、次の情報に基づいて計画のコストを判断します。
表と列の統計情報
メタデータ情報(参照整合性、主キーなど)
索引の選択(一時索引の自動作成を含む)
スキャン方法(全表スキャン、ROWID参照、範囲索引スキャン、ビットマップ索引参照、ハッシュ索引参照)
結合アルゴリズムの選択(ネステッド・ループ結合、索引付きネステッド・ループ結合、マージ結合)
この章の内容は次のとおりです。
オプティマイザは、適切な時間とメモリー制約内で実現可能な最高の計画の生成を目的に設計されています。すべての問合せに対して最適な計画を常に選択するオプティマイザは存在しませ。オプティマイザの目的は、計画の検索領域内で最も有効な可能性が高い領域を検出する方法を使用して、生成された一連の計画から最適な計画を選択することです。最適化は通常、問合せごとに1回のみであるのに対して、問合せ自体は何度も実行されることがあるため、オプティマイザは最適化時間よりも実行時間を優先するように設計されています。
オプティマイザの生成する計画では、メモリーの使用よりパフォーマンスが重視されます。オプティマイザによって、実行を高速化するために、大量の一時メモリー空間を使用するように指示される可能性があります。メモリー制約のある環境では、「オプティマイザ・ヒント」で説明するオプティマイザ・ヒントをアプリケーションで使用して、一時索引と一時表の使用を禁止し、パフォーマンスを最大化せずにメモリーの使用を節約する計画を作成することもできます。
問合せの実行パスを判断する際に、オプティマイザは表の行数などの問合せで参照されるデータ、条件で使用される列の間隔の統計における最小値、最大値および一意の値の数、表内の主キーの有無、既存の索引のサイズと構成などに関する統計を調べます。これらの統計は、アプリケーションがttIsql
statsupdate
コマンド、ttOptUpdateStats
またはttOptEstimateStats
組込みプロシージャを呼び出したときに移入されるSYS.TBL_STATS
およびSYS.COL_STATS
表に格納されます。
オプティマイザは各表の統計を使用して、t1.a=4
のような条件、またはt1.a=4 AND t1.b<10
のような条件の組合せの選択性を計算します。選択性とは、表に含まれる行数を測定したものです。割合の小さい行を選択する条件は選択性が高く、割合の大きい行を選択する条件は選択性が低いと言えます。
ヒントを適用して、TimesTen問合せオプティマイザに指示を渡すことができます。問合せに対して最適な実行計画を選択するとき、オプティマイザではこれらのヒントが考慮されます。次のようにヒントを適用できます。
特定のSQL文のみにヒントを適用するには、文レベルのオプティマイザ・ヒントを使用します。
トランザクション全体にヒントを適用するには、適切なTimesTen組込みプロシージャとともにトランザクション・レベルのオプティマイザ・ヒントを使用します。
問合せオプティマイザは、索引を使用して問合せの実行を高速化します。オプティマイザは、既存の索引を使用するか、一時索引を作成して、実行計画を生成します。索引とは、表の行の位置を示すキーのマップです。TimesTenシステムから最大のパフォーマンスを引き出すには、索引を戦略的に使用することが必須になります。
TimesTenでは、次のタイプの索引を使用します。
ハッシュ索引: ハッシュ索引は、1つ以上の列で完全一致する行を検索する場合に有効です。範囲索引は、一意の索引または一意でない索引として指定できます。通常、完全一致参照と等価結合については、ハッシュ索引の方が範囲索引より高速です。ただし、範囲またはキーの接頭辞を含む参照ではハッシュ索引を使用できません。また、ハッシュ索引では範囲索引およびビットマップ索引より多くの領域が必要になる可能性があります。
範囲索引: 範囲索引は、列の値が等価または非等価として指定された範囲内にある行を検出する場合に有効です。範囲索引は、表の1つ以上の列にわたって作成できます。範囲索引は、一意の索引または一意でない索引として指定できます。CREATE INDEX
SQL文を使用して索引を作成する際に索引タイプを指定しないと、範囲索引が作成されます。
ビットマップ索引: ビットマップ索引では、行内の一意の値に関する情報がビットマップにエンコードされます。ビットマップの各ビットが表の行に対応します。ビットマップ索引は、一意の値がそれほど多くない列に使用します。このような列の例として、性別を2つの値のいずれかとして記録する列があげられます。ビットマップ索引は、データ・ウェアハウス環境で広く使用されています。この環境では、通常、データおよび非定型の問合せは大量にありますが、同時DMLトランザクションは低いレベルです。ビットマップ索引は圧縮され、必要な記憶域が他の索引付けテクニックよりも少なくなります。
索引アドバイザ・ツールを使用して、特定のSQLワークロードのパフォーマンスを向上できる一連の索引を推奨できます。詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』の索引アドバイザを使用した索引の推奨に関する説明を参照してください。
オプティマイザは複数のタイプのスキャン方法から選択できます。最も一般的なスキャン方法は次のとおりです。
全表スキャン
ROWID参照
範囲索引スキャン(永続索引または一時索引のいずれか)
ハッシュ索引参照(永続索引または一時索引のいずれか)
ビットマップ索引参照(永続索引)
TimesTenおよびTimesTen Cacheでは、ハッシュ索引、ビットマップ索引およびROWID参照を介して高速に完全一致処理が実行されます。また、範囲索引を介して範囲一致処理が実行されます。問合せ計画の選択時にオプティマイザによる特定のスキャン方法についての検討を実行可能または実行不可にするには、オプティマイザ・ヒントを使用します。
全表スキャンでは、表内のすべての行が調べられます。全体スキャンは、問合せ条件を評価する最も非効率的な方法であるため、他の方法を使用できない場合にのみ使用されます。
TimesTenでは、表に保存される各行にROWIDという名前の一意IDを割り当てます。たとえば、アプリケーションで以前にROWIDを選択し、次にWHERE ROWID=
句を使用して同じ行をフェッチする場合に、ROWID参照が適用可能です。ROWID参照は索引参照より高速です。
範囲索引スキャンでは、範囲索引を使用して表にアクセスします。このようなスキャンは、条件に使用する列に範囲索引が定義されている場合にのみ、t1.a=2
などの完全一致条件またはt1.a>2
やt1.a<10
などの範囲条件に適用できます。範囲索引が複数の列にわたって定義されている場合は、複数の列条件にその範囲索引を使用できます。たとえば、列t1.b
およびt1.c
に範囲索引が定義されている場合、条件t1.b=100
およびt1.c>'ABC'
は範囲索引スキャンになります。索引は、複数の列にわたって定義されている場合でも使用できます。たとえば、t1.b
、t1.c
およびt1.d
に範囲索引が定義されている場合、オプティマイザでは、列b
およびc
の索引の接頭辞を使用し、列b
およびc
に指定された条件に一致する列d
のすべての値が返されます。
ハッシュ索引参照では、ハッシュ索引を使用して1つ以上の列で完全一致する行が検出されます。このような参照は、指定した1つ以上の列における等価検索に適用されます。
ビットマップ索引参照では、ビットマップ索引を使用して、customer.gender='male'
などの等価条件を満たす行が検出されます。ビットマップ索引は、一意の値がほとんどない列に適しています。特に、それぞれがビットマップ索引参照を使用できる複数の条件を評価する場合に有効です。これは、組み合せられた条件が、索引自体に対するビット演算を介して効率的に評価できるためです。たとえば、表customer
で列gender
にビットマップ索引が定義され、表sweater
で列color
にビットマップ索引が定義されている場合、条件customer.gender='male'
およびsweater.color='pink'
を指定すると、この2つのビットマップ索引に対して論理積
演算が実行され、ピンクのセーターを購入したすべての男性客が迅速に検出されます。
オプティマイザは複数の結合方法のいずれかを選択できます。2つの表の行を結合する場合は、一方の表を外部表、他方の表を内部表に指定します。オプティマイザは、どちらの表を外部表にしてどちらを内部表にするかを決定します。結合中に、オプティマイザは外部表と内部表の行をスキャンして、結合条件に一致する行を検索します。
オプティマイザは各表の統計を分析します。たとえば、オプティマイザは、最小の表、または問合せについて最高の選択性を持つ表を外部表として識別します。結合する1つ以上の表に索引が存在する場合、オプティマイザでは外部表と内部表を選択する際にそれらを考慮します。
3つ以上の表を結合する場合、オプティマイザは表のペアについて様々な結合の組合せを分析し、最初に結合するペア、次にその結合の結果によって結合する表など、最適な結合の順序を判断します。
結合のコストは、内部表と外部表にアクセスして、結合条件に一致する行を検索する方法に大きく影響されます。オプティマイザは、問合せオプティマイザ計画を決定する際に2つの結合方法から選択します。
索引のないネステッド・ループ結合では、外部表の行が一度に1行ずつ選択され、内部表のすべての行と一致するか確認されます。内部表のすべての行が、外部表の行数と同じ回数スキャンされます。内部表の結合列に索引がある場合、その索引は結合条件を満たす行の選択に使用されます。各表から結合条件を満たす行が返されます。処理中に、索引がネステッド・ループの内部表に対して作成され、内部スキャンの結果が結合の前にマテリアライズされる可能性があります。
図5-2に、ネステッド・ループ結合の例を示します。結条件は次のとおりです。
WHERE t1.a=t2.a
この例では、オプティマイザはt1
が外部表、t2
が内部表と決定しています。表t2
内の列a
の値と一致している表t1
内の列a
の値は1および7です。結合の結果、t1
およびt2
の行が連結されます。たとえば、最初の結合結果は次の行になります。
7 50 43.54 21 13.69
次のt1
の行が連結されます。
7 50 43.54
列a
の値が一致しているt2
の最初の行を次に示します。
7 21 13.69
マージ結合は、結合列が範囲索引でソートされる場合にのみ使用されます。マージ結合では、カーソルが各索引を一度に1行ずつ進みます。行はすでに各索引の結合列でソートされているため、簡単な式を適用することにより、単一のスキャンでカーソルが各行を効率的に進みます。式は次のようになります。
内部.結合列 < 外部.結合列の場合、内部カーソルを進める
内部.結合列 = 外部.結合列の場合、一致を読み取る
内部.結合列 > 外部.結合列の場合、外部カーソルを進める
ネステッド・ループ結合と異なり、外部表の各行について内部表全体をスキャンする必要はありません。マージ結合が使用できるのは、問合せを準備する前に表に範囲索引が作成されている場合です。問合せを準備する前に、結合する表に範囲索引が存在しない場合、状況によっては、オプティマイザがマージ結合を使用するために、一時範囲索引を作成する可能性もあります。
図5-3に、マージ結合の例を示します。結条件は次のとおりです。
WHERE t1.a=t2.a
x1
は、表t1
の索引を列a
でソートしたものです。x2
は、表t2
の索引を列a
でソートしたものです。マージ結合の結果、x1
の行は、列a
の値が一致するx2
の行と連結されます。たとえば、最初のマージ結合の結果は次のようになります。たとえば、最初のマージ結合の結果は次のようになります。
1 20 23.09 20 43.59
次のx1
の行が連結されます。
1 20 23.09
列a
の値が一致しているx2
の最初の行を次に示します。
1 20 43.59
多くのデータベース・オプティマイザと同様に、問合せオプティマイザは最も効率的なSQL処理方法の詳細を問合せ実行計画に保存し、アプリケーション開発者と管理者は、これを確認してカスタマイズできます。
実行計画のデータは、TimesTenのSYS.PLAN
表に保存され、アクセスする表とその順序、結合する表、使用する索引に関する情報を含みます。ttSqlCmdQueryPlan
組込みプロシージャまたはttIsql
explain
コマンドのいずれかを使用して、最近実行されたSQL文の問合せ計画を表示できます。ユーザーは計画生成オプティマイザ・ヒントを使用して、SYS.PLAN
表での実行計画の作成を有効または無効にするように問合せオプティマイザに指示できます。(トランザクション・レベルのヒントの場合は、ttOptSetFlag
組込みプロシージャでGenPlan
オプティマイザ・フラグを使用し、文レベルのヒントの場合は、SQL文でTT_GenPlan
ヒントを使用します。)
実行計画は、実行するデータベース処理ごとに個別の手順を指定して、問合せを実行します。計画内の手順は複数のレベルに編成されます。レベルでは、次のレベルの1つ以上の手順で必要となる結果を生成するために完了する必要がある手順を指定します。
次の問合せについて考えてみます。
SELECT COUNT(*) FROM t1, t2, t3 WHERE t3.b/t1.b > 1 AND t2.b <> 0 AND t1.a = -t2.a AND t2.a = t3.a;
この例では、図5-4に示すように、オプティマイザは問合せを個別の操作に分解し、3つのレベルで実行される5つの手順を生成します。