二次索引の基礎

概要

データベース処理の性能向上には、二次索引と問い合わせ計画の理解が重要である。二次索引は主索引のキー以外の属性に対して作成される索引で、検索処理を高速化する。一つのテーブルに対して任意の数の二次索引を作成でき、「CREATE INDEX <索引名> ON <テーブル名> (<列名の並び>)」という形式のSQL文で二次索引を作成する。例えば「CREATE INDEX idx1 ON point3(x)」はpoint3テーブルのx列に対する二次索引idx1を作成する。また、SQL文の前に「EXPLAIN」を付けて実行することでSQL問い合わせ計画を確認でき、SQLite 3の問い合わせ計画はOpenRead、Rewind、Column、Nextなどのオペコードから構成される。二次索引によるデータベース処理の性能向上は、問い合わせ計画で確認できる。

リレーショナルデータベースの基礎であるテーブル定義、一貫性制約、SQL、結合と分解、トランザクション、埋め込みSQL、実行計画、二次索引を学ぶ。SQLite 3 を用いて、SQL についての演習も行う。

目次

関連する外部ページ

SQLite 3 のオペコードの説明は https://www.sqlite.org/opcode.html にある。 SQLite 3 の SQL の説明は https://www.sqlite.org/lang.html にある。

サイト内の関連ページ

公開資料は クリエイティブコモンズ 表示-非営利-継承 4.0 国際ライセンス(CC BY-NC-SA 4.0) で提供しており,事前の許可なく自由に利用できます.条件は著作者表示(BY),非営利目的のみ(NC),同一ライセンスでの再配布(SA)です.











索引の基礎

SQLite 3 の主要なオペコード (opcode)

SQLite Manager Tool で既存のデータベースを開く

すでに作成済みのデータベースを、下記の手順で開く。

  1. ツールバーの「DBオープン (Ctrl+O)」ボタンをクリックする。
  2. データベースファイルを開く

    Ubuntu での実行例(「/home/ubuntuuser/mydb」を開く場合)

    データベースファイル /home/ubuntuuser/mydb を選び、「開く」をクリックする。

    Windows での実行例(「C:\SQLite\mydb」を開く場合)

    データベースファイル C:\SQLite\mydb を選び、「開く」をクリックする。

SQL を用いたテーブル定義と一貫性制約の記述

SQL を用いて、point3 テーブルを定義し、一貫性制約を記述する。

リレーショナル・スキーマ (relational schema): point3(id, x, y, z, created_at)
  1. point3 テーブルの定義

    次の SQL を入力し、「▶ SQL実行 (F5)」を押下する。

    create table point3 (
        id          integer  primary key autoincrement not null,
        x           real not null,
        y           real not null,
        z           real not null,
        created_at  datetime not null );
    

    「SQLエディタ」欄には、SQL プログラムを書くことができる。

  2. 出力欄の確認

    「出力」欄にエラーメッセージが表示されていないことを確認する。

SQL を用いたテーブルへの行の挿入

先に定義した point3 テーブルを使う。下記の操作により、演習用のデータ(1000行)を point3 テーブルに格納する。

  1. 演習用データ(1000行分のCSVファイル)を用意する。
  2. ツールバーの「CSV読込」ボタンをクリックするか、「SQLエディタ」に次のドットコマンドを記述し、「▶ SQL実行 (F5)」を押下する。

    x の値、y の値、z の値は、あらかじめ乱数で生成しておいたCSVファイルの値を使用する。

    .import "point3.csv" "point3"
    
  3. 確認

    「出力」欄にエラーメッセージが表示されていないことを確認する。

  4. 読込完了のメッセージを確認する。

データベースの構造の確認

  1. 「SQLエディタ」に「SELECT * FROM sqlite_master;」と入力し、「▶ SQL実行 (F5)」を押下する。
  2. 「出力」欄にデータベーススキーマが表示されるので、テーブル point3 のルート・ページ番号を確認する。

    この資料の実行例では、point3 テーブルのルート・ページ (root page) 番号は 12 になっている。ルート・ページ番号は SQLite 3 が決める値である。ルート・ページ番号が 12 以外の値になっていても問題はない。

この資料では、point3 テーブルのルート・ページは 12 になっているものとして説明を続ける。

SQLite Manager Tool を用いた SQL 問い合わせ計画の表示

単一テーブルに対する問い合わせの SQL 問い合わせ計画の表示例

ここでは、条件を満たす行のみを表示する SQL の問い合わせ計画の表示例を示す。

データベース管理システムは、SQL 文をコンパイルし、問い合わせ計画を作る。問い合わせ計画とは、データベースに関する基本的なオペレータの並びである。

SQLite Manager Tool を用いた二次索引の追加

ここでは、テーブル point3 の属性 x の二次索引を作る。

  1. CREATE INDEX を用いた二次索引の生成

    「SQLエディタ」に次の SQL を入力し、「▶ SQL実行 (F5)」を押下する。

    CREATE INDEX idx1 ON point3( x );
    

    「idx1」は索引名である。索引の管理(索引の削除など)に使用される。

    索引は数秒以内で生成される。

  2. 出力欄の確認

    「出力」欄にエラーメッセージが表示されていないことを確認する。

  3. SQLite Manager Tool での二次索引の確認

    下の図のように、「スキーマナビゲータ」でテーブル point3 の索引一覧に idx1 ができていることを確認する。

二次索引による問い合わせ計画の変化

データベースの構造の確認

  1. 「SQLエディタ」に「SELECT * FROM sqlite_master;」と入力し、「▶ SQL実行 (F5)」を押下する。
  2. テーブル point3 と二次索引 idx1 のルート・ページ番号が分かる。
    二次索引 idx1 のルート・ページ番号(上の図では「46」)を確認しておく。ルート・ページ番号はデータベース管理システムが決める値なので、違う値になっているはずである。

SQL 問い合わせ計画の表示

  1. 先ほどと同じ SQL 問い合わせを評価させる。「SQLエディタ」に SQL 文を記述したまま、ツールバーの「実行計画解析 (F6)」を押下する。
    SELECT * FROM point3 WHERE x < 1000000000;
    
【問い合わせ計画の要点】

上の図から、二次索引が使われていることが確認できる。

二次索引は事前に作成済みである。二次索引は多数の索引エントリから構成され、個々の索引エントリは元のテーブルの各行に対応する。最初、カーソル番号1のカーソルは二次索引の先頭にセットされる。次に、「x < 1000000000」という条件式を満たす行の索引エントリが、二次索引の中から検索される。この処理は高速である。その後、カーソルを使ってテーブル point3 の該当する行を取り出す。「x < 1000000000」を満たすすべての行を取り出し終えたら、処理を終える。

二次索引がないときは、テーブルの本体が一行ずつ処理される。テーブルのすべての行について処理が繰り返される(このことを「tuple at a time」ともいう)。

二次索引を使うときは、テーブルの本体が一行ずつすべて処理されるわけではない。このことで、データベース処理がより高速になることが期待できる。

【表示された問い合わせ計画の要点】

アドレス (addr) オペコード 主なオペランド  
1 Integer P1 = 1000000000, P2 = 1 レジスタ 1 に、値 1000000000 をセットする
3 OpenRead P1 = 0, P2 = 12 ルート・ページが 12 であるようなテーブル(テーブル point3)のカーソルを作る。カーソル番号は 0
4 OpenRead P1 = 1, P2 = 46 ルート・ページが 46 であるような二次索引(idx1)のカーソルを別に作る。カーソル番号は 1
6 Rewind P1 = 1, P2 = 23 P1 = 1 なので、カーソル番号1のカーソルを使う。カーソルを、二次索引 idx1 の先頭を指し示すようにする。二次索引が空の場合には、アドレス 23(「Close」の行)にジャンプする
7 IdxGE P1 = 1, P2 = 23 P1 = 1 なので、カーソル番号1のカーソルを使う。検索キーの値(この場合はレジスタ1に入っている「1000000000」)と、カーソルが指し示している索引エントリを比較する。索引エントリが検索キー以上のときは、アドレス 23 にジャンプする
11 から 12 Seek など 二次索引を使って、テーブルのカーソル(カーソル0)を該当する行に動かす
14 から 20 Column など id, x, y, z, created_at の値を、それぞれレジスタ 4, 5, 6, 7, 8 に格納する
21 ResultRow P1 = 4, P2 = 5 レジスタ 4 からレジスタ 8 までの値(レジスタの個数は、P2 に指定した 5 個)を一行として出力する
22 Next P1 = 1, P2 = 8 P1 = 1 なので、カーソル番号1のカーソルを使う。カーソルが指し示す索引エントリが末端ならば、次の命令に進む。末端でなければ、カーソルを一つ進めて、アドレス 8 にジャンプする

演習