3.3 論理設計の手順(2/4)

できるエンジニアになるためのちょい上DB術/第2章 概念設計

3.3 論理設計の手順(2/4)

索引を使うとなぜパフォーマンスが良くなるのか

1.次のようなSQL文による問い合わせが実行されると……
  SELECT ename,job,deptno
  FROM employee
  WHERE ename='SCOTT'; ←条件で行を選択

2.索引がなければ、表の行データを含むすべてのブロックがメモリに読み込まれ、該当の行が探索される(図3-3)

3.索引があって使用される場合、索引を使って行が存在するブロックを特定し、該当ブロックのみがメモリに読み込まれる(図3-4)

索引を使うと常に速い?

索引がある場合とない場合の処理の違いを確認しました。
索引を使用すると常に最も速い検索ができるわけではないことがわかったと思います。
違いを、以下にもう少し解説します。

2.と3.を比較して、アクセスするブロック数が少ない方が、パフォーマンスはよさそうであることがわかるでしょう。
実際には、発生する物理Ⅰ/0数、メモリ上でアクセスするブロック数が少ないほどパフォーマンスはよいということができます。

各種DBでは、SQL文をチェックした後、最適なアクセスパスを選択するため、オプティマイザと呼ばれる機能を使って複数のアクセスパスを比較し、最適な解を導き出します。
DB設計者は、このアクセスパスの選択肢を適切なものにできるよう、適切な種類のインデックスや表を作成する必要があります。
その指針として、次のような点が挙げられます。

  • 1,SQL文のWHERE条件句で使用される列で、対象となる行を絞り込むために使用される列に索引を作成する
  • 2,1.において、WHERE条件旬で対象となる行の絞り込みが有効な列(一意性が高い、カーディナリティが高いという)に
    索引を作成する
  • 3,一意性を高くするために、列を組み合わせた複合列に索引を作る

一方、小さい表をアクセスする場合は索引を使用しない場合がほとんどです。
Oracleでは、パフォーマンスをよくするために、「表全体を読み込む」というアクセスパスが選択された場合、複数のブロックをまとめて1回のIOで読み込む「マルチブロック読み込み」を行います。
ディスクから読み込みを行う場合、1回のIOで複数のブロックをまとめて読み込むことができます。
初期化パラメータ(db_file_multiblock_read_count)で設定します。
デフォルトは8ブロックです。

  • 索引を使用したときは1ブロック単位の読み込み
  • 全表検索を選択したときはマルチブロック読み込み

索引を使用しても、アクセスするブロック数(索引+表)が多ければ、かえって全表検索の方が効率がよい場合もあります。
したがって、下記のようなケースはB*tree索引は有効ではないということができます。

  • 小さい表を検索する場合
  • 一意性が高くないため、たくさんの行がヒットする(アクセスするブロック数が増える)場合

索引作成の目的

索引を作成する目的としては、これまでに紹介した検索処理の高速化を含め、次の2つを挙げることができます。

  • 1.検索処理の高速化
  • 2.データの一意性を保証データの一意性を保証

データの一意性を保証するために、Oracleデータベースは、列または列の組み合わせ(複数列)に対して、Primary Key制約またはUnique制約をつけると、自動的に一意索引を作成します。
そして、DML文(INSERTまたはUPDATE)が発行されると、索引を使用して、「挿入または更新後の列借」と「既存の索引のソートされた列値」が比較され、同じ値がないかどうかを高速に確認できるようになっています。
列値がソートされていないと、値を比較する際に、最初から最後まで検索する必要があり、検索に時間がかかることになります。

B*treeインデックスの特徴

B*treeインデックスの特徴から、どのように使用すべきかをまとめます。

  • where句の条件式で頻繁に使用される列または列の組み合わせに作成する
  • 一意性が高い列または列の組み合わせに有効
    等価条件が最も有効ということができるが、範囲検索でも指定した値の一意性が高ければ効果的
  • 小さい表では使用されない
  • not検索、null値権索、or条件を多用するような検索では使用されない
  • sort対象の列、結合列に作成すると有効
  • 更新によって、索引の構造が崩れてしまうと効率が悪くなる

一意性を高くするために

1列のみでは一意性が高くない場合でも、複数列を組み合わせると一意性が高くなる場合、複数列の組み合わせで索引を作成することを検討します。

一般的に、条件検索の値を指定した場合に、該当する検索対象の行が表全体の行の2%〜4%未満になる場合、その列に索引を作成するのは有効だといわれます。
一方、5%以上15%未満になる場合は、テストしてみます。
特に、SELECT句で問い合わされている列が索引の一部に組み込まれていて、値を取得するのに表へのアクセスが必要ない場合、パフォーマンスは非常に良くなります。
同じ表の複数列に索引を別々に作成していた場合、1つの複合索引にできないかを検討してみましょう。

ただし、複合索引を作成する場合、索引に指定する列の順序がパフォーマンスに影響を与えるので、その点は十分考慮してください。

条件式の記述を誤ると索引を使わない

せっかく索引を作成しても、SQL文の書き方が誤っていると、オプティマイザは索引を使うことができません。
次の点に注意してください(ただし、各DBのバージョンによっては下記のように記述しても索引を使う場合もあるので確認が必要です)。
WHERE条件文中で、以下のように、列に対する条件式が記述されている場合、その列に作成された索引は使用されません。

  • 列名!=値
  • 関数(列名)=値 (例)UPPER(列名)='SUZUKl'(*)
  • 列名LIKE'%値' 文字列検索で中間一致または後方一致)
(*)Oracle9iでは関数つきの列に索引を作成できるようになっています。

このケースと同様、複合索引を作成する際、複合索引の一番初めに指定される列が検索条件に指定されないと、複合索引も使用されません。
この理由から、複合索引を作成する場合、一番先に指定される列は、条件式に指定される確率が最も高いものを選択する必要があります。
指定される確率が同じ場合には、一意性の高い列を先頭にもってきます。(*)

(*)Oracle9iでは中間一致・後方一致も索引を使用できるようになっていますがパフォーマンスはよくありません。
  • 列で定義されたデータ型!=指定された値のデータ型

< 前へ | 3.3 論理設計の手順(2/4) | 次へ >

解説トレーナー

Oracle / 上流工程 担当 中村 才千代

データベース設計、システム構築の上流~下流工程全般のインストラクターです。SE時代の経験を生かし「業務を知るエンジニアこそDB設計に関わるべき」「DB設計に携わるエンジニアは業務を知る人に知恵を貸してもらう」ことを伝えたいと思っています。

■認定・受賞

2000年 Oracle University「Best Instructor of the Year」受賞
2002年 Oracle University「Best Instructor of the Year」受賞

Page Top