1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD html 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
4 <title>pg_hint_plan</title>
5 <!-- Uncoment after the tool has been hosted somewhere.
6 <link rel="home" title="pg_hint_plan" href="index.html">
8 <link rel="stylesheet" type="text/css" href="style.css">
9 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
13 <h1 id="pg_hint_plan">pg_hint_plan 1.0.0</h1>
14 <div class="navigation">
15 <a href="pg_hint_plan-ja.html">pg_hint_plan</a>
21 <li><a href="#name">pg_hint_planとは?</a></li>
22 <li><a href="#description">機能概要</a></li>
23 <li><a href="#install">インストール</a>
25 <li><a href="#requirement">動作環境</a></li>
26 <li><a href="#build">ビルド</a></li>
29 <li><a href="#uninstall">アンインストール</a></li>
30 <li><a href="#usage">使い方</a>
32 <li><a href="#hint-load">pg_hint_planのロード</a></li>
33 <li><a href="#hint-rule">ヒントの記述方法</a></li>
34 <li><a href="#hint-group">ヒントのグループ</a></li>
35 <li><a href="#hint-GUC">pg_hint_planのGUCパラメータ</a></li>
38 <li><a href="#restrictions">使用上の注意と制約</a></li>
39 <li><a href="#seealso">関連項目</a></li>
40 <li><a href="hint_list-ja.html">Appendix A. ヒント一覧</a></li>
43 <h2 id="name">pg_hint_planとは?</h2>
44 <p>pg_hint_planは、元のSQL文を変えずに実行計画を制御するためのツールです。</p>
46 <h2 id="description">機能概要</h2>
47 <p>pg_hint_planを用いると、ヒントを記述したブロックコメントをSQL文の前に加えることで、実行計画を制御することができます。</p>
49 <h2 id="install">インストール</h2>
50 <p>pg_hint_planのインストール方法について説明します。</p>
52 <h3 id="requirement">動作環境</h3>
60 <h3 id="build">ビルド</h3>
61 <p>pg_hint_planをソースコードからビルドする場合、pg_hint_planのソースを展開したディレクトリでmake → make installの順に実行してください。make installはPostgreSQLをインストールしたOSユーザで実行してください。なお、pg_hint_planのビルドにはpgxsを使用するので、RPM版のPostgreSQLを使用している環境では、postgresql-devel パッケージが必要です。</p>
64 $ tar xzvf pg_hint_plan-1.0.0.tar.gz
65 $ cd pg_hint_plan-1.0.0
71 <h2 id="uninstall">アンインストール</h2>
72 <p>pg_hint_planをアンインストールするには、pg_hint_planのソースを展開したディレクトリでmake uninstallを実行してください。</p>
73 <p>以下にアンインストールの例を示します。</p>
75 $ cd pg_hint_plan-1.0.0
80 <h2 id="usage">使い方</h2>
81 <p>pg_hint_planの使い方について説明します。</p>
83 <h3 id="hint-load">pg_hint_planのロード</h3>
84 <p>pg_hint_planを使うには、以下の例のようにpg_hint_planの共有ライブラリをロードしてください。全てのセッションでpg_hint_planを有効にするには、shared_preload_libraries GUCパラメータに'pg_hint_plan'を追加してからサーバを再起動して下さい。</p>
86 postgres=# LOAD 'pg_hint_plan';
90 <h3 id="hint-rule">ヒントの記述方法</h3>
91 <p>ヒントはクエリ文字列の先頭のブロックコメント内に記述してください。ブロックコメントをヒントとして認識させるには、ブロックコメントの開始直後にプラス(+)を指定する必要があります。ヒントの対象は、カッコ内にオブジェクト名または別名(エイリアス)で指定してください。オブジェクト名は、スペース、タブ、または改行のいずれかで区切って指定してください。</p>
93 <p>以下の例では、HashJoinとSeqScanヒントにより、pgbench_accountsテーブルに対するSeq Scanの結果をHash Joinする実行計画が選択されています。</p>
96 postgres*# <span class="strong">HashJoin(a b)</span>
97 postgres*# <span class="strong">SeqScan(a)</span>
99 postgres-# EXPLAIN SELECT *
100 postgres-# FROM pgbench_branches b
101 postgres-# JOIN pgbench_accounts a ON b.bid = a.bid
102 postgres-# ORDER BY a.aid;
104 ---------------------------------------------------------------------------------------
105 Sort (cost=31465.84..31715.84 rows=100000 width=197)
107 -> <span class="strong">Hash Join</span> (cost=1.02..4016.02 rows=100000 width=197)
108 Hash Cond: (a.bid = b.bid)
109 -> <span class="strong">Seq Scan on pgbench_accounts a</span> (cost=0.00..2640.00 rows=100000 width=97)
110 -> Hash (cost=1.01..1.01 rows=1 width=100)
111 -> Seq Scan on pgbench_branches b (cost=0.00..1.01 rows=1 width=100)
116 <h3 id="hint-group">ヒントのグループ</h3>
117 <p>pg_hint_planで使えるヒントは、スキャン方式と結合方式、結合順序、GUCパラメータの4グループに分けられます。各グループの具体的なヒントは、<a href="hint_list-ja.html">ヒント一覧</a>を参照してください。</p>
120 <p>あるオブジェクトでどのスキャン方式を選択するかを指定できるヒントのグループで、「SeqScan」や「IndexScan」などが含まれます。</p>
121 <p>スキャン方式を指定できるオブジェクトは、通常のテーブル、継承テーブル、UNLOGGEDテーブル、一時テーブル、システムカタログです。スキャン方式を指定できないオブジェクトは、外部テーブル、テーブル関数、VALUESコマンド結果、CTE、VIEW、副問い合わせ結果です。</p>
122 <p>特定のオブジェクトについてあるスキャン方式を選択して欲しい場合は、そのスキャン方式のヒントと、対象となるオブジェクトの名前を指定してください。逆に、特定のオブジェクトについてあるスキャン方式を選択して欲しくない場合は、Noで始まるヒントを指定してください。同じオブジェクトに対して複数のスキャン方式のヒントを指定した場合は、最後に指定したヒントが適用されます。</p>
125 <p>あるオブジェクトの組み合わせでどの結合方式を選択するかを指定できるヒントのグループで、「MergeJoin」や「NestLoop」などが含まれます。</p>
126 <p>結合方式を指定できるオブジェクトは、通常のテーブル、継承テーブル、UNLOGGEDテーブル、一時テーブル、外部テーブル、システムカタログ、テーブル関数、VALUESコマンド結果、CTEです。結合方式を指定できないオブジェクトは、VIEW、副問い合わせ結果です。</p>
127 <p>特定のオブジェクトの組み合わせについてある結合方式を選択して欲しい場合は、その結合方式のヒントと、対象となる2つ以上のオブジェクトの名前を指定してください。逆に、特定のオブジェクトの組み合わせについてある結合方式を選択して欲しくない場合は、Noで始まるヒントを指定してください。同じオブジェクトの組み合わせに対して複数の結合方式のヒントを指定した場合は、最後に指定したヒントが適用されます。</p>
129 <p>あるオブジェクトの組み合わせでどのような順番で結合するかを指定できるヒントのグループで、「Leading」のみが含まれます。</p>
130 <p>結合順序を指定できるオブジェクトは結合方式と同じです。</p>
131 <p>先に結合して欲しいオブジェクトから順にオブジェクト名または別名を指定してください。複数の結合順序のヒントを指定した場合は、最後に指定したヒントが適用されます。</p>
133 <p>そのクエリの実行計画を作成している間だけGUCパラメータを変更できるヒントのグループで、「Set」のみが含まれます。</p>
134 <p>設定したいGUCパラメータとそのパラメータの値を指定してください。<a href="http://www.postgresql.org/docs/9.1/static/sql-set.html">SET</a>コマンドで指定できるGUCパラメータならば全て指定できますが、効果があるのは<a href="http://www.postgresql.org/docs/9.1/static/runtime-config-query.html">問い合わせ計画</a>のGUCパラメータのみです。同じGUCパラメータに対して複数のGUCパラメータのヒントを指定した場合は、最後に指定したヒントが適用されます。</p>
136 <h3 id="hint-GUC">pg_hint_planのGUCパラメータ</h3>
137 <p>pg_hint_planの動作を制御するGUCパラメータを以下に記述します。</p>
141 <tr><th>GUCパラメータ</th><th>説明</th><th>デフォルト値</th></tr>
144 <tr><td>pg_hint_plan.enable</td>
145 <td>pg_hint_planの機能を有効または無効にします。</td><td>on</td></tr>
146 <tr><td>pg_hint_plan.debug_print</td>
147 <td>pg_hint_planのデバッグ出力を有効にします。メッセージはLOGメッセージレベルで出力されますので、デフォルトではサーバログに出力され、クライアントには渡されません。</td><td>off</td></tr>
148 <tr><td>pg_hint_plan.parse_messages</td>
149 <td>指定したヒントを解釈できなかった場合に、どのメッセージ階層でログを出力するかを指定します。有効な値は、debug5、debug4、debug3、debug2、debug1、log、info、notice、warning、またはerrorです。fatalとpanicは指定できません。</td><td>info</td></tr>
152 <p>これらのパラメータをpostgresql.confファイルに設定するには、<a href="http://www.postgresql.org/docs/9.1/static/runtime-config-custom.html#GUC-CUSTOM-VARIABLE-CLASSES">custom_variable_classes</a>にpg_hint_planを加える必要があります。典型的な使用例は以下のようになります。</p>
155 shared_preload_libraries = 'pg_hint_plan'
157 custom_variable_classes = 'pg_hint_plan'
158 pg_hint_plan.parse_messages = 'debug2'
161 <h2 id="restrictions">使用上の注意と制約</h2>
162 <p>pg_hint_planを使用する際には、以下の注意と制約があります。</p>
165 <dd>クエリの前に複数のブロックコメントを記述する場合は、最初のブロックコメントにのみヒントを記述してください。二番目以降のブロックコメントは、ヒントと見なされず無視されます。以下の例では、HashJoin(a b)とSeqScan(a)がヒントと見なされ、IndexScan(a)とMergeJoin(a b)は無視されています。</p>
168 postgres*# <span class="strong">HashJoin(a b)</span>
169 postgres*# <span class="strong">SeqScan(a)</span>
171 postgres-# /*+ IndexScan(a) */
172 postgres-# EXPLAIN SELECT /*+ MergeJoin(a b) */ *
173 postgres-# FROM pgbench_branches b
174 postgres-# JOIN pgbench_accounts a ON b.bid = a.bid
175 postgres-# ORDER BY a.aid;
177 ---------------------------------------------------------------------------------------
178 Sort (cost=31465.84..31715.84 rows=100000 width=197)
180 -> <span class="strong">Hash Join</span> (cost=1.02..4016.02 rows=100000 width=197)
181 Hash Cond: (a.bid = b.bid)
182 -> <span class="strong">Seq Scan on pgbench_accounts a</span> (cost=0.00..2640.00 rows=100000 width=97)
183 -> Hash (cost=1.01..1.01 rows=1 width=100)
184 -> Seq Scan on pgbench_branches b (cost=0.00..1.01 rows=1 width=100)
189 <dt>オブジェクト名の引用符付け</dt>
190 <dd>ヒントに記述するオブジェクト名や別名が閉じ括弧())、二重引用符(")、空白(スペース、タブ、改行のいずれか)を含む場合は、通常のSQL文で使う場合と同じようにダブルクォート(")で囲んでください。二重引用符を含むオブジェクト名の場合は、二重引用符で括ったうえで2つ続けて二重引用符を記述してください。</dd>
192 <dd>スキーマ違いや同一テーブルの複数回使用などでクエリ中に同一名称のテーブルが複数回出現する場合は、テーブルに別名をつけてそれぞれのテーブルを区別してください。以下の例の1つ目のSQL文では、MergeJoin(t1 t1)をヒントに指定したとき、ヒント対象のオブジェクトが特定できずにエラーになっています。2つ目のSQL文では、各テーブルにptやstという別名をつけているため、実行計画作成時にヒントで指定した通りにMerge Joinを選択しています。
195 postgres=# /*+ <span class="strong">MergeJoin(t1 t1)</span>*/
196 postgres-# EXPLAIN SELECT * FROM s1.t1
197 postgres-# JOIN public.t1 ON (s1.t1.id=public.t1.id);
198 INFO: hint syntax error at or near "t1 t1)"
199 <span class="strong">DETAIL: relation name "t1" is ambiguous</span>
200 INFO: hint syntax error at or near "t1 t1)"
201 <span class="strong">DETAIL: relation name "t1" is ambiguous</span>
203 --------------------------------------------------------------------
204 Hash Join (cost=270.00..323.05 rows=1230 width=44)
205 Hash Cond: (s1.t1.id = public.t1.id)
206 -> Seq Scan on t1 (cost=0.00..22.30 rows=1230 width=36)
207 -> Hash (cost=145.00..145.00 rows=10000 width=8)
208 -> Seq Scan on t1 (cost=0.00..145.00 rows=10000 width=8)
211 postgres=# /*+ <span class="strong">MergeJoin(pt st)</span> */
212 postgres-# EXPLAIN SELECT * FROM s1.t1 st
213 postgres-# JOIN public.t1 pt ON (st.id=pt.id);
215 ----------------------------------------------------------------------------------
216 <span class="strong">Merge Join</span> (cost=0.00..421.33 rows=1230 width=44)
217 Merge Cond: (st.id = pt.id)
218 -> Index Scan using t1_id_idx on t1 st (cost=0.00..62.70 rows=1230 width=36)
219 -> Index Scan using t1_pkey on t1 pt (cost=0.00..318.25 rows=10000 width=8)(4 rows)
225 <dd>pg_hint_planでは、ヒントの記述に誤りがあった場合は、誤った記述に関する情報を出力しますがエラー終了しません。誤った記述より前のヒントのみ有効となり、誤った記述以降のヒントを無視してクエリを実行します。</dd>
227 <dd>pg_hint_planでは、不正なヒントの指定があった場合は、不正なヒントに関する情報を出力しますがエラー終了しません。不正なヒントのみ無効となり、その他のヒントは有効なままでクエリを実行します。不正なヒントの例を以下に示します。
229 <li>クエリ中に同じ名称のテーブル名または別名のテーブルがあり、それに対してヒントを指定した。</li>
230 <li>結合方式のヒント、または結合順のヒントのオブジェクト名に、同じ名称を複数回指定した。</li>
233 <dt>影響を与えるGUCパラメータ</dt>
234 <dd>geqo_threshold、from_collapse_limit、およびjoin_collapse_limitによって結合順序が決定する場合は、結合順序のヒントより優先されます。GUCパラメータより結合順序のヒントを優先するには、GUCパラメータの値を結合対象のテーブル数より大きくしてください。</dd>
235 <dt>指定するヒントの種類の重複</dt>
236 <dd>同じオブジェクトに対して同じグループのヒントを重複して指定した場合は、最後に指定したヒントを使用します。</dd>
238 <dd>pg_hint_planでは、PostgreSQLのプランナが候補としてあげる事ができない実行計画をヒントに指定しても、その実行計画を生成することはできません。PostgreSQLのプランナが候補としてあげる事ができない実行計画の例を以下に示します。
240 <li>FULL OUTER JOINではNested Loopは候補パスとして扱われません。</li>
241 <li>WHERE句やJOIN条件などに指定されない列のみを含むインデックスは候補パスとして扱われません。</li>
242 <li>>検索条件にctidを指定しない場合はTid Scanは候補パスとして扱われません。</li>
245 <dt>PREPARE/EXECUTEに対する制限</dt>
246 <dd>libpqプロトコルの拡張問い合わせプロトコルを使い、かつSQL文をPREPARE文とEXECUTE文で実行する場合は、pg_hint_planでは実行計画を制御できません。拡張問い合わせプロトコルで準備された文を使用したい場合は、各種ライブラリが用意しているプリペアド機能を使用してください。例えば、JDBCではクエリの実行に常に拡張問い合わせプロトコルが使われるため、準備した文が必要な場合はPreparedStatementを使用する必要があります。</dd>
247 <dt>継承テーブルに対する制限</dt>
248 <dd>継承テーブルにスキャン方式のヒントを指定する場合は、オブジェクト名として親テーブルの名称または別名を指定してください。全ての子テーブルに同じスキャン方式を選択します。子テーブルごとに別のスキャン方式を指定することはできません。</dd>
249 <dt>VIEWおよびRULEに対する制限</dt>
250 <dd>VIEWやRULEを定義したテーブルを複数用いるときに、各VIEW内のテーブルの別名やRULE書き換え後のクエリのテーブルの別名が重複した場合は、ヒントの対象を区別できません。区別する場合は、各VIEW内のテーブルの別名やRULE書き換え後のクエリのテーブルの別名を重複させないでください。</dd>
251 <dt>マルチステートメントにおける制限</dt>
252 <dd>クエリがマルチステートメントで実行される場合は、先頭のコメントで指定したヒントを全てのクエリで使用します。2つ目以降のクエリに指定したヒントは無視します。psqlコマンドで-cオプションで複数のクエリを指定した場合などにマルチステートメントで実行されます。</dd>
254 <dd>RULEによるクエリ書き換え後によってクエリが複数になる場合は、先頭のコメントで指定したヒントを全てのクエリで使用します。</dd>
255 <dt>PL/pgSQLおける制限</dt>
256 <dd>PL/pgSQLでユーザ定義関数を実装する際に、関数定義内の各クエリの先頭にヒントを指定したとしても、そのヒントは無視します。ユーザ定義関数を実行するSELECTコマンドに指定したヒントを使用します。ただし、PL/pgSQLでは、関数定義内で指定したクエリがそのまま実行されるとは限らないため、ヒントを指定した場合の挙動は保証できません。</dd>
258 <dd>pg_hint_planでは、ECPGで実装したアプリケーションから発行するクエリは、基本的に実行計画を制御できません。これは、CプリプロセッサがCコードに変換するタイミングで、全てのコメントを取り除いてしまうためです。ECPGでも例外的に、動的SQLの先頭にヒントを指定した場合は、実行計画を制御できます。</dd>
259 <dt>psqlのフェッチ件数指定</dt>
260 <dd>psqlコマンドのFETCH_COUNT変数に0より大きな整数値を指定すると、pg_hint_planでは実行計画を制御できなくなります。FETCH_COUNT変数に0より大きな整数値を指定すると、ユーザが指定したクエリの先頭に「DECLARE _psql_cursor NO SCROLL CURSOR FOR」が自動的に追加されてクエリが発行されることにより、ヒントがクエリの先頭ではなくなってしまうためです。</dd>
261 <dt>ヒントによる他の機能への影響</dt>
262 <dd>pg_stat_statementやSQL文フィンガープリントベースのクエリキャッシュなどでは、ヒントが異なれば別のSQL文として扱われます。</dd>
263 <dt>FROM句にVALUESコマンドを指定した場合の制限</dt>
264 <dd>FROM句にVALUESコマンドを指定した場合は、ヒントのオブジェクト名に「*VALUES*」を指定してください。これは、VALUESの結果に別名を指定しても、内部的に「*VALUES*」に名称が置き換えられるためです。このため、複数のVALUESを指定するとヒントの対象を特定できなくなり、実行計画を制御できません。</dd>
266 postgres=# /* <span class="strong">MergeJoin(a *VALUES*)</span> */
267 postgres-# EXPLAIN SELECT *
268 postgres-# FROM pgbench_accounts a
269 postgres-# JOIN (VALUES (1,1),(2,2)) v (vid, vbalance) ON a.aid = v.vid
270 postgres-# ORDER BY a.aid;
272 -------------------------------------------------------------------------------------------------------------
273 Sort (cost=16.62..16.62 rows=2 width=105)
275 -> <span class="strong">Nested Loop</span> (cost=0.00..16.61 rows=2 width=105)
276 -> Values Scan on <span class="strong">"*VALUES*"</span> (cost=0.00..0.03 rows=2 width=8)
277 -> Index Scan using pgbench_accounts_pkey on pgbench_accounts a (cost=0.00..8.28 rows=1 width=97)
278 Index Cond: (aid = "*VALUES*".column1)
285 <h2 id="seealso">関連項目</h2>
286 <h3 id="postgresql_document">PostgreSQLドキュメント</h3>
287 <a href="http://www.postgresql.org/docs/9.1/static/sql-explain.html">EXPLAIN</a>
288 <a href="http://www.postgresql.org/docs/9.1/static/sql-set.html">SET</a>
289 <a href="http://www.postgresql.org/docs/9.1/static/runtime-config.html">サーバの設定</a>
292 <div class="navigation">
293 <a href="pg_hint_plan-ja.html">pg_hint_plan</a>
296 <p class="footer">Copyright (c) 2012, NIPPON TELEGRAPH AND TELEPHONE CORPORATION</p>
299 <script type="text/javascript">
300 var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
301 document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
302 </script><script src="pg_statsinfo-ja_files/ga.js" type="text/javascript"></script>
303 <script type="text/javascript">
305 var pageTracker = _gat._getTracker("UA-10244036-6");
306 pageTracker._trackPageview();