前回に引き続き,効果のないBツリー・インデックスを説明します。この特集で使用しているサンプルの[顧客]テーブル(表1)を基にします。表1には30レコードありますが,このテーブルのレコードが削除され,10レコードになったとします(表2)。この10レコードのテーブルで,次のSQL文を考えて見ましょう。

表1●[顧客]テーブルのカラム値
表1●[顧客]テーブルのカラム値
[画像のクリックで拡大表示]
表2●[顧客]テーブルのカラム値
表2●[顧客]テーブルのカラム値
[画像のクリックで拡大表示]

SELECT 顧客名 FROM 顧客 WHERE 顧客番号 = 1030
意味:[顧客番号]の値が1030である[顧客名]を抽出

 [顧客番号]カラムで検索していますので,[顧客番号]カラムにBツリー・インデックスを付けたとします。この特集では3レコードを1ブロックに格納するとしていますので,レコードを格納するブロック数は4になります注1

 このSQL文を処理する場合,インデックスを使わない処理手続きと使う処理手続きが考えられます。インデックスを使わない処理手続きは,

<手続き1> ([顧客]テーブルの全レコードに当たる)4ブロックをデータ・バッファに読み込み,[顧客番号]の値を判定して該当レコードを抽出

 となります。図1と併せて見てください。注目するディスク・アクセス回数は4回です。


図1●インデックスを使わない処理手続き
図1●インデックスを使わない処理手続き

 一方の,インデックスを使う処理手続きは,

<手続き2> Bツリー・インデックスのルート,ブランチ,リーフを,それぞれデータ・バッファに読み込む。リーフのポインタからレコードのブロックを読み込み,該当レコードを抽出

 となります。図2と併せて見てください。注目すべきディスク・アクセス回数は4回です。手続き1と手続き2のディスク・アクセス回数は同じになります。どちらが実行プランとして選ばれるかは分かりませんが,はっきりしているのは,インデックスの効果はなかったということです。

図2●インデックスを使う処理手続き
図2●インデックスを使う処理手続き

 効果が得られなかった理由は,インデックスそのものにあるわけではありません。もうお気付きだと思いますが,レコード数が少なければブロック数が少なく,レコード・ブロックをすべて読み込んでも大した回数にはなりません。Bツリー・インデックスでピンポイントに該当ブロックを特定できたとしても,インデックス・ブロックを読み込むディスク・アクセス回数(この例では3回)が必要になるので,合計のディスク・アクセス回数を減らせません。

 ここで知っておきたいことは,「実行プランを自動生成するオプティマイザは,正確なディスク・アクセス回数を把握していない」ということです。コスト・ベースのオプティマイザは,統計情報を基に処理手続きごとのコスト(手続きの良しあしを数値化したもの)を算出し,その値の小さいものを最適と判断します。ですが一般に,統計情報にはレコード数の情報は含まれません。含まれるのは,インデックスの有無,インデックスの種類,カラム値の最大値/最小値――などです。

 これらの情報だけでは,全レコードを読み込む場合であっても,ディスク・アクセス回数が何回になるかは分かりません。Bツリー・インデックスもレコード数によってはブランチが複数の層になることがあり,正確なディスク・アクセス回数をつかむことはできません。オプティマイザは“最適”と判断できる処理手続きを推測するしかなく,結果的に判断を間違うこともまれにあります。だからこそ,どのような処理手続きが最適なのかを把握し,RDBMSが判断した実行プランがその通りになっているかどうかをチェックすることは重要なのです。

 今回はBツリー・インデックスのマイナス面をまとめました。次回は,二つのテーブルをジョインするSQL文について説明します

監修:藤塚 勤也(ふじづか きんや) NTTデータ 基盤システム事業本部 オープンソース開発センタ 技術開発担当 シニアスペシャリスト
沖電気工業,タンデムコンピューターズ(現日本HP)を経て,2003年より株式会社 NTTデータに勤務。現在は,オープンソース・ソフトウエアを活用したエンタープライズ・システム向けの技術開発・技術支援に従事しており,特にシステムの中核であるRDBMSに注力している。「RDBMS解剖学」(翔泳社)を共著