6. パーサ
• SQL文の構文を解析して、文字列が正しい構文になっているかをチェック
• 構文が正しくなければエラーを返す
• 構文が正しければパースツリーの形に変換
• テーブル名やカラム名が実在するかは問わないので「ローパースツリー」
とも呼ばれる
SELECT oid FROM pg_proc WHERE oid = 1;
SELECT
TargetList
oid
RelationList
pg_proc
Qualifier
Expression
=
oid 1 6
8. アナライザ
• パースツリーをもとにどのような表や関数、演算子が参照されるか
を判断して、クエリツリーを作成する
• この時DBにテーブルが存在するかチェックし、存在したらテーブル名
をOIDに変換する
SELECT oid FROM pg_proc WHERE oid = 1;
SELECT
TargetList
oid
RelationList
pg_proc
Qualifier
Expression
=
oid 1
カタログ
oidに変更8
35. Seq Scanのコスト計算
Seq Scanのコスト= (DISK I/Oコスト)+(CPUコスト)
=(テーブル全ページ数×Seq_page_cost)
+(テーブル全行数×cpu_tuple_cost )
+(テーブル全行数×cpu_operator_cost)
35
=# EXPLAIN SELECT oid FROM pg_proc WHERE oid = 1;
QUERY PLAN
--------------------------------------------------
Seq Scan on pg_proc
(cost=0.00..92.12 rows=1 width=4)
Filter: (oid = 1::oid)
=# SELECT relpages,reltuples FROM pg_class
WHERE relname = 'pg_proc';
relpages | reltuples
----------+-----------
61 | 2490
総コスト
= (61×1.0) + (2490×0.01)
+ (2490×0.0025)
= 92.125
テーブル全行数
テーブル全ページ数
規定値0.0025
36. -----------------------------------------------------
Index Scan using pg_proc_oid_index on pg_proc
36
Index Scan 演算子
=# EXPLAIN SELECT oid FROM pg_proc WHERE oid=1;
QUERY PLAN
(cost=0.00..5.99 rows=1 width=4)
Index Cond: (oid = 1::oid)
• 特に大きなテーブルではコストが低くなるので選ば
れる可能性が高い
• Index Condが無い場合は、ソートの代わりとして使
われるインデックス順のフルスキャンを表す
37. 37
Index Scan について
• 検索条件に合致するインデックスがあれば検討する。
• 通常は対象行が少なければこちらが選択される。
• インデックスとテーブルを交互にアクセスする。
id列のインデックステーブル
id = 1
id = 11
id = 34
id = 45
・・・
1 11 45 100
検索条件に合う
リーフノードを探索
必要な行に
ランダムアクセス
Index Scan のコスト
= インデックスI/Oコスト+ テーブルI/Oコスト
+ インデックスCPUコスト+ テーブルCPUコスト
インデックスI/Oコスト
= 必要ページ数×sequential_page_cost(1)
テーブルI/Oコスト
= 必要行数×(1~4) ※
インデックスCPUコスト
= 必要行数×cpu_index_tuple_cost(0.005)
テーブルCPUコスト
= 必要行数×cpu_tuple_cost(0.01)
※
アクセスページがメモリサイズ
(effective_cache_size)の
何倍かでアクセスコストは変化
41. Index Only Scan
• 9.2で追加された
• 取得したい値にインデックスが含まれるとき、テーブ
ルのアクセスを省略して検索する
• 非常に高速(しかしindex only scanが選ばれるには
条件が…)
41
42. Index Only Scanのスキャン方法
• Index Only ScanはまずインデックスからVisibility
Mapを参照しに行く(早速テーブルには行かない)
• そして高速に値を返せるか返せないかは、実はこの
Visibility Mapにかかっている
→このVisibility Mapって一体何者なの?
42
44. Visibility Mapのbitが0だと
• テーブルにアクセスすることなくタプルの値を返す
44
SELECT id FROM table1 WHERE id BETWEEN 1 AND 11
ブロック
1
2
3
4
…
全タプル有効!
インデックス
1 11 34 45
テーブル
テーブルにアクセスしない
45. Visibility Mapのbitが1だと
• タプルの値が返せるものか判断するために通常の
テーブルアクセスを行う
無効タプルあり!
45
SELECT id FROM table1 WHERE id BETWEEN 1 AND 11
ブロック
1
2
3
4 1 11 34 45
…
インデックス
テーブル
1
本当に値返していいの?
テーブルにアクセスしよう
47. ------------------------------------------------------
Tid Scan on pg_proc (cost=0.00..4.01 rows=1 width=4)
47
Tid Scan 演算子
=# EXPLAIN SELECT oid FROM pg_proc WHERE ctid
='(0,1)';
QUERY PLAN
Filter: (ctid = '(0,1)'::tid)
• カラムタプルID
• “ctid=”がクエリに指定された場合のみ使われる
• 滅多に使わない、非常に速い
48. 処理を補助する演算子
48
分類演算子
テーブルスキャンSeq Scan
Index Scan
Bitmap Scan
Index Only Scan
Tid Scan
その他スキャンFunction Scan
テーブルの結合Nested Loop
Merge Join
Hash Join
分類演算子
検索結果に対して
作用
limit
Unique
Aggregate
Group Aggregate
Result
結果の結合Append
SetOp
その他の処理を補
助
Sort
49. 49
Sort 演算子
=# EXPLAIN SELECT oid FROM pg_proc ORDER BY oid;
QUERY PLAN
---------------------------------------------
Sort (cost=181.55..185.92 rows=1747 width=4)
Sort Key: oid
-> Seq Scan on pg_proc
(cost=0.00..87.47 rows=1747 width=4)
• 明示的なソート: ORDER BY句
• 暗黙的なソート: Unique, Sort-Merge Join など
• 開始コストを持っている: 最初の値はすぐには返却
されない
55. Merge Join 演算子
# EXPLAIN SELECT * FROM pgbench_accounts AS a,
pgbench_tellers AS t where a.aid = t.tid;
QUERY PLAN
---------------------------------------------------------------
Merge Join (cost=5.94..11.25 rows=100 width=449)
Merge Cond: (a.aid = t.tid)
-> Index Scan using pgbench_accounts_pkey on pgbench_accounts a
(cost=0.42..39669.43 rows=1000000 width=97)
-> Sort (cost=5.32..5.57 rows=100 width=352)
Sort Key: t.tid
-> Seq Scan on pgbench_tellers t
(cost=0.00..2.00 rows=100 width=352)
• 二つのデータセットをJOINする:outerとinner
• Merge Right JoinとMerge In Joinがある
• データセットはあらかじめソートされていなければならず、また両方同
時に走査される。
55
64. =# EXPLAIN SELECT count(*) FROM pg_proc GROUP BY oid;
-----------------------------------------------------
GroupAggregate (cost=0.28..108.15 rows=2529 width=4)
64
GroupAggregate 演算子
QUERY PLAN
-> Index Only Scan using pg_proc_oid_index on
pg_proc (cost=0.28..70.22 rows=2529 width=4)
• GROUP BYを使用し、より大きな結果セット上に集
約を行う
65. 65
Result 演算子
=# EXPLAIN SELECT 1 + 1 ;
QUERY PLAN
------------------------------------------
Result (cost=0.00..0.01 rows=1 width=0)
• 非テーブル問い合わせ
• テーブルを参照せずに結果が得られる場合
66. 結果を結合する演算子
66
分類演算子
テーブルスキャンSeq Scan
Index Scan
Bitmap Scan
Index Only Scan
Tid Scan
その他スキャンFunction Scan
テーブルの結合Nested Loop
Merge Join
Hash Join
分類演算子
検索結果に対して
作用
limit
Unique
Aggregate
Group Aggregate
Result
結果の結合Append
SetOp
その他の処理を補
助
Sort
67. 67
Append 演算子
=# EXPLAIN SELECT oid FROM pg_proc
UNION ALL SELECT oid ORDER BY pg_proc;
QUERY PLAN
--------------------------------------------------------------
Append (cost=0.00..209.88 rows=3494 width=4)
-> Seq Scan on pg_proc (cost=0.00..87.47 rows=1747 width=4)
-> Seq Scan on pg_proc (cost=0.00..87.47 rows=1747 width=4)
• UNION (ALL) によるトリガー, 継承
• 開始コスト無し
• コストは単に全ての入力の合計
68. =# EXPLAIN SELECT oid FROM pg_proc INTERSECT SELECT oid FROM pg_proc;
-----------------------------------------------------------------------
SetOp Intersect (cost=415.51..432.98 rows=349 width=4)
-> Subquery Scan "*SELECT* 1" (cost=0.00..104.94 rows=1747)
-> Subquery Scan "*SELECT* 2" (cost=0.00..104.94 rows=1747)
68
SetOp 演算子
QUERY PLAN
-> Sort (cost=415.51..424.25 rows=3494 width=4)
Sort Key: oid
-> Append (cost=0.00..209.88 rows=3494 width=4)
-> Seq Scan on pg_proc (cost=0.00..87.47 rows=1747)
-> Seq Scan on pg_proc (cost=0.00..87.47 rows=1747)
• INTERSECT, INTERSECT ALL, EXCEPT, EXCEPT ALL句
のために使用される
– SetOp Intersect, Intersect All, Except, Except All