索引を作成すれば高速になるとは限らない
索引があれば表の全ブロック走査よりも短時間で1つのデータを特定できることがわかりました。では、索引で行データの特定が高速になるなら、すべての列に索引を作成しておけばよいのでしょうか? 立ち止まって考えてみましょう。
索引は、表にすでに格納されている行データの位置を特定するために有効なデータ構造ですが、データベースはデータを検索するだけではありません。データの更新があります。行データを追加・更新する場合、表のデータ構造だけでなく該当する列の索引のデータ構造も更新する必要があります。SQLのUPDATEは指定された列のみを更新しますが、INSERTとDELETEはすべての列を更新することに注意してください。表に作成されている索引の個数が多いほど更新性能が低下します。
また、オンライン系で発生した個別の取引のデータを集計するような処理を考えてみましょう。集計や分析のような処理ではかなり多くの行データにアクセスします。索引ブロックを経由してデータの実体である表ブロックにアクセスする行数がわずかであれば速いのですが、該当件数が多いと、いつか表ブロックを全走査するよりも索引ブロックにアクセスした分だけ処理量が多くなります。また、メモリ上であったとしても索引ブロックから表ブロックへのランダム・アクセスを繰り返すよりも表ブロックを連続で走査する方が高速です。そのため、表データのかなり多くの割合にアクセスすることになる分析や集計処理では、索引アクセスではなく表ブロックを全走査するSQL実行計画が選択される場合があります。
第1回のSQL実行モデルの解説で、最適なアルゴリズムであるSQL実行計画の生成のために表の統計情報を収集しておくと説明しました。これは重要で、クエリーの検索条件が表のどれくらいの割合のデータに合致するかの判断には、事前に表のデータの値の分布を収集しておく必要があるためです。
索引を作成する判断
索引は、クエリーが指定した検索条件に合致するデータが全データのうちとても少ない割合(選択率が小さい)である場合に効果が高いデータ構造です。管理者が索引の作成を検討する場合、索引を作成する列はクエリーの選択率が小さい列が候補になります。この判断には業務を十分理解しデータの分布やアプリケーションの検索の特性を知っている必要があります。
最近は、人が行っていたこの過程を自動化するDBMSが登場しています。第1回でSQL実行計画はメモリ上にキャッシュされており、また、表の値の分布の統計情報も取得されていると説明しました。SQL実行計画のデータへのアクセス・パスと表の統計情報から選択率を推定し、索引を作成したほうが処理時間を短縮できるかの推定を行います。Oracle DatabaseではTuning Pack機能で索引作成候補の提示を行います。また、Automatic Indexing機能では索引作成まで自動化します。
まとめ
索引はデータの値とそのポインタを組で持つデータ構造で、その値のデータが格納されている位置を短時間で特定することができます。しかし、データを更新すると索引も更新する必要があるため、索引が多いほど更新性能が低下します。
索引経由のデータ・アクセスは1データを特定することは局所的最適解として高速に実行可能ですが、必ずしも大域的最適解としての最速であるとは限りません。クエリーによっては表の全ブロック走査の方が高速になる場合があります。
では、分析や集計処理のように多数のデータにアクセスする場合に、アクセスするブロック数を減らす方法はないでしょうか。それはパーティショニングというデータ構造です。次回はパーティショニングについて見ていきましょう。
