SlideShare a Scribd company logo
1 of 88
PostgreSQLクエリ実行の基礎知識 
~Explainを読み解こう~ 
第30回(仮名)PostgreSQL勉強会 
2014年10月11日 
TIS株式会社下雅意美紀 
1
自己紹介 
• 氏名下雅意美紀 
• 所属TIS株式会社 
• 経歴入社1年目 
• PostgreSQL歴= 入社歴 
• 業務で勉強する以外にも、前回のJPUGのしくみ分科会にも 
参加したり(http://thinkit.co.jp/story/2014/07/01/5074)、 
PGEConsにも参加したりとコミュニティ活動なども通して日々 
PostgreSQLの勉強をしています。 
2
PostgreSQLクエリ実行の基礎知識 
~Explainを読み解こう~ 
アジェンダ 
・PostgreSQLのクエリ実行の概要 
・Explain実行結果(問い合わせプラン)の読み方 
・Explain演算子の種類 
・問い合わせプランを変更させる 
・実際のデバック例 
3 
目標 
クエリチューニングで使用するExlpainコマンドが出力する実行 
計画を読めるようになりましょう。 
PostgreSQLがクエリ実行時に内部でどのような処理を行ってい 
るかを知りましょう。
クエリの実行 
そもそもクエリはどのようにPostgreSQL内部で実 
行されているのか 
4
PostgreSQLのクエリ処理のフロー 
DBにテーブルがあるか確認 
クエリの書き換え 
プランを実行 
5
パーサ 
• クエリの構文を解析して、文字列が正しい構文になっているかをチェック 
• 構文が正しくなければエラーを返す 
• 構文が正しければパースツリーの形に変換 
• テーブル名やカラム名が実在するかは問わないので「ローパースツリー」 
とも呼ばれる 
SELECT oid FROM pg_proc WHERE oid = 1; 
SELECT 
TargetList 
oid 
RelationList 
pg_proc 
Qualifier 
Expression 
= 
oid 1 6
PostgreSQLのクエリ処理のフロー 
クエリの書き換え 
プランを実行 
7 
DBにテーブルがあるか確認
アナライザ 
• パースツリーをもとにどのような表や関数、演算子が参照されるか 
を判断して、クエリツリーを作成する 
• この時DBにテーブルが存在するかチェックし、存在したらテーブル名 
をOIDに変換する 
SELECT oid FROM pg_proc WHERE oid = 1; 
SELECT 
TargetList 
oid 
RelationList 
pg_proc 
Qualifier 
Expression 
= 
oid 1 
カタログ 
oidに変更8
PostgreSQLのクエリ処理のフロー 
DBにテーブルがあるか確認 
クエリの書き換え 
プランを実行 
9
リライタ 
• PostgreSQLではVIEWやRULEはクエリを書き換えることで実行 
している 
• このような書き換えの処理をリライタという 
10
PostgreSQLのクエリ処理のフロー 
DBにテーブルがあるか確認 
クエリの書き換え 
プランを実行 
11
プランナ 
• クエリツリーを解析して、実際に問い合わせを実行するための問い 
合わせプランを求める 
• 問い合わせの実行コストを見積もり、最小コストのものを問い合わ 
せプランとする(問い合わせの最適化) 
• コスト計算のための最小単位はパス 
• パスは各処理によって種類がある 
• ここで作成された問い合わせプランはあくまで推定されたもの 
クエリツリー 
パス単位でコスト計算 
最小コストのものを問い合わせプランに 
パスの種類 
・全件スキャン 
・インデックスを使ってスキャン 
・テーブル結合 
など 
12
問い合わせプランとは 
・問い合わせプランとは、問い合わせを実行するときに、 
・どの方式でテーブルを検索するか 
・複数のテーブルがある時はどの順序や結合方式で検索する 
か 
などを記述したもの 
・問い合わせプランの優劣はコストで決まる 
・Explainはこの問い合わせプランを表示す 
るコマンド 
13
PostgreSQLのクエリ処理のフロー 
DBにテーブルがあるか確認 
クエリの書き換え 
プランを実行 
14
エグゼキュータ 
• プランナで作成した問い合わせプランを実際に実行する 
• 方式によって実行ルーチンが変わる 
表スキャン 
結合処理 
条件処理 
15
Explainとは 
• PostgreSQLはクエリ(SQL文)を実行する際にクエリを分解して、 
最も効率の良い問い合わせプラン(実行計画)でデータを取 
得してくる 
• 問い合わせプランはPostgreSQLが推定してくれる 
• そのPostgreSQLによって推定された問い合わせプランの詳細 
を表示してくれるのがExplainです。 
16 
Explain 
クエリ実行のための 
問い合わせプラン
なぜExplainしなければならないのか 
• クエリをより高速に実行しDBのパフォーマンスを上げるには 
(クエリチューニングするには)、クエリの構造とクエリに含ま 
れるデータの性質にとって最適なプランを持つことが重要 
• しかしその最適なプランとPostgreSQLによって推定されたプラ 
ンがいつも一致するとは限らない 
• PostgreSQLによって推定されたプランが最適なプランかどう 
か確認するためにもExplainで確認することは大切 
17 
推定されたプラン= 最適なプラン 
Explainコマンドで確認しよう!
Explainの実行結果の読み方 
18
Explain Planの例 
=# EXPLAIN SELECT * FROM pg_proc 
ORDER BY proname; 
QUERY PLAN 
---------------------------------------------------- 
Sort (cost=181.55..185.92 rows=1747 width=322) 
Sort Key: proname 
-> Seq Scan on pg_proc 
(cost=0.00..87.47 rows=1747 width=322) 
19
20 
Explaining → Cost 
=# EXPLAIN SELECT oid FROM pg_proc; 
• コストは、プランナがさまざまなプランの中からある特定のプランを選 
ぶための指標である 
• 2つのコスト: 初期コスト(左) とトータルコスト(右) 
– 実行プランの比較で重要なのはトータルコスト。 
– いくつかの演算子には初期コストがある。無いものもある。 
– コストは推定値に過ぎない。その算出は結構複雑。 
• 値はシーケンシャルI/Oで1ページを読み込むコストを1.0 とした際の 
相対値で示される。 
QUERY PLAN 
------------------------------------------ 
Seq Scan on pg_proc 
(cost=0.00..87.47 rows=1747 width=4)
初期コストとトータルコスト 
21 
cost=0.00..87.47 
初期コスト実行コスト 
最後の行を返す 
最初の行を返す 
トータルコスト
Explaining → Cost 
パラメータ説明規定値相対速度 
seq_page_cost シーケンシャル読み込み1回1.00 (基準) 
random_page_cost ランダム読み込み1回4.00 4倍遅い 
cpu_tuple_cost 行の処理1回0.01 100倍速い 
cpu_index_tuple_cost 索引の処理1回0.005 200倍速い 
cpu_operator_cost 計算1回0.0025 400倍速い 
effective_cache_size ページキャッシュサイズ128MB N/A 
22
23 
Explaining → Rows 
=# EXPLAIN SELECT oid FROM pg_proc; 
QUERY PLAN 
------------------------------------------ 
Seq Scan on pg_proc 
(cost=0.00..87.47 rows=1747 width=4) 
• 推定された行数を表示する 
• PostgreSQL 8.0以前では、一度もVACUUM/ANALYZEされて 
いないテーブルについては1000行がデフォルト。 
• 実際の値と大きくかけ離れている場合、vacuum あるいは 
analyzeをすべきというサインである。
一般的なデータ型のサイズについて 
24 
Explaining → Widths 
=# EXPLAIN SELECT oid FROM pg_proc; 
QUERY PLAN 
------------------------------------------ 
Seq Scan on pg_proc 
(cost=0.00..87.47 rows=1747 width=4) 
• このレベルにおける推定さ 
れた入力サイズを表示する。 
• それほど重要ではない 
smallint 2 
integer 4 
bigint 8 
boolean 1 
char(n) n+1 
~ 
n+4 
varchar(n) 
text [ n文字]
しかし、これらはみな推定された値である。 
→実際のコストや行数を知るには? 
25
26 
Explaining → Explain Analyze 
=# EXPLAIN ANALYZE SELECT oid FROM pg_proc; 
QUERY PLAN 
------------------------------------------ 
Seq Scan on pg_proc 
(cost=0.00..87.47 rows=1747 width=4) 
(actual time=0.077..17.082 rows=1747 loops=1) 
Total runtime: 20.125 ms 
• 実際にクエリを実行し、実際の情報を表示する。 
• 時間はミリ秒で表示される。「コスト」とは無関係。 
• 全体の実行時間も表示される。 
• 「loops」は処理の繰り返し回数。実行時間(time)は繰り返し 
全体の時間を表す。
Explainの演算子 
27
Explain演算子とは 
• クエリを実行するための内部的な処理の計算タイプ 
• 処理の内容に応じていくつかの種類がある 
• PostgreSQLのプランナは、統計情報やwork_memの 
大きさなどをもとに、複数の演算子を組み合わせ、 
最も最適と推定される問い合わせプランを選択する 
• この演算子を変更して問い合わせプランを変更する 
のがクエリチューニング 
→演算子の処理について知っておくことが大切 
28
主な演算子一覧 
分類演算子処理 
テーブルスキャンSeq scan インデックスを使用せず、全件を検索 
Index scan インデックスを使用してスキャン 
Bitmap scan ビットマップを使用してスキャン 
Index only scan 問い合わせがインデックスに含まれるカラム 
のみで完結する場合のスキャン 
Tid scan 検索条件がタプルID(ctid)のスキャン 
その他のスキャンFunction scan 関数がデータをgatherした結果をスキャン 
テーブルの結合Nested Loop ネステッド・ループ結合を行う 
Merge Join ソート・マージ結合を行う 
Hash Join ハッシュ結合を行う 
29
分類演算子処理 
検索結果に対して 
作用 
Group GROUP BY 
limit LIMIT,OFFSET 
Unique UNIQUE 
Aggregate 集計関数(count,sum,,,) 
Group 
Aggregate 
集計関数にGROUP BYを使用し、より大きな結 
果のセットを得る 
Result 非テーブル問い合わせ 
結果の結合Append UNION(和) 
SetOp INTERSECT(積),EXCEPT(差) 
その他の処理を 
補助 
Sort ソート処理 
30 
更に詳しく知りたい方はこちらをどうぞ→ 
第20回目しくみ分科会Explaing Explain 第2回目 
http://www.postgresql.jp/wg/shikumi/sikumi_20/
テーブルスキャンする演算子 
31 
分類演算子 
テーブルスキャンSeq Scan 
Index Scan 
Bitmap Scan 
Index Only Scan 
Tid Scan 
その他スキャンFunction Scan 
テーブルの結合Nested Loop 
Merge Join 
Hash Join 
分類演算子 
検索結果に対して 
作用 
Group 
limit 
Unique 
Aggregate 
Group Aggregate 
Result 
結果の結合Append 
SetOp 
その他の処理を補 
助 
Sort
32 
Seq Scan 演算子 
=# 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) 
• 最も基本。単に表を最初から最後へとスキャンする 
• 条件にかかわらず各行をチェックする 
• 大きなテーブルはインデックススキャンの方が良い 
• コスト(開始コスト無し), 行(タプル), 幅(oid) 
• トータルコストは92.12
33 
Seq Scan について 
• テーブルを最初から最後までチェックして必要な行を探す。 
• 検索条件に合致するインデックスがない場合はこれしかない。 
• インデックスが使えても対象行が多い場合はSeq Scan に。 
⇒ プランナがコスト計算した結果を比較して判断する。 
id列のインデックステーブル 
id = 1 
id = 11 
id = 34 
id = 45 
・・・ 
使わない 
先頭行から順に走査 
(最後の行まで見る必要あり) 
Seq Scan のコスト 
= DISK I/O コスト+ CPU コスト 
= テーブル全ページ数×sequential_page_cost 
+ テーブル全行数×cpu_tuple_cost 
+ テーブル全行数×cpu_operator_cost 
・テーブル全ページ数pg_class のrelpages 
・テーブル全行数pg_calss のreltuples 
・シーケンシャルにDISK1ページを読むコスト 
sequential_page_cost = 1 
・1行を走査するCPUコスト 
cpu_tuple_cost = 0.01 
・計算1回のCPUコスト(条件絞りこみ) 
cpu_operator_cost = 0.0025
Seq Scanのコスト計算 
Seq Scanのコスト= (DISK I/Oコスト)+(CPUコスト) 
=(テーブル全ページ数×Seq_page_cost) 
+(テーブル全行数×cpu_tuple_cost ) 
+(テーブル全行数×cpu_operator_cost) 
34 
=# 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
----------------------------------------------------- 
Index Scan using pg_proc_oid_index on pg_proc 
35 
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が無い場合は、ソートの代わりとして使 
われるインデックス順のフルスキャンを表す
36 
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)の 
何倍かでアクセスコストは変化
37 
必要行数って何? 
• 指定条件を満たす行数 
• Explain の実行結果で「rows=100」とか表示される値。 
• プランナがテーブルの統計情報から行数を予測。 
⇒ 実際に検索した時の行数とは異なる。 
• 必要行数= 選択度×テーブル行数 
• 「選択度」は対象データがカラムに存在する割合 
• 選択度は対象カラムの統計情報を使って計算 
• 各カラム値の分布はpg_stats(pg_statistic)でわかる。 
⇒ ANALYZE時に収集した情報が格納されている。
38 
Bitmap Scan 演算子 
• 8.1で追加された 
• BitmapOr, BitmapAnd で複数のビットマップを合体 
• リレーションの”ビットマップ“をメモリ内で作成する
WHERE (id1 BETWEEN 10 AND 40) OR (id2 BETWEEN 20 AND 70) 
39 
Bitmap Scan について 
• インデックスを有効に使って検索効率を向上させる機構 
• ORで結合した条件式を使った検索に効果大 
id1 = 1, id2 = 33 
id1 = 11, id2 = 55 
id1 = 34, id2 = 77 
id1 = 45, id2 = 99 
・・・ 
1 11 34 45 
テーブル 
id1列のインデックス 
ビットONの行を取得 
id2列のインデックス 
33 55 77 99 
0 
1 
1 
0 
・・ 
1 
1 
0 
0 
・・ 
Bitmap Index Scan 
1 
1 
1 
0 
・・ 
BitmapOr 
条件を満たす行(TID)を 
ビットマップとして生成 
ビットマップ 
同士でOR演算 
Bitmap Heap Scan 
同一ページ内に複数の対象行が 
ある場合、まとめて取得できるので、 
I/Oコストが有利になる。
Index Only Scan 
• 9.2で追加された 
• 取得したい値にインデックスが含まれるとき、テーブ 
ルのアクセスを省略して検索する 
• 非常に高速(しかしindex only scanが選ばれるには 
条件が…) 
40
Index Only Scanのスキャン方法 
• Index Only ScanはまずインデックスからVisibility 
Mapを参照しに行く(早速テーブルには行かない) 
• そして高速に値を返せるか返せないかは、実はこの 
Visibility Mapにかかっている 
→このVisibility Mapって一体何者なの? 
41
Visibility Mapとは 
• ページ内にトランザクションによって更新され、参照すること 
ができなくなったタプルがあるかどうかを、ビットで管理してい 
る 
• テーブルのブロック毎に1bitのデータ領域を確保し、不要なタ 
プルがない&&どのトランザクションも更新していないブロック 
には”0”を、それ以外は”1”を保存する 
ブロック1の可視性 
ブロック2の可視性 
42 
ブロック1 
ブロック2 
ブロック3 
ブロック4
Visibility Mapのbitが0だと 
• テーブルにアクセスすることなくタプルの値を返す 
43 
SELECT id FROM table1 WHERE id BETWEEN 1 AND 11 
ブロック 
1 
2 
3 
4 
… 
全タプル有効! 
インデックス 
1 11 34 45 
テーブル 
テーブルにアクセスしない
Visibility Mapのbitが1だと 
• タプルの値が返せるものか判断するために通常の 
テーブルアクセスを行う 
無効タプルあり! 
44 
SELECT id FROM table1 WHERE id BETWEEN 1 AND 11 
ブロック 
1 
2 
3 
4 1 11 34 45 
… 
インデックス 
テーブル 
1 
本当に値返していいの? 
テーブルにアクセスしよう
不要タプルの回収 
・トランザクションによって発生した不要タプルを回収するには 
vacuumを行う 
無効タプル 
45 
ブロック2 
ViisibilityMap 
ブロック1 
ブロック2 
ブロック3 
ブロック4 
ブロック5 
テーブル 
VACUUM前 
VACUUM後 
再利用可能タプル 
ブロック2 
ViisibilityMap 
ブロック1 
ブロック2 
ブロック3 
ブロック4 
ブロック5 
テーブル
46 
Tid Scan 演算子 
=# EXPLAIN SELECT oid FROM pg_proc WHERE ctid = '(0,1)'; 
QUERY PLAN 
------------------------------------------------------ 
Tid Scan on pg_proc (cost=0.00..4.01 rows=1 width=4) 
Filter: (ctid = '(0,1)'::tid) 
• カラムタプルID 
• “ctid=”がクエリに指定された場合のみ使われる 
• 滅多に使わない、非常に速い
処理を補助する演算子 
47 
分類演算子 
テーブルスキャンSeq Scan 
Index Scan 
Bitmap Scan 
Index Only Scan 
Tid Scan 
その他スキャンFunction Scan 
テーブルの結合Nested Loop 
Merge Join 
Hash Join 
分類演算子 
検索結果に対して 
作用 
Group 
limit 
Unique 
Aggregate 
Group Aggregate 
Result 
結果の結合Append 
SetOp 
その他の処理を補 
助 
Sort
48 
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 など 
• 開始コストを持っている: 最初の値はすぐには返却 
されない
49 
Sort について 
• データが作業メモリ(work_mem)に収まればクイックソート 
– DISK I/Oが発生しない。高速。 
• 作業メモリに収まらなければ外部ソートを選択 
– アルゴリズムは「マージソート」 
– DISK I/Oが発生するのでクイックソートより低速。 
– I/Oコストは対象データとwork_mem のサイズで変わってくる。 
work_memに収まるサイズ毎にソートを繰り返すから。多分。。。 
– 詳しくは/src/backend/optimizer/path/costsize.c のcost_sort 参照。 
7 
4 
9 
2 
DISK 
• 対象データを全て 
メモリに保持 
• メモリ上でクイック 
ソートを実行 
7 
4 
9 
2 
2 
4 
7 
9 
2 
4 
7 
9 
8 
1 
3 
5 
1 
3 
5 
8 
DISK DISK 
・・・ 
【対象データ< work_mem】 
work_mem 
【対象データ> work_mem】 
work_mem 以下を繰り返す。 
• データの一部を 
メモリに保持 
• メモリ上でソート実行 
• ソート結果を 
DISKに戻す
50 
Sortの実行例 
# EXPLAIN ANALYZE SELECT * FROM pgbench_accounts ORDER BY bid; 
-------------------------------------------------------------------------------------------------------------------------- 
Sort (cost=290114.34..292614.34 rows=1000000 width=97) 
(actual time=882.522..1186.626 rows=1000000 loops=1) 
Sort Key: bid 
Sort Method: external sort Disk: 104600kB 
-> Seq Scan on pgbench_accounts (cost=0.00..26394.00 rows=1000000 width=97) 
ソート対象が大きいので外部ソート 
(actual time=0.023..176.540 rows=1000000 loops=1) 
Total runtime: 1264.377 ms 
※ ログに一時ファイル作成状況を表示(postgresql.conf のlog_temp_files = 0) 
LOG: temporary file: path "base/pgsql_tmp/pgsql_tmp32001.0", size 107110400 
STATEMENT: EXPLAIN ANALYZE SELECT * FROM pgbench_accounts ORDER BY bid; 
※ work_mem を1⇒200MBに拡張して実行してみる 
# SET work_mem=‘200MB’; 
# explain analyze select * from pgbench_accounts order by bid; 
-------------------------------------------------------------------------------------------------------------------------- 
Sort (cost=126051.84..128551.84 rows=1000000 width=97) 
(actual time=472.334..563.570 rows=1000000 loops=1) 
Sort Key: bid 
Sort Method: quicksort Memory: 165202kB 
-> Seq Scan on pgbench_accounts (cost=0.00..26394.00 rows=1000000 width=97) 
メモリに収まったのでクイックソート 
(actual time=0.030..166.788 rows=1000000 loops=1) 
Total runtime: 634.155 ms
テーブル結合する演算子 
51 
分類演算子 
テーブルスキャンSeq Scan 
Index Scan 
Bitmap Scan 
Index Only Scan 
Tid Scan 
その他スキャンFunction Scan 
テーブルの結合Nested Loop 
Merge Join 
Hash Join 
分類演算子 
検索結果に対して 
作用 
Group 
limit 
Unique 
Aggregate 
Group Aggregate 
Result 
結果の結合Append 
SetOp 
その他の処理を補 
助 
Sort
52 
Nested Loop 演算子 
=# EXPLAIN SELECT * FROM pgbench_accounts AS a, 
pgbench_accounts AS b; 
• 2つのテーブルの結合(2つの入力セット) 
• INNER JOIN とLEFT OUTER JOIN の使用 
• 「外部」テーブルをスキャンし、「内部」テーブルにマッチするものの発見 
• 開始コスト無し 
• インデックスが無い場合遅い問い合わせになる可能性、特にselect句に関 
数がある場合 
QUERY PLAN 
--------------------------------------------------------------- 
Nested Loop 
(cost=0.00..27637054248.00 rows=1000000000000 width=194) 
-> Seq Scan on pgbench_accounts a 
(cost=0.00..25874.00 rows=1000000 width=97) 
-> Materialize (cost=0.00..46011.00 rows=1000000 width=97) 
-> Seq Scan on pgbench_accounts b 
(cost=0.00..25874.00 rows=1000000 width=97)
Nested loop 
・もっとも単純な結合方式 
・外部テーブルを一レコードずつ取り出し、その都度内 
部テーブルの全レコードとマッチングする 
・初期コストは0、総コストは結合するテーブルのレコー 
ド数の積に比する(O(M×N)) 
53
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がある 
• データセットはあらかじめソートされていなければならず、また両方同 
時に走査される。 
54
55 
Merge Join (ソートマージ) 
• 事前に両方のテーブルを結合キーでソートする。 
• 両方のテーブルを先頭からマッチングしていく。 
⇒ テーブルを1回調べればよく、テーブルの走査回数減 
• 処理対象の行が多いケースで有効 
2 
4 
7 
9 
2 
7 
4 
9 
2 
1 
4 
3 
外側テーブル 
(N件) 
内側テーブル 
(M件) 
結合キーで 
事前にソート 
1 
2 
3 
4 
両テーブルを 
キー順に 
マッチング 
結合キーで 
事前にソート 
• ソートさえできれば速いが。。。 
⇒ インデックスがない列が結合キー 
の場合はコスト大。 
• 計算量はO(NlogN + MlogM)。
56 
Hash & Hash Join 演算子 
=# EXPLAIN SELECT * FROM pgbench_accounts AS a, 
pgbench_tellers AS t where a.bid = t.bid; 
QUERY PLAN 
--------------------------------------------------------------- 
Hash Join (cost=3.25..140877.25 rows=10000000 width=449) 
Hash Cond: (a.bid = t.bid) 
-> Seq Scan on pgbench_accounts a 
(cost=0.00..25874.00 rows=1000000 width=97) 
-> Hash (cost=2.00..2.00 rows=100 width=352) 
-> Seq Scan on pgbench_tellers t 
(cost=0.00..2.00 rows=100 width=352) 
• Hashは、異なるHash Join演算子で使用されるハッシュテーブルを作成 
する 
• 一方の入力からハッシュテーブルを作成し、二つの入力を比較する 
• INNER JOIN、OUTER JOINと同時に使われる 
• ハッシュの作成にはスタートアップコストが伴う
57 
Hash Join(ハッシュ値マッチング) 
• 事前に内側テーブルのハッシュ表を作成。 
⇒ ハッシュ表を作成する初期コストが必要。 
• 外側テーブルとハッシュ表を突き合わせる。 
• ハッシュ表がメモリ(work_mem)に収まらないと性能劣化。 
2 
7 
4 
9 
2 
1 
4 
3 
• 一度ハッシュ表を作ってしまえば、 
メモリ内で検索を行えるので 
ハッシュ表の検索は高速。 
• 計算量のオーダーはO(N+M)。 
外側テーブル 
(N件) 
内側テーブル 
(M件) 
ハッシュ表 
(メモリ内) 
ハッシュ表を 
事前に作成 
先頭から1行 
ずつスキャン 
結合キーのハッシュ値で 
ハッシュ表を検索
JOINの比較 
• Nested loop joinは,データが小さい場合に向 
いている 
• Merge joinは,データ量が多い場合に向いて 
いる 
• Hash joinは、ソートメモリーが十分にある場合 
に向いている 
58
検索結果に対して作用する演算子 
59 
分類演算子 
テーブルスキャンSeq Scan 
Index Scan 
Bitmap Scan 
Index Only Scan 
Tid Scan 
その他スキャンFunction Scan 
テーブルの結合Nested Loop 
Merge Join 
Hash Join 
分類演算子 
検索結果に対して 
作用 
Group 
limit 
Unique 
Aggregate 
Group Aggregate 
Result 
結果の結合Append 
SetOp 
その他の処理を補 
助 
Sort
60 
Limit 演算子 
=# EXPLAIN SELECT oid FROM pg_proc LIMIT 5; 
QUERY PLAN 
------------------------------------------ 
Limit (cost=0.00..0.25 rows=5 width=4) 
-> Seq Scan on pg_proc 
(cost=0.00..87.47 rows=1747 width=4) 
• 行は指定された数に等しい 
• 最初の行を即時に返す 
• 少量の開始コスト追加でオフセットの扱いも可 
=# EXPLAIN SELECT oid FROM pg_proc LIMIT 5 OFFSET 5; 
QUERY PLAN 
------------------------------------------ 
Limit (cost=0.25..0.50 rows=5 width=4) 
-> Seq Scan on pg_proc 
(cost=0.00..87.47 rows=1747 width=4)
61 
Result 演算子 
=# EXPLAIN SELECT 1 + 1 ; 
QUERY PLAN 
------------------------------------------ 
Result (cost=0.00..0.01 rows=1 width=0) 
• 非テーブル問い合わせ 
• テーブルを参照せずに結果が得られる場合
結果を結合する演算子 
62 
分類演算子 
テーブルスキャンSeq Scan 
Index Scan 
Bitmap Scan 
Index Only Scan 
Tid Scan 
その他スキャンFunction Scan 
テーブルの結合Nested Loop 
Merge Join 
Hash Join 
分類演算子 
検索結果に対して 
作用 
Group 
limit 
Unique 
Aggregate 
Group Aggregate 
Result 
結果の結合Append 
SetOp 
その他の処理を補 
助 
Sort
63 
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) によるトリガー, 継承 
• 開始コスト無し 
• コストは単に全ての入力の合計
------------------------------------------------------------------------ 
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) 
64 
SetOp 演算子 
=# EXPLAIN SELECT oid FROM pg_proc INTERSECT SELECT oid FROM pg_proc; 
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
実行プランを変える 
65
その前に 
• どの問い合わせプランを選んでくれるかは基本的に 
はPostgreSQL任せ 
• プランナーは人より賢いのでむやみに強制しないほ 
うが良い 
• PostgreSQLコミュニティの考えも以下のよう 
• We are not interested in implementing hints in the exact ways they are commonly 
implemented on other databases. Proposals based on "because they've got them" 
will not be welcomed. If you have an idea that avoids the problems that have been 
observed with other hint systems, that could lead to valuable discussion. 
• →他のDBにあるからなんて理由でPostgreSQLにヒント機能を持たせるのは歓迎し 
ません。もし既存のヒント機能における問題点を避けれるようなアイデアがあるな 
ら、そこで初めて議論しましょう。 
• 他方では、プランナーは推測しかしない 
– 統計情報を正しい状態に保つため定期的なANALYZEを。 
66
実行プランの強制例① 
• pg_hint_planを使用する 
• pg_hint_planは追加で提供されているモジュール 
• PostgreSQLのプランナに対して、どのような問い合 
わせプランを選ぶべきか指示(HINT)を与えることが 
できる。 
• クエリ単位で演算子を強制する 
67
pg_hint_planの実行例 
=# EXPLAIN SELECT aid FROM pgbench_accounts ; 
QUERY PLAN 
--------------------------------------------------------------------- 
- Index Only Scan using pgbench_accounts_pkey on pgbench_accounts 
(cost=0.00..2384.26 rows=100000 width=4) 
=# /*+ SeqScan(pgbench_accounts) */ explain select aid from 
pgbench_accounts; 
QUERY PLAN 
--------------------------------------------------------------------- 
- Seq Scan on pgbench_accounts (cost=0.00..2588.00 rows=100000 
width=4) 
68
69 
実行プランの強制②: 
• SETコマンドで演算子を無効にする 
• SET enable_演算子= off; 
– プランナーがある演算子を使おうとするのを「強く思いとどまらせる」 
ことができる 
• Planner Method Configuration (on/off) 
– enable_bitmapscan 
– enable_hashagg 
– enable_hashjoin 
– enable_indexscan 
– enable_indexonlyscan 
– enable_mergejoin 
– enable_nestloop 
– enable_seqscan 
– enable_sort 
– enable_tidscan 
• セッション単位で演算子を強制する
70 
SETコマンドの実行例 
=# EXPLAIN ANALYZE SELECT * FROM pg_class WHERE oid > 2112; 
QUERY PLAN 
------------------------------------------------ 
Seq Scan on pg_class 
(cost=0.00..7.33 rows=62 width=164) 
(actual time=0.087..1.700 rows=174 loops=1) 
Filter: (oid > 2112::oid) 
Total runtime: 2.413 ms 
=# SET enable_seqscan = off; 
=# EXPLAIN ANALYZE SELECT * ORDER BY pg_class WHERE oid > 2112; 
QUERY PLAN 
------------------------------------------------ 
Index Scan using pg_class_oid_index on pg_class 
(cost=0.00..22.84 rows=62 width=164) 
(actual time=0.144..1.802 rows=174 loops=1) 
Index Cond: (oid > 2112::oid) 
Total runtime: 2.653 ms
71 
Seq Scan の強制 
=# EXPLAIN SELECT * FROM pg_class; 
QUERY PLAN 
------------------------------------------------------- 
Seq Scan on pg_class 
(cost=100000000.00..100000006.86 rows=186 width=164) 
• 始動コストに100000000.0 を足すだけ 
– /src/backend/optimizer/path/costsize.c
実際のデバック例 
VACUUM ANALYZEをしよう 
72
このようなテーブルを用意 
73 
exception 
exception_id 
complete 
exception_notice_map 
exception_notice_map_id 
exception_id 
notice_id 
[boolean] 
SELECT exception_id FROM exception 
JOIN exception_notice_map 
USING (exception_id) 
WHERE complete IS FALSE AND notice_id = 3; 
インデックス 
exception_id 
部分インデックスcomplete=FALSE 
全体の0.25%
74 
VACUUM ANALYZE前 
=# EXPLAIN ANALYZE SELECT exception_id FROM exception 
JOIN exception_notice_map USING (exception_id) 
WHERE complete IS FALSE AND notice_id = 3; 
QUERY PLAN 
-------------------------------------------------------------------- 
Nested Loop (cost=0.00..2654.65 rows=199 width=8) 
(actual time=151.16..538.45 rows=124 loops=1) 
-> Seq Scan on exception_notice_map 
(cost=0.00..250.50 rows=399 width=4) 
(actual time=0.10..101.61 rows=15181 loops=1) 
Filter: (notice_id = 3) 
-> Index Scan using exception_pkey on exception 
(cost=0.00..6.01 rows=1 width=4) 
(actual time=0.03..0.03 rows=0 loops=15181) 
Index Cond: (exception.exception_id = "outer".exception_id) 
Filter: (complete IS FALSE) 
Total runtime: 538.76 msec exception表に“WHERE complete IS 
False”という条件の部分インデックスが 
あり、条件を満たす行は251行だけな 
のに使ってくれない
75 
VACUUM ANALYZE後 
=# ANALYZE exception; 
=# EXPLAIN ANALYZE SELECT exception_id FROM exception 
JOIN exception_notice_map USING (exception_id) 
WHERE complete IS FALSE AND notice_id = 3; 
QUERY PLAN 
-------------------------------------------------------------- 
Hash Join (cost=28.48..280.98 rows=1 width=8) 
(actual time=31.45..97.78 rows=124 loops=1) 
Hash Cond: ("outer".exception_id = "inner".exception_id) 
-> Seq Scan on exception_notice_map 
(cost=0.00..250.50 rows=399 width=4) 
(actual time=0.12..77.12 rows=15181 loops=1) 
Filter: (notice_id = 3) 
-> Hash (cost=26.31..26.31 rows=251 width=4) 
(actual time=2.96..2.96 rows=0 loops=1) 
-> Index Scan using active_exceptions on exception 
(cost=0.00..26.31 rows=251 width=4) 
(actual time=0.24..2.55 rows=251 loops=1) 
Filter: (complete IS FALSE) 
Total runtime: 97.99 msec 
部分インデックスを 
使ってくれた
Explainの実行に対して 
気を付けておくこと 
• まず最初に、テーブルがVACUUMとANALYZEされ 
ていることを確かめる 
• EXPLAINの出力を確認する 
– ANALYZEをつけて出力された実際の行数rows 
と推定行数rowsは一致しているか? 
– もしも一致していなかったら、統計情報から状態 
を確認しましょう。(pg_stat_all_tables) 
• n_dead_tup(無効タプル数) 
• last_vacuum/autovacuum(最後に(auto)vacuumされた時刻) 
• last_analyze(最後にanalyzeされた時刻) 
• などなど。。 
76
まとめ 
• Explainはクエリを実行するために最適と推 
定された問い合わせプランを表示するもの! 
• クエリチューニングをするためにはExplainが 
正しく読めることが重要! 
• 実行が遅いクエリを見つけたら、まずは 
VACUUM ANALYZEを! 
• PostgreSQLは最新のバージョンを使おう! 
77
参考文献 
• PostgreSQL全機能バイブル 
鈴木啓修・著 
• Explaining Explain ~ PostgreSQLの実行計画を読む~ 
by Robert Treat(翻訳:日本PostgreSQLユーザ会) 
• Explaining EXPLAIN 第2回 
第20回しくみ+アプリケーション勉強会中西さん 
• Explaining Explain 第3回 
第21回しくみ+アプリケーション勉強会田中さん 
• Let’s PostgreSQL 
http://lets.postgresql.jp/ 
• PostgreSQL wiki 
http://wiki.postgresql.org/wiki/Main_Page 
• 問合わせ最適化インサイド 
NTT オープンソースソフトウェアセンタ板垣さん 
78
ご清聴ありがとうございました 
79
参考までに 
80
81 
選択度の計算 
• 計算方法は2通り。 
• テーブル内で多く出現(重複)する値を条件指定した場合 
Common値(MCV: Most Common Values) 
# SELECT most_common_vals, most_common_freqs FROM pg_stats 
WHERE tablename='tenk1' AND attname='stringu1'; 
most_common_vals | {EJAAAA,BBAAAA,CRAAAA,FCAAAA,FEAAAA, 
GSAAAA,JOAAAA,MCAAAA,NAAAAA,WGAAAA} 
most_common_freqs | {0.00333333,0.003,0.003,0.003,0.003,0.003,0.003,0.003,0.003,0.003} 
• 実際にその値が入っている行の出現頻度が 
分かっているので、そのまま使用する。 
上記の例でテーブルtenk1の全行数を1000件とすると、 
「Stringu1=‘MCAAAA’」の行数は「1000×0.003 = 3」行と推測できる。 
出現数/テーブル行数 
※PostgreSQL 9.0.3 のマニュアル第56章の例を引用
82 
選択度の計算 
• Common値以外の値を条件指定した場合 
• 一致検索(WHERE stringu1 = ‘IAAAA’) 
選択度= MCV値を除いた行数/ カーディナリティ 
⇒ MCV値以外はテーブル内に均等に出現すると仮定。 
• 範囲検索(WHERE stringu1 < ‘IAAAA’) 
MCV値以外のヒストグラムを利用 
# SELECT histogram_bounds FROM pg_stats 
WHERE tablename='tenk1' AND attname='stringu1'; 
histogram_bounds 
各帯のサンプル数が均一化 
されるように帯幅を調整 
-------------------------------------------------------------------------------- 
{AAAAAA,CQAAAA,FRAAAA,IBAAAA,KRAAAA,NFAAAA,PSAAAA,SGAAAA, 
VAAAAA,XLAAAA,ZZAAAA} 
※PostgreSQL 9.0.3 のマニュアル第56章の例を引用 
• 指定範囲に含まれるMVC値の選択度と、 
ヒストグラムから導出した非MVC値の選択度を加える。
83 
work_mem とlossy storage 
• ビットマップは作業メモリ(work_mem)上に作成する。 
• 通常、ビットマップには行の位置を表すTIDを持つ。 
– work_mem = 1MB で500万行ほどしか持てない。 
• work_mem に収まらないサイズの場合、 
lossy storage モードへ移行してビットマップサイズを縮小 
– 1行を1ビットで表現⇒ 1ページを1ビットで表現(1MBで64GBまでOK) 
– 取得データから条件を満たさないデータを排除するコストが必要 
通常モードlossy storage モード 
0 TID(0, 1) 
1 TID(0, 2) 
1 TID(0, 3) 
0 TID(1, 1) 
0 TID(1, 2) 
0 TID(1, 3) 
・・・・ 
1 ページ0 
0 ページ1 
・・・・ 
ページ単位の 
ビットマップに 
変更してサイズ縮小 
TID(0, 1) 
TID(0, 2) 
TID(0, 3) 
・・ 
行データを取ってから 
不要行を削除する
84 
・・・ 
TIDとは 
• システムによって暗黙的に定義されたシステム列。 
• 行データの位置(格納ブロック,アイテムポインタ位置)を示す。 
索引 
表 
キー値:1000 TID=(5,1) キー値:1001 TID=(5,2) ・・・ 
ブロック番号5 
ブロック(ページ)ヘッダアイテムポインタ1 アイテムポインタ2 ・・・ 
・・・行データ2(キー値:1001) 行データ1(キー値:1000) 
TIDを1つ指定して検索する場合のコスト: 
random_page_cost(4.00)+ cpu_tuple_cost(0.01) = 4.01 
ただし、行のctidはレコードが更新されたり、VACUUM FULLで移動させられると 
変わるので、直接TIDを指定して検索するケースは少ないと思われる。
85 
Function Scan 演算子 
=# CREATE FUNCTION foo(integer) RETURNS SETOF integer AS 
$$ 
select $1; 
$$ 
LANGUAGE sql; 
=# EXPLAIN SELECT * FROM foo(12); 
QUERY PLAN 
------------------------------------------------------------ 
Function Scan on foo (cost=0.00..12.50 rows=1000 width=4) 
• 関数がデータをgatherするときに出てくる 
• トラブルシューティングの観点からは若干ミステリアス 
• 関数の中で使われているクエリについてexplainを走らせるべき
86 
Unique 演算子 
=# EXPLAIN SELECT distinct oid FROM pg_proc; 
QUERY PLAN 
-------------------------------------------------- 
Unique (cost=181.55..190.29 rows=1747 width=4) 
-> 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) 
• 入力セットから重複する値を削除 
• 行の並べ替えはせず、単に重複する行を取り除く 
• 入力セットは予めソート済み(Sort演算子の後に行う) 
• タプルコストごとに「CPU演算」×2 
• DISTINCT とUNION で使用される
87 
Aggregate 演算子 
=# EXPLAIN SELECT count(*) FROM pg_proc; 
QUERY PLAN 
-------------------------------------------------------------- 
Aggregate (cost=91.84..91.84 rows=1 width=0) 
-> Seq Scan on pg_proc (cost=0.00..87.47 rows=1747 width=0) 
• count, sum, min, max, avg, sttdev, varianceを使用 
• GROUP BY 使用の場合差異が認められることがあり 
=# EXPLAIN SELECT count(oid), oid FROM pg_proc GROUP BY oid; 
QUERY PLAN 
------------------------------------------------------------- 
HashAggregate (cost=96.20..100.57 rows=1747 width=4) 
-> Seq Scan on pg_proc (cost=0.00..87.47 rows=1747 width=4)
Sort Key: oid 
-> Seq Scan on pg_foo (cost=0.00..13520.54 rows=234654 width=4) 
88 
GroupAggregate 演算子 
=# EXPLAIN SELECT count(*) FROM pg_foo GROUP BY oid; 
QUERY PLAN 
----------------------------------------------------------------- 
GroupAggregate (cost=37442.53..39789.07 rows=234654 width=4) 
-> Sort (cost=37442.53..38029.16 rows=234654 width=4) 
• GROUP BYを使用し、より大きな結果セット上に集 
約を行う

More Related Content

What's hot

PostgreSQL 15 開発最新情報
PostgreSQL 15 開発最新情報PostgreSQL 15 開発最新情報
PostgreSQL 15 開発最新情報Masahiko Sawada
 
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)NTT DATA Technology & Innovation
 
PostgreSQLレプリケーション10周年!徹底紹介!(PostgreSQL Conference Japan 2019講演資料)
PostgreSQLレプリケーション10周年!徹底紹介!(PostgreSQL Conference Japan 2019講演資料)PostgreSQLレプリケーション10周年!徹底紹介!(PostgreSQL Conference Japan 2019講演資料)
PostgreSQLレプリケーション10周年!徹底紹介!(PostgreSQL Conference Japan 2019講演資料)NTT DATA Technology & Innovation
 
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)Hironobu Suzuki
 
マルチテナント化で知っておきたいデータベースのこと
マルチテナント化で知っておきたいデータベースのことマルチテナント化で知っておきたいデータベースのこと
マルチテナント化で知っておきたいデータベースのことAmazon Web Services Japan
 
初心者向けMongoDBのキホン!
初心者向けMongoDBのキホン!初心者向けMongoDBのキホン!
初心者向けMongoDBのキホン!Tetsutaro Watanabe
 
Inside vacuum - 第一回PostgreSQLプレ勉強会
Inside vacuum - 第一回PostgreSQLプレ勉強会Inside vacuum - 第一回PostgreSQLプレ勉強会
Inside vacuum - 第一回PostgreSQLプレ勉強会Masahiko Sawada
 
がっつりMongoDB事例紹介
がっつりMongoDB事例紹介がっつりMongoDB事例紹介
がっつりMongoDB事例紹介Tetsutaro Watanabe
 
分散システムについて語らせてくれ
分散システムについて語らせてくれ分散システムについて語らせてくれ
分散システムについて語らせてくれKumazaki Hiroki
 
20090107 Postgre Sqlチューニング(Sql編)
20090107 Postgre Sqlチューニング(Sql編)20090107 Postgre Sqlチューニング(Sql編)
20090107 Postgre Sqlチューニング(Sql編)Hiromu Shioya
 
本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話Kumazaki Hiroki
 
PostgreSQLの関数属性を知ろう
PostgreSQLの関数属性を知ろうPostgreSQLの関数属性を知ろう
PostgreSQLの関数属性を知ろうkasaharatt
 
PostgreSQL14の pg_stat_statements 改善(第23回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQL14の pg_stat_statements 改善(第23回PostgreSQLアンカンファレンス@オンライン 発表資料)PostgreSQL14の pg_stat_statements 改善(第23回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQL14の pg_stat_statements 改善(第23回PostgreSQLアンカンファレンス@オンライン 発表資料)NTT DATA Technology & Innovation
 
問合せ最適化インサイド
問合せ最適化インサイド問合せ最適化インサイド
問合せ最適化インサイドTakahiro Itagaki
 
PostgreSQLのfull_page_writesについて(第24回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQLのfull_page_writesについて(第24回PostgreSQLアンカンファレンス@オンライン 発表資料)PostgreSQLのfull_page_writesについて(第24回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQLのfull_page_writesについて(第24回PostgreSQLアンカンファレンス@オンライン 発表資料)NTT DATA Technology & Innovation
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!mosa siru
 
Apache Avro vs Protocol Buffers
Apache Avro vs Protocol BuffersApache Avro vs Protocol Buffers
Apache Avro vs Protocol BuffersSeiya Mizuno
 
大量のデータ処理や分析に使えるOSS Apache Spark入門(Open Source Conference 2021 Online/Kyoto 発表資料)
大量のデータ処理や分析に使えるOSS Apache Spark入門(Open Source Conference 2021 Online/Kyoto 発表資料)大量のデータ処理や分析に使えるOSS Apache Spark入門(Open Source Conference 2021 Online/Kyoto 発表資料)
大量のデータ処理や分析に使えるOSS Apache Spark入門(Open Source Conference 2021 Online/Kyoto 発表資料)NTT DATA Technology & Innovation
 
MySQL勉強会 クエリチューニング編
MySQL勉強会 クエリチューニング編MySQL勉強会 クエリチューニング編
MySQL勉強会 クエリチューニング編MicroAd, Inc.(Engineer)
 

What's hot (20)

PostgreSQL 15 開発最新情報
PostgreSQL 15 開発最新情報PostgreSQL 15 開発最新情報
PostgreSQL 15 開発最新情報
 
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
 
PostgreSQLレプリケーション10周年!徹底紹介!(PostgreSQL Conference Japan 2019講演資料)
PostgreSQLレプリケーション10周年!徹底紹介!(PostgreSQL Conference Japan 2019講演資料)PostgreSQLレプリケーション10周年!徹底紹介!(PostgreSQL Conference Japan 2019講演資料)
PostgreSQLレプリケーション10周年!徹底紹介!(PostgreSQL Conference Japan 2019講演資料)
 
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
 
マルチテナント化で知っておきたいデータベースのこと
マルチテナント化で知っておきたいデータベースのことマルチテナント化で知っておきたいデータベースのこと
マルチテナント化で知っておきたいデータベースのこと
 
初心者向けMongoDBのキホン!
初心者向けMongoDBのキホン!初心者向けMongoDBのキホン!
初心者向けMongoDBのキホン!
 
PostgreSQLバックアップの基本
PostgreSQLバックアップの基本PostgreSQLバックアップの基本
PostgreSQLバックアップの基本
 
Inside vacuum - 第一回PostgreSQLプレ勉強会
Inside vacuum - 第一回PostgreSQLプレ勉強会Inside vacuum - 第一回PostgreSQLプレ勉強会
Inside vacuum - 第一回PostgreSQLプレ勉強会
 
がっつりMongoDB事例紹介
がっつりMongoDB事例紹介がっつりMongoDB事例紹介
がっつりMongoDB事例紹介
 
分散システムについて語らせてくれ
分散システムについて語らせてくれ分散システムについて語らせてくれ
分散システムについて語らせてくれ
 
20090107 Postgre Sqlチューニング(Sql編)
20090107 Postgre Sqlチューニング(Sql編)20090107 Postgre Sqlチューニング(Sql編)
20090107 Postgre Sqlチューニング(Sql編)
 
本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話
 
PostgreSQLの関数属性を知ろう
PostgreSQLの関数属性を知ろうPostgreSQLの関数属性を知ろう
PostgreSQLの関数属性を知ろう
 
PostgreSQL14の pg_stat_statements 改善(第23回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQL14の pg_stat_statements 改善(第23回PostgreSQLアンカンファレンス@オンライン 発表資料)PostgreSQL14の pg_stat_statements 改善(第23回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQL14の pg_stat_statements 改善(第23回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
問合せ最適化インサイド
問合せ最適化インサイド問合せ最適化インサイド
問合せ最適化インサイド
 
PostgreSQLのfull_page_writesについて(第24回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQLのfull_page_writesについて(第24回PostgreSQLアンカンファレンス@オンライン 発表資料)PostgreSQLのfull_page_writesについて(第24回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQLのfull_page_writesについて(第24回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
 
Apache Avro vs Protocol Buffers
Apache Avro vs Protocol BuffersApache Avro vs Protocol Buffers
Apache Avro vs Protocol Buffers
 
大量のデータ処理や分析に使えるOSS Apache Spark入門(Open Source Conference 2021 Online/Kyoto 発表資料)
大量のデータ処理や分析に使えるOSS Apache Spark入門(Open Source Conference 2021 Online/Kyoto 発表資料)大量のデータ処理や分析に使えるOSS Apache Spark入門(Open Source Conference 2021 Online/Kyoto 発表資料)
大量のデータ処理や分析に使えるOSS Apache Spark入門(Open Source Conference 2021 Online/Kyoto 発表資料)
 
MySQL勉強会 クエリチューニング編
MySQL勉強会 クエリチューニング編MySQL勉強会 クエリチューニング編
MySQL勉強会 クエリチューニング編
 

Viewers also liked

PostgreSQL:行数推定を読み解く
PostgreSQL:行数推定を読み解くPostgreSQL:行数推定を読み解く
PostgreSQL:行数推定を読み解くHiroya Kabata
 
より深く知るオプティマイザとそのチューニング
より深く知るオプティマイザとそのチューニングより深く知るオプティマイザとそのチューニング
より深く知るオプティマイザとそのチューニングYuto Hayamizu
 
15分で情シスに怒られる方法
15分で情シスに怒られる方法15分で情シスに怒られる方法
15分で情シスに怒られる方法Satoshi Yamada
 
自治体Gisの勘違い(1)
自治体Gisの勘違い(1)自治体Gisの勘違い(1)
自治体Gisの勘違い(1)和仁 浅野
 
[よくわかるクラウドデータベース] Amazon RDS for PostgreSQL検証報告
[よくわかるクラウドデータベース] Amazon RDS for PostgreSQL検証報告[よくわかるクラウドデータベース] Amazon RDS for PostgreSQL検証報告
[よくわかるクラウドデータベース] Amazon RDS for PostgreSQL検証報告Amazon Web Services Japan
 
OSS-DB Gold技術解説セミナー@db tech showcase 東京 2014
OSS-DB Gold技術解説セミナー@db tech showcase 東京 2014OSS-DB Gold技術解説セミナー@db tech showcase 東京 2014
OSS-DB Gold技術解説セミナー@db tech showcase 東京 2014Shigeru Hanada
 
Data analytics with hadoop hive on multiple data centers
Data analytics with hadoop hive on multiple data centersData analytics with hadoop hive on multiple data centers
Data analytics with hadoop hive on multiple data centersHirotaka Niisato
 
Lars George HBase Seminar with O'REILLY Oct.12 2012
Lars George HBase Seminar with O'REILLY Oct.12 2012Lars George HBase Seminar with O'REILLY Oct.12 2012
Lars George HBase Seminar with O'REILLY Oct.12 2012Cloudera Japan
 
PostgreSQLの実行計画を読み解こう(OSC2015 Spring/Tokyo)
PostgreSQLの実行計画を読み解こう(OSC2015 Spring/Tokyo)PostgreSQLの実行計画を読み解こう(OSC2015 Spring/Tokyo)
PostgreSQLの実行計画を読み解こう(OSC2015 Spring/Tokyo)Satoshi Yamada
 
【17-E-3】 オンライン機械学習で実現する大規模データ処理
【17-E-3】 オンライン機械学習で実現する大規模データ処理【17-E-3】 オンライン機械学習で実現する大規模データ処理
【17-E-3】 オンライン機械学習で実現する大規模データ処理Developers Summit
 
20120830 DBリファクタリング読書会第三回
20120830 DBリファクタリング読書会第三回20120830 DBリファクタリング読書会第三回
20120830 DBリファクタリング読書会第三回都元ダイスケ Miyamoto
 
並列データベースシステムの概念と原理
並列データベースシステムの概念と原理並列データベースシステムの概念と原理
並列データベースシステムの概念と原理Makoto Yui
 
Cloudera Manager4.0とNameNode-HAセミナー資料
Cloudera Manager4.0とNameNode-HAセミナー資料Cloudera Manager4.0とNameNode-HAセミナー資料
Cloudera Manager4.0とNameNode-HAセミナー資料Cloudera Japan
 
Future of HCatalog - Hadoop Summit 2012
Future of HCatalog - Hadoop Summit 2012Future of HCatalog - Hadoop Summit 2012
Future of HCatalog - Hadoop Summit 2012Hortonworks
 
Writing Yarn Applications Hadoop Summit 2012
Writing Yarn Applications Hadoop Summit 2012Writing Yarn Applications Hadoop Summit 2012
Writing Yarn Applications Hadoop Summit 2012Hortonworks
 
あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界Yoshinori Nakanishi
 
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方kwatch
 

Viewers also liked (20)

使ってみませんか?pg_hint_plan
使ってみませんか?pg_hint_plan使ってみませんか?pg_hint_plan
使ってみませんか?pg_hint_plan
 
PostgreSQL:行数推定を読み解く
PostgreSQL:行数推定を読み解くPostgreSQL:行数推定を読み解く
PostgreSQL:行数推定を読み解く
 
より深く知るオプティマイザとそのチューニング
より深く知るオプティマイザとそのチューニングより深く知るオプティマイザとそのチューニング
より深く知るオプティマイザとそのチューニング
 
15分で情シスに怒られる方法
15分で情シスに怒られる方法15分で情シスに怒られる方法
15分で情シスに怒られる方法
 
自治体Gisの勘違い(1)
自治体Gisの勘違い(1)自治体Gisの勘違い(1)
自治体Gisの勘違い(1)
 
[よくわかるクラウドデータベース] Amazon RDS for PostgreSQL検証報告
[よくわかるクラウドデータベース] Amazon RDS for PostgreSQL検証報告[よくわかるクラウドデータベース] Amazon RDS for PostgreSQL検証報告
[よくわかるクラウドデータベース] Amazon RDS for PostgreSQL検証報告
 
OSC2015kyoto
OSC2015kyotoOSC2015kyoto
OSC2015kyoto
 
OSS-DB Gold技術解説セミナー@db tech showcase 東京 2014
OSS-DB Gold技術解説セミナー@db tech showcase 東京 2014OSS-DB Gold技術解説セミナー@db tech showcase 東京 2014
OSS-DB Gold技術解説セミナー@db tech showcase 東京 2014
 
Data analytics with hadoop hive on multiple data centers
Data analytics with hadoop hive on multiple data centersData analytics with hadoop hive on multiple data centers
Data analytics with hadoop hive on multiple data centers
 
Lars George HBase Seminar with O'REILLY Oct.12 2012
Lars George HBase Seminar with O'REILLY Oct.12 2012Lars George HBase Seminar with O'REILLY Oct.12 2012
Lars George HBase Seminar with O'REILLY Oct.12 2012
 
PostgreSQLの実行計画を読み解こう(OSC2015 Spring/Tokyo)
PostgreSQLの実行計画を読み解こう(OSC2015 Spring/Tokyo)PostgreSQLの実行計画を読み解こう(OSC2015 Spring/Tokyo)
PostgreSQLの実行計画を読み解こう(OSC2015 Spring/Tokyo)
 
Database smells
Database smellsDatabase smells
Database smells
 
【17-E-3】 オンライン機械学習で実現する大規模データ処理
【17-E-3】 オンライン機械学習で実現する大規模データ処理【17-E-3】 オンライン機械学習で実現する大規模データ処理
【17-E-3】 オンライン機械学習で実現する大規模データ処理
 
20120830 DBリファクタリング読書会第三回
20120830 DBリファクタリング読書会第三回20120830 DBリファクタリング読書会第三回
20120830 DBリファクタリング読書会第三回
 
並列データベースシステムの概念と原理
並列データベースシステムの概念と原理並列データベースシステムの概念と原理
並列データベースシステムの概念と原理
 
Cloudera Manager4.0とNameNode-HAセミナー資料
Cloudera Manager4.0とNameNode-HAセミナー資料Cloudera Manager4.0とNameNode-HAセミナー資料
Cloudera Manager4.0とNameNode-HAセミナー資料
 
Future of HCatalog - Hadoop Summit 2012
Future of HCatalog - Hadoop Summit 2012Future of HCatalog - Hadoop Summit 2012
Future of HCatalog - Hadoop Summit 2012
 
Writing Yarn Applications Hadoop Summit 2012
Writing Yarn Applications Hadoop Summit 2012Writing Yarn Applications Hadoop Summit 2012
Writing Yarn Applications Hadoop Summit 2012
 
あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界
 
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
 

Similar to PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~

JPUGしくみ+アプリケーション勉強会(第20回)
JPUGしくみ+アプリケーション勉強会(第20回)JPUGしくみ+アプリケーション勉強会(第20回)
JPUGしくみ+アプリケーション勉強会(第20回)Yoshinori Nakanishi
 
Fundamentals of Relational Database Management Systems chapter19
Fundamentals of Relational Database Management Systems chapter19Fundamentals of Relational Database Management Systems chapter19
Fundamentals of Relational Database Management Systems chapter19Keisuke Suzuki
 
A Tour of PostgreSQL
A Tour of PostgreSQLA Tour of PostgreSQL
A Tour of PostgreSQLEDB
 
RailsエンジニアのためのSQLチューニング速習会
RailsエンジニアのためのSQLチューニング速習会RailsエンジニアのためのSQLチューニング速習会
RailsエンジニアのためのSQLチューニング速習会Nao Minami
 
PostgreSQL13 新機能紹介
PostgreSQL13 新機能紹介PostgreSQL13 新機能紹介
PostgreSQL13 新機能紹介Satoshi Hirata
 
PL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
PL/CUDA - Fusion of HPC Grade Power with In-Database AnalyticsPL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
PL/CUDA - Fusion of HPC Grade Power with In-Database AnalyticsKohei KaiGai
 
Pgunconf 20121212-postgeres fdw
Pgunconf 20121212-postgeres fdwPgunconf 20121212-postgeres fdw
Pgunconf 20121212-postgeres fdwToshi Harada
 
20170127 JAWS HPC-UG#8
20170127 JAWS HPC-UG#820170127 JAWS HPC-UG#8
20170127 JAWS HPC-UG#8Kohei KaiGai
 
20190119 aws-study-pg-extension
20190119 aws-study-pg-extension20190119 aws-study-pg-extension
20190119 aws-study-pg-extensionToshi Harada
 
Django/Celeyを用いたデータ分析Webアプリケーションにおける非同期処理の設計と実装
Django/Celeyを用いたデータ分析Webアプリケーションにおける非同期処理の設計と実装Django/Celeyを用いたデータ分析Webアプリケーションにおける非同期処理の設計と実装
Django/Celeyを用いたデータ分析Webアプリケーションにおける非同期処理の設計と実装Satoshi Nagayasu
 
20181110 fok2018-pg-extension
20181110 fok2018-pg-extension20181110 fok2018-pg-extension
20181110 fok2018-pg-extensionToshi Harada
 
Slurmのジョブスケジューリングと実装
Slurmのジョブスケジューリングと実装Slurmのジョブスケジューリングと実装
Slurmのジョブスケジューリングと実装Ryuichi Sakamoto
 
Maatkit で MySQL チューニング
Maatkit で MySQL チューニングMaatkit で MySQL チューニング
Maatkit で MySQL チューニングKensuke Nagae
 
Let's scale-out PostgreSQL using Citus (Japanese)
Let's scale-out PostgreSQL using Citus (Japanese)Let's scale-out PostgreSQL using Citus (Japanese)
Let's scale-out PostgreSQL using Citus (Japanese)Noriyoshi Shinoda
 
20140531 JPUGしくみ+アプリケーション分科会 勉強会資料
20140531 JPUGしくみ+アプリケーション分科会 勉強会資料20140531 JPUGしくみ+アプリケーション分科会 勉強会資料
20140531 JPUGしくみ+アプリケーション分科会 勉強会資料kasaharatt
 
TPC-DSから学ぶPostgreSQLの弱点と今後の展望
TPC-DSから学ぶPostgreSQLの弱点と今後の展望TPC-DSから学ぶPostgreSQLの弱点と今後の展望
TPC-DSから学ぶPostgreSQLの弱点と今後の展望Kohei KaiGai
 
MongoDB: システム可用性を拡張するインデクス戦略
MongoDB: システム可用性を拡張するインデクス戦略MongoDB: システム可用性を拡張するインデクス戦略
MongoDB: システム可用性を拡張するインデクス戦略ippei_suzuki
 

Similar to PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~ (20)

JPUGしくみ+アプリケーション勉強会(第20回)
JPUGしくみ+アプリケーション勉強会(第20回)JPUGしくみ+アプリケーション勉強会(第20回)
JPUGしくみ+アプリケーション勉強会(第20回)
 
Fundamentals of Relational Database Management Systems chapter19
Fundamentals of Relational Database Management Systems chapter19Fundamentals of Relational Database Management Systems chapter19
Fundamentals of Relational Database Management Systems chapter19
 
pg_bigmを用いた全文検索のしくみ(前編)
pg_bigmを用いた全文検索のしくみ(前編)pg_bigmを用いた全文検索のしくみ(前編)
pg_bigmを用いた全文検索のしくみ(前編)
 
A Tour of PostgreSQL
A Tour of PostgreSQLA Tour of PostgreSQL
A Tour of PostgreSQL
 
RailsエンジニアのためのSQLチューニング速習会
RailsエンジニアのためのSQLチューニング速習会RailsエンジニアのためのSQLチューニング速習会
RailsエンジニアのためのSQLチューニング速習会
 
PostgreSQL13 新機能紹介
PostgreSQL13 新機能紹介PostgreSQL13 新機能紹介
PostgreSQL13 新機能紹介
 
PL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
PL/CUDA - Fusion of HPC Grade Power with In-Database AnalyticsPL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
PL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
 
Pgunconf 20121212-postgeres fdw
Pgunconf 20121212-postgeres fdwPgunconf 20121212-postgeres fdw
Pgunconf 20121212-postgeres fdw
 
20170127 JAWS HPC-UG#8
20170127 JAWS HPC-UG#820170127 JAWS HPC-UG#8
20170127 JAWS HPC-UG#8
 
20190119 aws-study-pg-extension
20190119 aws-study-pg-extension20190119 aws-study-pg-extension
20190119 aws-study-pg-extension
 
Django/Celeyを用いたデータ分析Webアプリケーションにおける非同期処理の設計と実装
Django/Celeyを用いたデータ分析Webアプリケーションにおける非同期処理の設計と実装Django/Celeyを用いたデータ分析Webアプリケーションにおける非同期処理の設計と実装
Django/Celeyを用いたデータ分析Webアプリケーションにおける非同期処理の設計と実装
 
20181110 fok2018-pg-extension
20181110 fok2018-pg-extension20181110 fok2018-pg-extension
20181110 fok2018-pg-extension
 
Slurmのジョブスケジューリングと実装
Slurmのジョブスケジューリングと実装Slurmのジョブスケジューリングと実装
Slurmのジョブスケジューリングと実装
 
Maatkit で MySQL チューニング
Maatkit で MySQL チューニングMaatkit で MySQL チューニング
Maatkit で MySQL チューニング
 
Let's scale-out PostgreSQL using Citus (Japanese)
Let's scale-out PostgreSQL using Citus (Japanese)Let's scale-out PostgreSQL using Citus (Japanese)
Let's scale-out PostgreSQL using Citus (Japanese)
 
20140531 JPUGしくみ+アプリケーション分科会 勉強会資料
20140531 JPUGしくみ+アプリケーション分科会 勉強会資料20140531 JPUGしくみ+アプリケーション分科会 勉強会資料
20140531 JPUGしくみ+アプリケーション分科会 勉強会資料
 
PostgreSQL 12の話
PostgreSQL 12の話PostgreSQL 12の話
PostgreSQL 12の話
 
TPC-DSから学ぶPostgreSQLの弱点と今後の展望
TPC-DSから学ぶPostgreSQLの弱点と今後の展望TPC-DSから学ぶPostgreSQLの弱点と今後の展望
TPC-DSから学ぶPostgreSQLの弱点と今後の展望
 
MongoDB: システム可用性を拡張するインデクス戦略
MongoDB: システム可用性を拡張するインデクス戦略MongoDB: システム可用性を拡張するインデクス戦略
MongoDB: システム可用性を拡張するインデクス戦略
 
Chugokudb18_2
Chugokudb18_2Chugokudb18_2
Chugokudb18_2
 

Recently uploaded

[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略Ryo Sasaki
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNetToru Tamaki
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A surveyToru Tamaki
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdftaisei2219
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムsugiuralab
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものですiPride Co., Ltd.
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Yuma Ohgami
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)Hiroki Ichikura
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...Toru Tamaki
 

Recently uploaded (9)

[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システム
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
 

PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~

  • 2. 自己紹介 • 氏名下雅意美紀 • 所属TIS株式会社 • 経歴入社1年目 • PostgreSQL歴= 入社歴 • 業務で勉強する以外にも、前回のJPUGのしくみ分科会にも 参加したり(http://thinkit.co.jp/story/2014/07/01/5074)、 PGEConsにも参加したりとコミュニティ活動なども通して日々 PostgreSQLの勉強をしています。 2
  • 3. PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~ アジェンダ ・PostgreSQLのクエリ実行の概要 ・Explain実行結果(問い合わせプラン)の読み方 ・Explain演算子の種類 ・問い合わせプランを変更させる ・実際のデバック例 3 目標 クエリチューニングで使用するExlpainコマンドが出力する実行 計画を読めるようになりましょう。 PostgreSQLがクエリ実行時に内部でどのような処理を行ってい るかを知りましょう。
  • 6. パーサ • クエリの構文を解析して、文字列が正しい構文になっているかをチェック • 構文が正しくなければエラーを返す • 構文が正しければパースツリーの形に変換 • テーブル名やカラム名が実在するかは問わないので「ローパースツリー」 とも呼ばれる 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
  • 10. リライタ • PostgreSQLではVIEWやRULEはクエリを書き換えることで実行 している • このような書き換えの処理をリライタという 10
  • 12. プランナ • クエリツリーを解析して、実際に問い合わせを実行するための問い 合わせプランを求める • 問い合わせの実行コストを見積もり、最小コストのものを問い合わ せプランとする(問い合わせの最適化) • コスト計算のための最小単位はパス • パスは各処理によって種類がある • ここで作成された問い合わせプランはあくまで推定されたもの クエリツリー パス単位でコスト計算 最小コストのものを問い合わせプランに パスの種類 ・全件スキャン ・インデックスを使ってスキャン ・テーブル結合 など 12
  • 13. 問い合わせプランとは ・問い合わせプランとは、問い合わせを実行するときに、 ・どの方式でテーブルを検索するか ・複数のテーブルがある時はどの順序や結合方式で検索する か などを記述したもの ・問い合わせプランの優劣はコストで決まる ・Explainはこの問い合わせプランを表示す るコマンド 13
  • 15. エグゼキュータ • プランナで作成した問い合わせプランを実際に実行する • 方式によって実行ルーチンが変わる 表スキャン 結合処理 条件処理 15
  • 16. Explainとは • PostgreSQLはクエリ(SQL文)を実行する際にクエリを分解して、 最も効率の良い問い合わせプラン(実行計画)でデータを取 得してくる • 問い合わせプランはPostgreSQLが推定してくれる • そのPostgreSQLによって推定された問い合わせプランの詳細 を表示してくれるのがExplainです。 16 Explain クエリ実行のための 問い合わせプラン
  • 17. なぜExplainしなければならないのか • クエリをより高速に実行しDBのパフォーマンスを上げるには (クエリチューニングするには)、クエリの構造とクエリに含ま れるデータの性質にとって最適なプランを持つことが重要 • しかしその最適なプランとPostgreSQLによって推定されたプラ ンがいつも一致するとは限らない • PostgreSQLによって推定されたプランが最適なプランかどう か確認するためにもExplainで確認することは大切 17 推定されたプラン= 最適なプラン Explainコマンドで確認しよう!
  • 19. Explain Planの例 =# EXPLAIN SELECT * FROM pg_proc ORDER BY proname; QUERY PLAN ---------------------------------------------------- Sort (cost=181.55..185.92 rows=1747 width=322) Sort Key: proname -> Seq Scan on pg_proc (cost=0.00..87.47 rows=1747 width=322) 19
  • 20. 20 Explaining → Cost =# EXPLAIN SELECT oid FROM pg_proc; • コストは、プランナがさまざまなプランの中からある特定のプランを選 ぶための指標である • 2つのコスト: 初期コスト(左) とトータルコスト(右) – 実行プランの比較で重要なのはトータルコスト。 – いくつかの演算子には初期コストがある。無いものもある。 – コストは推定値に過ぎない。その算出は結構複雑。 • 値はシーケンシャルI/Oで1ページを読み込むコストを1.0 とした際の 相対値で示される。 QUERY PLAN ------------------------------------------ Seq Scan on pg_proc (cost=0.00..87.47 rows=1747 width=4)
  • 21. 初期コストとトータルコスト 21 cost=0.00..87.47 初期コスト実行コスト 最後の行を返す 最初の行を返す トータルコスト
  • 22. Explaining → Cost パラメータ説明規定値相対速度 seq_page_cost シーケンシャル読み込み1回1.00 (基準) random_page_cost ランダム読み込み1回4.00 4倍遅い cpu_tuple_cost 行の処理1回0.01 100倍速い cpu_index_tuple_cost 索引の処理1回0.005 200倍速い cpu_operator_cost 計算1回0.0025 400倍速い effective_cache_size ページキャッシュサイズ128MB N/A 22
  • 23. 23 Explaining → Rows =# EXPLAIN SELECT oid FROM pg_proc; QUERY PLAN ------------------------------------------ Seq Scan on pg_proc (cost=0.00..87.47 rows=1747 width=4) • 推定された行数を表示する • PostgreSQL 8.0以前では、一度もVACUUM/ANALYZEされて いないテーブルについては1000行がデフォルト。 • 実際の値と大きくかけ離れている場合、vacuum あるいは analyzeをすべきというサインである。
  • 24. 一般的なデータ型のサイズについて 24 Explaining → Widths =# EXPLAIN SELECT oid FROM pg_proc; QUERY PLAN ------------------------------------------ Seq Scan on pg_proc (cost=0.00..87.47 rows=1747 width=4) • このレベルにおける推定さ れた入力サイズを表示する。 • それほど重要ではない smallint 2 integer 4 bigint 8 boolean 1 char(n) n+1 ~ n+4 varchar(n) text [ n文字]
  • 26. 26 Explaining → Explain Analyze =# EXPLAIN ANALYZE SELECT oid FROM pg_proc; QUERY PLAN ------------------------------------------ Seq Scan on pg_proc (cost=0.00..87.47 rows=1747 width=4) (actual time=0.077..17.082 rows=1747 loops=1) Total runtime: 20.125 ms • 実際にクエリを実行し、実際の情報を表示する。 • 時間はミリ秒で表示される。「コスト」とは無関係。 • 全体の実行時間も表示される。 • 「loops」は処理の繰り返し回数。実行時間(time)は繰り返し 全体の時間を表す。
  • 28. Explain演算子とは • クエリを実行するための内部的な処理の計算タイプ • 処理の内容に応じていくつかの種類がある • PostgreSQLのプランナは、統計情報やwork_memの 大きさなどをもとに、複数の演算子を組み合わせ、 最も最適と推定される問い合わせプランを選択する • この演算子を変更して問い合わせプランを変更する のがクエリチューニング →演算子の処理について知っておくことが大切 28
  • 29. 主な演算子一覧 分類演算子処理 テーブルスキャンSeq scan インデックスを使用せず、全件を検索 Index scan インデックスを使用してスキャン Bitmap scan ビットマップを使用してスキャン Index only scan 問い合わせがインデックスに含まれるカラム のみで完結する場合のスキャン Tid scan 検索条件がタプルID(ctid)のスキャン その他のスキャンFunction scan 関数がデータをgatherした結果をスキャン テーブルの結合Nested Loop ネステッド・ループ結合を行う Merge Join ソート・マージ結合を行う Hash Join ハッシュ結合を行う 29
  • 30. 分類演算子処理 検索結果に対して 作用 Group GROUP BY limit LIMIT,OFFSET Unique UNIQUE Aggregate 集計関数(count,sum,,,) Group Aggregate 集計関数にGROUP BYを使用し、より大きな結 果のセットを得る Result 非テーブル問い合わせ 結果の結合Append UNION(和) SetOp INTERSECT(積),EXCEPT(差) その他の処理を 補助 Sort ソート処理 30 更に詳しく知りたい方はこちらをどうぞ→ 第20回目しくみ分科会Explaing Explain 第2回目 http://www.postgresql.jp/wg/shikumi/sikumi_20/
  • 31. テーブルスキャンする演算子 31 分類演算子 テーブルスキャンSeq Scan Index Scan Bitmap Scan Index Only Scan Tid Scan その他スキャンFunction Scan テーブルの結合Nested Loop Merge Join Hash Join 分類演算子 検索結果に対して 作用 Group limit Unique Aggregate Group Aggregate Result 結果の結合Append SetOp その他の処理を補 助 Sort
  • 32. 32 Seq Scan 演算子 =# 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) • 最も基本。単に表を最初から最後へとスキャンする • 条件にかかわらず各行をチェックする • 大きなテーブルはインデックススキャンの方が良い • コスト(開始コスト無し), 行(タプル), 幅(oid) • トータルコストは92.12
  • 33. 33 Seq Scan について • テーブルを最初から最後までチェックして必要な行を探す。 • 検索条件に合致するインデックスがない場合はこれしかない。 • インデックスが使えても対象行が多い場合はSeq Scan に。 ⇒ プランナがコスト計算した結果を比較して判断する。 id列のインデックステーブル id = 1 id = 11 id = 34 id = 45 ・・・ 使わない 先頭行から順に走査 (最後の行まで見る必要あり) Seq Scan のコスト = DISK I/O コスト+ CPU コスト = テーブル全ページ数×sequential_page_cost + テーブル全行数×cpu_tuple_cost + テーブル全行数×cpu_operator_cost ・テーブル全ページ数pg_class のrelpages ・テーブル全行数pg_calss のreltuples ・シーケンシャルにDISK1ページを読むコスト sequential_page_cost = 1 ・1行を走査するCPUコスト cpu_tuple_cost = 0.01 ・計算1回のCPUコスト(条件絞りこみ) cpu_operator_cost = 0.0025
  • 34. Seq Scanのコスト計算 Seq Scanのコスト= (DISK I/Oコスト)+(CPUコスト) =(テーブル全ページ数×Seq_page_cost) +(テーブル全行数×cpu_tuple_cost ) +(テーブル全行数×cpu_operator_cost) 34 =# 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
  • 35. ----------------------------------------------------- Index Scan using pg_proc_oid_index on pg_proc 35 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が無い場合は、ソートの代わりとして使 われるインデックス順のフルスキャンを表す
  • 36. 36 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)の 何倍かでアクセスコストは変化
  • 37. 37 必要行数って何? • 指定条件を満たす行数 • Explain の実行結果で「rows=100」とか表示される値。 • プランナがテーブルの統計情報から行数を予測。 ⇒ 実際に検索した時の行数とは異なる。 • 必要行数= 選択度×テーブル行数 • 「選択度」は対象データがカラムに存在する割合 • 選択度は対象カラムの統計情報を使って計算 • 各カラム値の分布はpg_stats(pg_statistic)でわかる。 ⇒ ANALYZE時に収集した情報が格納されている。
  • 38. 38 Bitmap Scan 演算子 • 8.1で追加された • BitmapOr, BitmapAnd で複数のビットマップを合体 • リレーションの”ビットマップ“をメモリ内で作成する
  • 39. WHERE (id1 BETWEEN 10 AND 40) OR (id2 BETWEEN 20 AND 70) 39 Bitmap Scan について • インデックスを有効に使って検索効率を向上させる機構 • ORで結合した条件式を使った検索に効果大 id1 = 1, id2 = 33 id1 = 11, id2 = 55 id1 = 34, id2 = 77 id1 = 45, id2 = 99 ・・・ 1 11 34 45 テーブル id1列のインデックス ビットONの行を取得 id2列のインデックス 33 55 77 99 0 1 1 0 ・・ 1 1 0 0 ・・ Bitmap Index Scan 1 1 1 0 ・・ BitmapOr 条件を満たす行(TID)を ビットマップとして生成 ビットマップ 同士でOR演算 Bitmap Heap Scan 同一ページ内に複数の対象行が ある場合、まとめて取得できるので、 I/Oコストが有利になる。
  • 40. Index Only Scan • 9.2で追加された • 取得したい値にインデックスが含まれるとき、テーブ ルのアクセスを省略して検索する • 非常に高速(しかしindex only scanが選ばれるには 条件が…) 40
  • 41. Index Only Scanのスキャン方法 • Index Only ScanはまずインデックスからVisibility Mapを参照しに行く(早速テーブルには行かない) • そして高速に値を返せるか返せないかは、実はこの Visibility Mapにかかっている →このVisibility Mapって一体何者なの? 41
  • 42. Visibility Mapとは • ページ内にトランザクションによって更新され、参照すること ができなくなったタプルがあるかどうかを、ビットで管理してい る • テーブルのブロック毎に1bitのデータ領域を確保し、不要なタ プルがない&&どのトランザクションも更新していないブロック には”0”を、それ以外は”1”を保存する ブロック1の可視性 ブロック2の可視性 42 ブロック1 ブロック2 ブロック3 ブロック4
  • 43. Visibility Mapのbitが0だと • テーブルにアクセスすることなくタプルの値を返す 43 SELECT id FROM table1 WHERE id BETWEEN 1 AND 11 ブロック 1 2 3 4 … 全タプル有効! インデックス 1 11 34 45 テーブル テーブルにアクセスしない
  • 44. Visibility Mapのbitが1だと • タプルの値が返せるものか判断するために通常の テーブルアクセスを行う 無効タプルあり! 44 SELECT id FROM table1 WHERE id BETWEEN 1 AND 11 ブロック 1 2 3 4 1 11 34 45 … インデックス テーブル 1 本当に値返していいの? テーブルにアクセスしよう
  • 45. 不要タプルの回収 ・トランザクションによって発生した不要タプルを回収するには vacuumを行う 無効タプル 45 ブロック2 ViisibilityMap ブロック1 ブロック2 ブロック3 ブロック4 ブロック5 テーブル VACUUM前 VACUUM後 再利用可能タプル ブロック2 ViisibilityMap ブロック1 ブロック2 ブロック3 ブロック4 ブロック5 テーブル
  • 46. 46 Tid Scan 演算子 =# EXPLAIN SELECT oid FROM pg_proc WHERE ctid = '(0,1)'; QUERY PLAN ------------------------------------------------------ Tid Scan on pg_proc (cost=0.00..4.01 rows=1 width=4) Filter: (ctid = '(0,1)'::tid) • カラムタプルID • “ctid=”がクエリに指定された場合のみ使われる • 滅多に使わない、非常に速い
  • 47. 処理を補助する演算子 47 分類演算子 テーブルスキャンSeq Scan Index Scan Bitmap Scan Index Only Scan Tid Scan その他スキャンFunction Scan テーブルの結合Nested Loop Merge Join Hash Join 分類演算子 検索結果に対して 作用 Group limit Unique Aggregate Group Aggregate Result 結果の結合Append SetOp その他の処理を補 助 Sort
  • 48. 48 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 など • 開始コストを持っている: 最初の値はすぐには返却 されない
  • 49. 49 Sort について • データが作業メモリ(work_mem)に収まればクイックソート – DISK I/Oが発生しない。高速。 • 作業メモリに収まらなければ外部ソートを選択 – アルゴリズムは「マージソート」 – DISK I/Oが発生するのでクイックソートより低速。 – I/Oコストは対象データとwork_mem のサイズで変わってくる。 work_memに収まるサイズ毎にソートを繰り返すから。多分。。。 – 詳しくは/src/backend/optimizer/path/costsize.c のcost_sort 参照。 7 4 9 2 DISK • 対象データを全て メモリに保持 • メモリ上でクイック ソートを実行 7 4 9 2 2 4 7 9 2 4 7 9 8 1 3 5 1 3 5 8 DISK DISK ・・・ 【対象データ< work_mem】 work_mem 【対象データ> work_mem】 work_mem 以下を繰り返す。 • データの一部を メモリに保持 • メモリ上でソート実行 • ソート結果を DISKに戻す
  • 50. 50 Sortの実行例 # EXPLAIN ANALYZE SELECT * FROM pgbench_accounts ORDER BY bid; -------------------------------------------------------------------------------------------------------------------------- Sort (cost=290114.34..292614.34 rows=1000000 width=97) (actual time=882.522..1186.626 rows=1000000 loops=1) Sort Key: bid Sort Method: external sort Disk: 104600kB -> Seq Scan on pgbench_accounts (cost=0.00..26394.00 rows=1000000 width=97) ソート対象が大きいので外部ソート (actual time=0.023..176.540 rows=1000000 loops=1) Total runtime: 1264.377 ms ※ ログに一時ファイル作成状況を表示(postgresql.conf のlog_temp_files = 0) LOG: temporary file: path "base/pgsql_tmp/pgsql_tmp32001.0", size 107110400 STATEMENT: EXPLAIN ANALYZE SELECT * FROM pgbench_accounts ORDER BY bid; ※ work_mem を1⇒200MBに拡張して実行してみる # SET work_mem=‘200MB’; # explain analyze select * from pgbench_accounts order by bid; -------------------------------------------------------------------------------------------------------------------------- Sort (cost=126051.84..128551.84 rows=1000000 width=97) (actual time=472.334..563.570 rows=1000000 loops=1) Sort Key: bid Sort Method: quicksort Memory: 165202kB -> Seq Scan on pgbench_accounts (cost=0.00..26394.00 rows=1000000 width=97) メモリに収まったのでクイックソート (actual time=0.030..166.788 rows=1000000 loops=1) Total runtime: 634.155 ms
  • 51. テーブル結合する演算子 51 分類演算子 テーブルスキャンSeq Scan Index Scan Bitmap Scan Index Only Scan Tid Scan その他スキャンFunction Scan テーブルの結合Nested Loop Merge Join Hash Join 分類演算子 検索結果に対して 作用 Group limit Unique Aggregate Group Aggregate Result 結果の結合Append SetOp その他の処理を補 助 Sort
  • 52. 52 Nested Loop 演算子 =# EXPLAIN SELECT * FROM pgbench_accounts AS a, pgbench_accounts AS b; • 2つのテーブルの結合(2つの入力セット) • INNER JOIN とLEFT OUTER JOIN の使用 • 「外部」テーブルをスキャンし、「内部」テーブルにマッチするものの発見 • 開始コスト無し • インデックスが無い場合遅い問い合わせになる可能性、特にselect句に関 数がある場合 QUERY PLAN --------------------------------------------------------------- Nested Loop (cost=0.00..27637054248.00 rows=1000000000000 width=194) -> Seq Scan on pgbench_accounts a (cost=0.00..25874.00 rows=1000000 width=97) -> Materialize (cost=0.00..46011.00 rows=1000000 width=97) -> Seq Scan on pgbench_accounts b (cost=0.00..25874.00 rows=1000000 width=97)
  • 53. Nested loop ・もっとも単純な結合方式 ・外部テーブルを一レコードずつ取り出し、その都度内 部テーブルの全レコードとマッチングする ・初期コストは0、総コストは結合するテーブルのレコー ド数の積に比する(O(M×N)) 53
  • 54. 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がある • データセットはあらかじめソートされていなければならず、また両方同 時に走査される。 54
  • 55. 55 Merge Join (ソートマージ) • 事前に両方のテーブルを結合キーでソートする。 • 両方のテーブルを先頭からマッチングしていく。 ⇒ テーブルを1回調べればよく、テーブルの走査回数減 • 処理対象の行が多いケースで有効 2 4 7 9 2 7 4 9 2 1 4 3 外側テーブル (N件) 内側テーブル (M件) 結合キーで 事前にソート 1 2 3 4 両テーブルを キー順に マッチング 結合キーで 事前にソート • ソートさえできれば速いが。。。 ⇒ インデックスがない列が結合キー の場合はコスト大。 • 計算量はO(NlogN + MlogM)。
  • 56. 56 Hash & Hash Join 演算子 =# EXPLAIN SELECT * FROM pgbench_accounts AS a, pgbench_tellers AS t where a.bid = t.bid; QUERY PLAN --------------------------------------------------------------- Hash Join (cost=3.25..140877.25 rows=10000000 width=449) Hash Cond: (a.bid = t.bid) -> Seq Scan on pgbench_accounts a (cost=0.00..25874.00 rows=1000000 width=97) -> Hash (cost=2.00..2.00 rows=100 width=352) -> Seq Scan on pgbench_tellers t (cost=0.00..2.00 rows=100 width=352) • Hashは、異なるHash Join演算子で使用されるハッシュテーブルを作成 する • 一方の入力からハッシュテーブルを作成し、二つの入力を比較する • INNER JOIN、OUTER JOINと同時に使われる • ハッシュの作成にはスタートアップコストが伴う
  • 57. 57 Hash Join(ハッシュ値マッチング) • 事前に内側テーブルのハッシュ表を作成。 ⇒ ハッシュ表を作成する初期コストが必要。 • 外側テーブルとハッシュ表を突き合わせる。 • ハッシュ表がメモリ(work_mem)に収まらないと性能劣化。 2 7 4 9 2 1 4 3 • 一度ハッシュ表を作ってしまえば、 メモリ内で検索を行えるので ハッシュ表の検索は高速。 • 計算量のオーダーはO(N+M)。 外側テーブル (N件) 内側テーブル (M件) ハッシュ表 (メモリ内) ハッシュ表を 事前に作成 先頭から1行 ずつスキャン 結合キーのハッシュ値で ハッシュ表を検索
  • 58. JOINの比較 • Nested loop joinは,データが小さい場合に向 いている • Merge joinは,データ量が多い場合に向いて いる • Hash joinは、ソートメモリーが十分にある場合 に向いている 58
  • 59. 検索結果に対して作用する演算子 59 分類演算子 テーブルスキャンSeq Scan Index Scan Bitmap Scan Index Only Scan Tid Scan その他スキャンFunction Scan テーブルの結合Nested Loop Merge Join Hash Join 分類演算子 検索結果に対して 作用 Group limit Unique Aggregate Group Aggregate Result 結果の結合Append SetOp その他の処理を補 助 Sort
  • 60. 60 Limit 演算子 =# EXPLAIN SELECT oid FROM pg_proc LIMIT 5; QUERY PLAN ------------------------------------------ Limit (cost=0.00..0.25 rows=5 width=4) -> Seq Scan on pg_proc (cost=0.00..87.47 rows=1747 width=4) • 行は指定された数に等しい • 最初の行を即時に返す • 少量の開始コスト追加でオフセットの扱いも可 =# EXPLAIN SELECT oid FROM pg_proc LIMIT 5 OFFSET 5; QUERY PLAN ------------------------------------------ Limit (cost=0.25..0.50 rows=5 width=4) -> Seq Scan on pg_proc (cost=0.00..87.47 rows=1747 width=4)
  • 61. 61 Result 演算子 =# EXPLAIN SELECT 1 + 1 ; QUERY PLAN ------------------------------------------ Result (cost=0.00..0.01 rows=1 width=0) • 非テーブル問い合わせ • テーブルを参照せずに結果が得られる場合
  • 62. 結果を結合する演算子 62 分類演算子 テーブルスキャンSeq Scan Index Scan Bitmap Scan Index Only Scan Tid Scan その他スキャンFunction Scan テーブルの結合Nested Loop Merge Join Hash Join 分類演算子 検索結果に対して 作用 Group limit Unique Aggregate Group Aggregate Result 結果の結合Append SetOp その他の処理を補 助 Sort
  • 63. 63 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) によるトリガー, 継承 • 開始コスト無し • コストは単に全ての入力の合計
  • 64. ------------------------------------------------------------------------ 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) 64 SetOp 演算子 =# EXPLAIN SELECT oid FROM pg_proc INTERSECT SELECT oid FROM pg_proc; 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
  • 66. その前に • どの問い合わせプランを選んでくれるかは基本的に はPostgreSQL任せ • プランナーは人より賢いのでむやみに強制しないほ うが良い • PostgreSQLコミュニティの考えも以下のよう • We are not interested in implementing hints in the exact ways they are commonly implemented on other databases. Proposals based on "because they've got them" will not be welcomed. If you have an idea that avoids the problems that have been observed with other hint systems, that could lead to valuable discussion. • →他のDBにあるからなんて理由でPostgreSQLにヒント機能を持たせるのは歓迎し ません。もし既存のヒント機能における問題点を避けれるようなアイデアがあるな ら、そこで初めて議論しましょう。 • 他方では、プランナーは推測しかしない – 統計情報を正しい状態に保つため定期的なANALYZEを。 66
  • 67. 実行プランの強制例① • pg_hint_planを使用する • pg_hint_planは追加で提供されているモジュール • PostgreSQLのプランナに対して、どのような問い合 わせプランを選ぶべきか指示(HINT)を与えることが できる。 • クエリ単位で演算子を強制する 67
  • 68. pg_hint_planの実行例 =# EXPLAIN SELECT aid FROM pgbench_accounts ; QUERY PLAN --------------------------------------------------------------------- - Index Only Scan using pgbench_accounts_pkey on pgbench_accounts (cost=0.00..2384.26 rows=100000 width=4) =# /*+ SeqScan(pgbench_accounts) */ explain select aid from pgbench_accounts; QUERY PLAN --------------------------------------------------------------------- - Seq Scan on pgbench_accounts (cost=0.00..2588.00 rows=100000 width=4) 68
  • 69. 69 実行プランの強制②: • SETコマンドで演算子を無効にする • SET enable_演算子= off; – プランナーがある演算子を使おうとするのを「強く思いとどまらせる」 ことができる • Planner Method Configuration (on/off) – enable_bitmapscan – enable_hashagg – enable_hashjoin – enable_indexscan – enable_indexonlyscan – enable_mergejoin – enable_nestloop – enable_seqscan – enable_sort – enable_tidscan • セッション単位で演算子を強制する
  • 70. 70 SETコマンドの実行例 =# EXPLAIN ANALYZE SELECT * FROM pg_class WHERE oid > 2112; QUERY PLAN ------------------------------------------------ Seq Scan on pg_class (cost=0.00..7.33 rows=62 width=164) (actual time=0.087..1.700 rows=174 loops=1) Filter: (oid > 2112::oid) Total runtime: 2.413 ms =# SET enable_seqscan = off; =# EXPLAIN ANALYZE SELECT * ORDER BY pg_class WHERE oid > 2112; QUERY PLAN ------------------------------------------------ Index Scan using pg_class_oid_index on pg_class (cost=0.00..22.84 rows=62 width=164) (actual time=0.144..1.802 rows=174 loops=1) Index Cond: (oid > 2112::oid) Total runtime: 2.653 ms
  • 71. 71 Seq Scan の強制 =# EXPLAIN SELECT * FROM pg_class; QUERY PLAN ------------------------------------------------------- Seq Scan on pg_class (cost=100000000.00..100000006.86 rows=186 width=164) • 始動コストに100000000.0 を足すだけ – /src/backend/optimizer/path/costsize.c
  • 73. このようなテーブルを用意 73 exception exception_id complete exception_notice_map exception_notice_map_id exception_id notice_id [boolean] SELECT exception_id FROM exception JOIN exception_notice_map USING (exception_id) WHERE complete IS FALSE AND notice_id = 3; インデックス exception_id 部分インデックスcomplete=FALSE 全体の0.25%
  • 74. 74 VACUUM ANALYZE前 =# EXPLAIN ANALYZE SELECT exception_id FROM exception JOIN exception_notice_map USING (exception_id) WHERE complete IS FALSE AND notice_id = 3; QUERY PLAN -------------------------------------------------------------------- Nested Loop (cost=0.00..2654.65 rows=199 width=8) (actual time=151.16..538.45 rows=124 loops=1) -> Seq Scan on exception_notice_map (cost=0.00..250.50 rows=399 width=4) (actual time=0.10..101.61 rows=15181 loops=1) Filter: (notice_id = 3) -> Index Scan using exception_pkey on exception (cost=0.00..6.01 rows=1 width=4) (actual time=0.03..0.03 rows=0 loops=15181) Index Cond: (exception.exception_id = "outer".exception_id) Filter: (complete IS FALSE) Total runtime: 538.76 msec exception表に“WHERE complete IS False”という条件の部分インデックスが あり、条件を満たす行は251行だけな のに使ってくれない
  • 75. 75 VACUUM ANALYZE後 =# ANALYZE exception; =# EXPLAIN ANALYZE SELECT exception_id FROM exception JOIN exception_notice_map USING (exception_id) WHERE complete IS FALSE AND notice_id = 3; QUERY PLAN -------------------------------------------------------------- Hash Join (cost=28.48..280.98 rows=1 width=8) (actual time=31.45..97.78 rows=124 loops=1) Hash Cond: ("outer".exception_id = "inner".exception_id) -> Seq Scan on exception_notice_map (cost=0.00..250.50 rows=399 width=4) (actual time=0.12..77.12 rows=15181 loops=1) Filter: (notice_id = 3) -> Hash (cost=26.31..26.31 rows=251 width=4) (actual time=2.96..2.96 rows=0 loops=1) -> Index Scan using active_exceptions on exception (cost=0.00..26.31 rows=251 width=4) (actual time=0.24..2.55 rows=251 loops=1) Filter: (complete IS FALSE) Total runtime: 97.99 msec 部分インデックスを 使ってくれた
  • 76. Explainの実行に対して 気を付けておくこと • まず最初に、テーブルがVACUUMとANALYZEされ ていることを確かめる • EXPLAINの出力を確認する – ANALYZEをつけて出力された実際の行数rows と推定行数rowsは一致しているか? – もしも一致していなかったら、統計情報から状態 を確認しましょう。(pg_stat_all_tables) • n_dead_tup(無効タプル数) • last_vacuum/autovacuum(最後に(auto)vacuumされた時刻) • last_analyze(最後にanalyzeされた時刻) • などなど。。 76
  • 77. まとめ • Explainはクエリを実行するために最適と推 定された問い合わせプランを表示するもの! • クエリチューニングをするためにはExplainが 正しく読めることが重要! • 実行が遅いクエリを見つけたら、まずは VACUUM ANALYZEを! • PostgreSQLは最新のバージョンを使おう! 77
  • 78. 参考文献 • PostgreSQL全機能バイブル 鈴木啓修・著 • Explaining Explain ~ PostgreSQLの実行計画を読む~ by Robert Treat(翻訳:日本PostgreSQLユーザ会) • Explaining EXPLAIN 第2回 第20回しくみ+アプリケーション勉強会中西さん • Explaining Explain 第3回 第21回しくみ+アプリケーション勉強会田中さん • Let’s PostgreSQL http://lets.postgresql.jp/ • PostgreSQL wiki http://wiki.postgresql.org/wiki/Main_Page • 問合わせ最適化インサイド NTT オープンソースソフトウェアセンタ板垣さん 78
  • 81. 81 選択度の計算 • 計算方法は2通り。 • テーブル内で多く出現(重複)する値を条件指定した場合 Common値(MCV: Most Common Values) # SELECT most_common_vals, most_common_freqs FROM pg_stats WHERE tablename='tenk1' AND attname='stringu1'; most_common_vals | {EJAAAA,BBAAAA,CRAAAA,FCAAAA,FEAAAA, GSAAAA,JOAAAA,MCAAAA,NAAAAA,WGAAAA} most_common_freqs | {0.00333333,0.003,0.003,0.003,0.003,0.003,0.003,0.003,0.003,0.003} • 実際にその値が入っている行の出現頻度が 分かっているので、そのまま使用する。 上記の例でテーブルtenk1の全行数を1000件とすると、 「Stringu1=‘MCAAAA’」の行数は「1000×0.003 = 3」行と推測できる。 出現数/テーブル行数 ※PostgreSQL 9.0.3 のマニュアル第56章の例を引用
  • 82. 82 選択度の計算 • Common値以外の値を条件指定した場合 • 一致検索(WHERE stringu1 = ‘IAAAA’) 選択度= MCV値を除いた行数/ カーディナリティ ⇒ MCV値以外はテーブル内に均等に出現すると仮定。 • 範囲検索(WHERE stringu1 < ‘IAAAA’) MCV値以外のヒストグラムを利用 # SELECT histogram_bounds FROM pg_stats WHERE tablename='tenk1' AND attname='stringu1'; histogram_bounds 各帯のサンプル数が均一化 されるように帯幅を調整 -------------------------------------------------------------------------------- {AAAAAA,CQAAAA,FRAAAA,IBAAAA,KRAAAA,NFAAAA,PSAAAA,SGAAAA, VAAAAA,XLAAAA,ZZAAAA} ※PostgreSQL 9.0.3 のマニュアル第56章の例を引用 • 指定範囲に含まれるMVC値の選択度と、 ヒストグラムから導出した非MVC値の選択度を加える。
  • 83. 83 work_mem とlossy storage • ビットマップは作業メモリ(work_mem)上に作成する。 • 通常、ビットマップには行の位置を表すTIDを持つ。 – work_mem = 1MB で500万行ほどしか持てない。 • work_mem に収まらないサイズの場合、 lossy storage モードへ移行してビットマップサイズを縮小 – 1行を1ビットで表現⇒ 1ページを1ビットで表現(1MBで64GBまでOK) – 取得データから条件を満たさないデータを排除するコストが必要 通常モードlossy storage モード 0 TID(0, 1) 1 TID(0, 2) 1 TID(0, 3) 0 TID(1, 1) 0 TID(1, 2) 0 TID(1, 3) ・・・・ 1 ページ0 0 ページ1 ・・・・ ページ単位の ビットマップに 変更してサイズ縮小 TID(0, 1) TID(0, 2) TID(0, 3) ・・ 行データを取ってから 不要行を削除する
  • 84. 84 ・・・ TIDとは • システムによって暗黙的に定義されたシステム列。 • 行データの位置(格納ブロック,アイテムポインタ位置)を示す。 索引 表 キー値:1000 TID=(5,1) キー値:1001 TID=(5,2) ・・・ ブロック番号5 ブロック(ページ)ヘッダアイテムポインタ1 アイテムポインタ2 ・・・ ・・・行データ2(キー値:1001) 行データ1(キー値:1000) TIDを1つ指定して検索する場合のコスト: random_page_cost(4.00)+ cpu_tuple_cost(0.01) = 4.01 ただし、行のctidはレコードが更新されたり、VACUUM FULLで移動させられると 変わるので、直接TIDを指定して検索するケースは少ないと思われる。
  • 85. 85 Function Scan 演算子 =# CREATE FUNCTION foo(integer) RETURNS SETOF integer AS $$ select $1; $$ LANGUAGE sql; =# EXPLAIN SELECT * FROM foo(12); QUERY PLAN ------------------------------------------------------------ Function Scan on foo (cost=0.00..12.50 rows=1000 width=4) • 関数がデータをgatherするときに出てくる • トラブルシューティングの観点からは若干ミステリアス • 関数の中で使われているクエリについてexplainを走らせるべき
  • 86. 86 Unique 演算子 =# EXPLAIN SELECT distinct oid FROM pg_proc; QUERY PLAN -------------------------------------------------- Unique (cost=181.55..190.29 rows=1747 width=4) -> 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) • 入力セットから重複する値を削除 • 行の並べ替えはせず、単に重複する行を取り除く • 入力セットは予めソート済み(Sort演算子の後に行う) • タプルコストごとに「CPU演算」×2 • DISTINCT とUNION で使用される
  • 87. 87 Aggregate 演算子 =# EXPLAIN SELECT count(*) FROM pg_proc; QUERY PLAN -------------------------------------------------------------- Aggregate (cost=91.84..91.84 rows=1 width=0) -> Seq Scan on pg_proc (cost=0.00..87.47 rows=1747 width=0) • count, sum, min, max, avg, sttdev, varianceを使用 • GROUP BY 使用の場合差異が認められることがあり =# EXPLAIN SELECT count(oid), oid FROM pg_proc GROUP BY oid; QUERY PLAN ------------------------------------------------------------- HashAggregate (cost=96.20..100.57 rows=1747 width=4) -> Seq Scan on pg_proc (cost=0.00..87.47 rows=1747 width=4)
  • 88. Sort Key: oid -> Seq Scan on pg_foo (cost=0.00..13520.54 rows=234654 width=4) 88 GroupAggregate 演算子 =# EXPLAIN SELECT count(*) FROM pg_foo GROUP BY oid; QUERY PLAN ----------------------------------------------------------------- GroupAggregate (cost=37442.53..39789.07 rows=234654 width=4) -> Sort (cost=37442.53..38029.16 rows=234654 width=4) • GROUP BYを使用し、より大きな結果セット上に集 約を行う