SQL 問い合わせ計画 (SQL query plan)
【概要】
SQL問い合わせ計画は,SQL問い合わせ(クエリ)がどのように実行されるかを示す計画で,SQL文の前に「EXPLAIN」を付けると表示される.SQLite 3では,オペコードと呼ばれるSQLite 3の仮想マシンが実行する基本命令の列である.主要なオペコードには,OpenRead(テーブル読み取り用のカーソル作成),Rewind(カーソルをテーブル先頭に位置づけ),Column(レコードの列データ取得),ResultRow(結果行の出力)などがある.カーソルはテーブル内の特定の位置を指し示すポインタで,オペコードによって操作され,テーブル内の行を順に処理するために使用される.条件付きジャンプはWHERE句の条件処理などに使用されるオペコードの機能で,レジスタの値を比較し,条件が満たされると指定されたアドレスにジャンプする.例えば「Ne 1 15 2」はレジスタ1と2の値が等しくないときにアドレス15へジャンプする.
【目次】
- 1. 演習で行うこと
- 2. SQLite 3 の主要なオペコード
- 3. 既存のデータベースを開く
- 4. テーブル定義と一貫性制約の記述
- 5. テーブルへの行の挿入
- 6. テーブル一覧とデータベーススキーマの確認
- 7. データのブラウズ
- 8. 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)です.
1. 演習で行うこと
- SQL 問い合わせ計画 (SQL Query Plan) の表示.
2. SQLite 3 の主要なオペコード
SQL 文の前に「explain」を付けると,SQL は実行されずに,SQL 問い合わせ計画が表示される.問い合わせ計画とは,SQLite 3 の場合,仮想のデータベースマシンが実行する命令列である.
【SQLite 3 の主要なオペコード (Opcode) の要点】
- OpenRead:ルート・ページが P2 であるようなテーブルのカーソルを作る.P1 にはカーソル番号を設定する.P4 には,テーブルの列数を設定するか,KeyInfo 構造体へのポインタを設定する.
- Rewind:将来の Column, Rowid, Next 命令の実行に備えて,カーソル P1 をテーブルの先頭を指し示すようにする.テーブルが空の場合には,アドレス P2 にジャンプする.
- Column:カーソル P1 が指し示すレコードの P2 番目の列からデータを取り出して,レジスタ P3 に格納する(列番号は 0 から始まる).
- Rowid:カーソル P1 が指し示すレコードの主キーの値を,レジスタ P2 に格納する.
- ResultRow:レジスタ P1 から レジスタ (P1+P2-1) までの値を1行として出力する.
- Ne:レジスタ P1 の値とレジスタ P3 の値が等しくないときに限り,アドレス P2 にジャンプする.
- Next:カーソル P1 が指し示すレコードが末端レコードならば,次の命令に進む.末端レコードでなければ,カーソル P1 を1つ進めて,アドレス P2 にジャンプする.
- Goto:アドレス P2 にジャンプする.
3. 既存のデータベースを開く
作成済みのデータベースを,下記の手順で開く.
- ツールバーの「DBオープン (Ctrl+O)」ボタンをクリックする.
- データベースファイルを開く
* Ubuntu での実行例(「/home/ubuntuuser/mydb」を開く場合).データベースファイル /home/ubuntuuser/mydb を選ぶ.
* Windows での実行例(「C:\SQLite\mydb」を開く場合).データベースファイル C:\SQLite\mydb を選び,「開く」をクリックする.
4. テーブル定義と一貫性制約の記述
以前の授業で定義した scores テーブルを使う.scores テーブルのテーブル定義が残っている場合には,この操作は不要である.残っていない場合には,次の手順で定義する.
SQL を用いて,scores テーブルを定義し,一貫性制約を記述する.
リレーショナル・スキーマ (relational schema):scores( name, teacher_name, student_name, score )
- scores テーブルの定義
次の SQL を入力し,「▶ SQL実行 (F5)」を押下する.
create table scores ( id integer primary key autoincrement not null, name text not null, teacher_name text not null, student_name text not null, score integer not null check ( score >= 0 and score <= 100 ), created_at datetime not null, updated_at datetime, unique (name, student_name) );* 「SQLエディタ」欄には,SQL プログラムを書くことができる.
- 出力欄の確認
「出力」欄にエラーメッセージが表示されていないことを確認する.
5. テーブルへの行の挿入
以前の授業で定義した scores テーブルを使う.scores テーブルが残っている場合には,この操作は不要である.残っていない場合には,次の手順で作成する.
次のような scores テーブルを作る.
以下の手順で,SQL を用いて scores テーブルへの行の挿入を行う.
- SQL プログラムの記述
「insert into ...」は行の挿入である.ここには 5つの SQL 文を書き,「begin transaction」と「commit」で囲む.
begin transaction; insert into scores values( 1, 'Database', 'K', 'KK', 85, datetime('now', 'localtime'), NULL ); insert into scores values( 2, 'Database', 'K', 'AA', 75, datetime('now', 'localtime'), NULL ); insert into scores values( 3, 'Database', 'K', 'LL', 90, datetime('now', 'localtime'), NULL ); insert into scores values( 4, 'Programming', 'A', 'KK', 85, datetime('now', 'localtime'), NULL ); insert into scores values( 5, 'Programming', 'A', 'LL', 75, datetime('now', 'localtime'), NULL ); commit;
- 複数の SQL 文の一括実行
「SQLエディタ」に記述した複数の SQL 文をまとめて実行するには,「▶ SQL実行 (F5)」を押下する.
- 「出力」欄の確認
エラーメッセージが出ていないことを確認する.
6. テーブル一覧とデータベーススキーマの確認
- 「スキーマナビゲータ」にテーブルの一覧が表示されるので確認する.
- 「SQLエディタ」に「select * from sqlite_master;」と入力し,「▶ SQL実行 (F5)」を押下すると,「出力」欄にデータベーススキーマが表示されるので,scores の行を確認する.
* 「2」の部分は別の数値になっている場合がある.これは,scores テーブルのデータが置かれるページ番号に関する情報 (rootpage) であり,SQLite 3 システムが自動で決める値である.
7. データのブラウズ
- 「スキーマナビゲータ」の一覧から scores テーブルを選択する.
- 「テーブル定義ビューワ」に scores テーブルの CREATE 文が,「出力」欄にデータが表示される.
* データに間違いがあれば,このウインドウで修正できる.
8. SQL 問い合わせ計画の表示
データベース管理システムは,SQL 文をコンパイルし,SQL 問い合わせ計画を作る.SQL 問い合わせ計画とは,データベースに関する基本的なオペレータの並びである.
* テーブルの全ての行の表示
- SQL の問い合わせの発行と評価結果の確認
まずは scores テーブルを使った簡単な SQL を試す.「SQLエディタ」に次の SQL を入力し,「▶ SQL実行 (F5)」を押下する.
select * from scores;「出力」欄で評価結果を確認する.
- 問い合わせ計画の表示
「SQLエディタ」に上記の SQL 文を記述したまま,ツールバーの「実行計画解析 (F6)」を押下する.「出力」のテキスト欄に,問い合わせ計画(オペコードの並び)と,その解説が表示される.
【表示された問い合わせ計画の要点】
| アドレス (addr) | オペコード | 主なオペランド | |
| 2 | OpenRead | P2 = 2 | ルート・ページが 2 であるようなテーブル(この場合は,テーブル scores)のカーソルを作る. |
| 3 | Rewind | P2 = 13 | カーソルを,テーブルの先頭を指し示すようにする.テーブルが空の場合には,アドレス 13(Close)にジャンプする. |
| 5, 6, 7, 8, 9, 10 | Column | P2 = 1,2,3,4,5,6, P3 = 2,3,4,5,6,7 | 列番号 1,2,3,4,5,6 の値を,それぞれレジスタ 2,3,4,5,6,7 に格納する. |
| 11 | ResultRow | P1 = 1, P2 = 7 | レジスタ 1 からレジスタ 7 までの値を1行として出力する. |
| 12 | Next | P2 = 4 | カーソルが指し示すレコードが末端レコードならば,次の命令に進む.末端レコードでなければ,カーソルを1つ進めて,アドレス 4 にジャンプする. |
二次索引については,今後の授業で学ぶ.二次索引がないとき,テーブルの本体が1行ずつ処理される.テーブルの全ての行について処理が繰り返される(このことを「tuple at a time」ともいう).
* 条件を満足する行のみの表示
- SQL の問い合わせの発行と評価結果の確認
「SQLエディタ」に次の SQL を入力し,「▶ SQL実行 (F5)」を押下する.「出力」欄で評価結果を確認する.
select * from scores where student_name = 'KK'; - 問い合わせ計画の表示
SQL 文の前に「EXPLAIN」を付ける.次の SQL を「SQLエディタ」に入力し,「▶ SQL実行 (F5)」を押下すると,「出力」欄に問い合わせ計画(オペコードの並び)が表示される.
explain select * from scores where student_name = 'KK';アドレス 6 の「Ne 1 15 2 collseq(BINARY) 69」は「条件付きジャンプ」である.最初,カーソルは先頭行にセットされる.この条件付きジャンプは,SQL で指定された「student_name = 'KK'」の処理を行うためのもので,条件を満たさない行の場合には,結果を得るプログラムの部分(ここでは7行目から11行目まで)をジャンプする.これにより,条件を満たす行だけが評価結果に追加される.その後,カーソルは次の行へ動く.このようにして,scores テーブルの全ての行が精査される.