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を実行してください。make uninstallはPostgreSQLをインストールしたOSユーザで実行してください。</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>先に結合して欲しいオブジェクトから順にオブジェクト名または別名を指定してください。複数の結合順序のヒントを指定した場合は、最後に指定したヒントが適用されます。クエリ中に複数の問い合わせブロックがあり、それぞれに結合順を指定したい場合は、それぞれの結合順を1つのLeadingヒントに連続して指定してください。</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>
135 <p>Setヒントに<a href="#hint-GUC">pg_hint_planのGUCパラメータ</a>を指定することはできますが、期待通りの動作をしないため、指定しないことをおすすめします。指定した場合の実際の動作は、<a href="#restrictions">使用上の注意と制約</a>を参照してください。</p>
137 <h3 id="hint-GUC">pg_hint_planのGUCパラメータ</h3>
138 <p>pg_hint_planの動作を制御するGUCパラメータを以下に記述します。</p>
142 <tr><th>GUCパラメータ</th><th>説明</th><th>デフォルト値</th></tr>
145 <tr><td>pg_hint_plan.enable</td>
146 <td>pg_hint_planの機能を有効または無効にします。</td><td>on</td></tr>
147 <tr><td>pg_hint_plan.debug_print</td>
148 <td>pg_hint_planのデバッグ出力を有効にします。メッセージはLOGメッセージレベルで出力されますので、デフォルトではサーバログに出力され、クライアントには渡されません。</td><td>off</td></tr>
149 <tr><td>pg_hint_plan.parse_messages</td>
150 <td>指定したヒントを解釈できなかった場合に、どのメッセージ階層でログを出力するかを指定します。有効な値は、debug5、debug4、debug3、debug2、debug1、log、info、notice、warning、またはerrorです。fatalとpanicは指定できません。</td><td>info</td></tr>
153 <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>
156 shared_preload_libraries = 'pg_hint_plan'
158 custom_variable_classes = 'pg_hint_plan'
159 pg_hint_plan.parse_messages = 'debug2'
162 <h2 id="restrictions">使用上の注意と制約</h2>
163 <p>pg_hint_planを使用する際には、以下の注意と制約があります。</p>
166 <dd>クエリの前に複数のブロックコメントを記述する場合は、最初のブロックコメントにのみヒントを記述してください。二番目以降のブロックコメントは、ヒントと見なされず無視されます。以下の例では、HashJoin(a b)とSeqScan(a)がヒントと見なされ、IndexScan(a)とMergeJoin(a b)は無視されています。</p>
169 postgres*# <span class="strong">HashJoin(a b)</span>
170 postgres*# <span class="strong">SeqScan(a)</span>
172 postgres-# /*+ IndexScan(a) */
173 postgres-# EXPLAIN SELECT /*+ MergeJoin(a b) */ *
174 postgres-# FROM pgbench_branches b
175 postgres-# JOIN pgbench_accounts a ON b.bid = a.bid
176 postgres-# ORDER BY a.aid;
178 ---------------------------------------------------------------------------------------
179 Sort (cost=31465.84..31715.84 rows=100000 width=197)
181 -> <span class="strong">Hash Join</span> (cost=1.02..4016.02 rows=100000 width=197)
182 Hash Cond: (a.bid = b.bid)
183 -> <span class="strong">Seq Scan on pgbench_accounts a</span> (cost=0.00..2640.00 rows=100000 width=97)
184 -> Hash (cost=1.01..1.01 rows=1 width=100)
185 -> Seq Scan on pgbench_branches b (cost=0.00..1.01 rows=1 width=100)
190 <dt>オブジェクト名の引用符付け</dt>
191 <dd>ヒントに記述するオブジェクト名や別名が閉じ括弧())、二重引用符(")、空白(スペース、タブ、改行のいずれか)を含む場合は、通常のSQL文で使う場合と同じようにダブルクォート(")で囲んでください。二重引用符を含むオブジェクト名の場合は、二重引用符で括ったうえで2つ続けて二重引用符を記述してください。</dd>
193 <dd>スキーマ違いや同一テーブルの複数回使用などでクエリ中に同一名称のテーブルが複数回出現する場合は、テーブルに別名をつけてそれぞれのテーブルを区別してください。以下の例の1つ目のSQL文では、MergeJoin(t1 t1)をヒントに指定したとき、ヒント対象のオブジェクトが特定できずにエラーになっています。2つ目のSQL文では、各テーブルにptやstという別名をつけているため、実行計画作成時にヒントで指定した通りにMerge Joinを選択しています。
196 postgres=# /*+ <span class="strong">HashJoin(t1 t1)</span>*/
197 postgres-# EXPLAIN SELECT * FROM s1.t1
198 postgres-# JOIN public.t1 ON (s1.t1.id=public.t1.id);
199 INFO: hint syntax error at or near "HashJoin(t1 t1)"
200 <span class="strong">DETAIL: Relation name "t1" is ambiguous.</span>
202 ------------------------------------------------------------------
203 Merge Join (cost=337.49..781.49 rows=28800 width=8)
204 Merge Cond: (s1.t1.id = public.t1.id)
205 -> Sort (cost=168.75..174.75 rows=2400 width=4)
207 -> Seq Scan on t1 (cost=0.00..34.00 rows=2400 width=4)
208 -> Sort (cost=168.75..174.75 rows=2400 width=4)
209 Sort Key: public.t1.id
210 -> Seq Scan on t1 (cost=0.00..34.00 rows=2400 width=4)
213 postgres=# /*+ <span class="strong">HashJoin(pt st)</span> */
214 postgres-# EXPLAIN SELECT * FROM s1.t1 st
215 postgres-# JOIN public.t1 pt ON (st.id=pt.id);
217 ---------------------------------------------------------------------
218 <span class="strong">Hash Join</span> (cost=64.00..1112.00 rows=28800 width=8)
219 Hash Cond: (st.id = pt.id)
220 -> Seq Scan on t1 st (cost=0.00..34.00 rows=2400 width=4)
221 -> Hash (cost=34.00..34.00 rows=2400 width=4)
222 -> Seq Scan on t1 pt (cost=0.00..34.00 rows=2400 width=4)
229 <dd>pg_hint_planでは、ヒントの記述に誤りがあった場合は、誤った記述に関する情報を出力しますがエラー終了しません。誤った記述より前のヒントのみ有効となり、誤った記述以降のヒントを無視してクエリを実行します。</dd>
231 <dd>pg_hint_planでは、不正なヒントの指定があった場合は、不正なヒントに関する情報を出力しますがエラー終了しません。不正なヒントのみ無効となり、その他のヒントは有効なままでクエリを実行します。不正なヒントの例を以下に示します。
233 <li>クエリ中に同じ名称のテーブル名または別名のテーブルがあり、それに対してヒントを指定した。</li>
234 <li>結合方式のヒント、または結合順のヒントのオブジェクト名に、同じ名称を複数回指定した。</li>
237 <dt>ネストしたブロックコメント</dt>
238 <dd>pg_hint_planでは、ヒントを指定したブロックコメントにネストしたブロックコメントを含めることができません。ネストしたブロックコメントを含めた場合は、誤った記述に関する情報を出力しますがエラー終了しません。全てのヒントを無視してクエリを実行します。</dd>
239 <dt>影響を与えるGUCパラメータ</dt>
240 <dd>FROMリストの数がfrom_collapse_limitの設定値以上の場合、またはFROMリストの数がjoin_collapse_limitの設定値より大きい場合は、結合順序のヒントが無視されます。また、FROMリストの数がgeqo_thresholdの設定値以上の場合は、結合順序のヒント、および結合方式のヒントが無視されます。ヒントが使われるようにするには、これらのGUCパラメータの値を大きくしてください。</dd>
241 <dt>指定するヒントの種類の重複</dt>
242 <dd>同じオブジェクトに対して同じグループのヒントを重複して指定した場合は、最後に指定したヒントを使用します。</dd>
244 <dd>pg_hint_planでは、PostgreSQLのプランナが候補としてあげる事ができない実行計画をヒントに指定しても、その実行計画を生成することはできません。PostgreSQLのプランナが候補としてあげる事ができない実行計画の例を以下に示します。
246 <li>FULL OUTER JOINではNested Loopは候補パスとして扱われません。</li>
247 <li>WHERE句やJOIN条件などに指定されない列のみを含むインデックスは候補パスとして扱われません。</li>
248 <li>検索条件にctidを指定しない場合はTid Scanは候補パスとして扱われません。</li>
251 <dt>継承テーブルに対する制限</dt>
252 <dd>継承テーブルにスキャン方式のヒントを指定する場合は、オブジェクト名として親テーブルの名称または別名を指定してください。全ての子テーブルに同じスキャン方式を選択します。子テーブルごとに別のスキャン方式を指定することはできません。</dd>
253 <dt>VIEWおよびRULEに対する制限</dt>
254 <dd>VIEWやRULEを定義したテーブルを複数用いるときに、各VIEW内のテーブルの別名やRULE書き換え後のクエリのテーブルの別名が重複した場合は、ヒントの対象を区別できません。区別する場合は、各VIEW内のテーブルの別名やRULE書き換え後のクエリのテーブルの別名を重複させないでください。</dd>
255 <dt>マルチステートメントにおける制限</dt>
256 <dd>クエリがマルチステートメントで実行される場合は、先頭のブロックコメントで指定したヒントを全てのクエリで使用します。2つ目以降のクエリに指定したヒントは無視します。psqlコマンドで-cオプションで複数のクエリを指定した場合などにマルチステートメントで実行されます。</dd>
258 <dd>RULEによるクエリ書き換え後によってクエリが複数になる場合は、先頭のブロックコメントで指定したヒントを全てのクエリで使用します。</dd>
259 <dt>PL/pgSQLにおける制限</dt>
260 <dd>PL/pgSQLでユーザ定義関数を実装する際に、関数定義内の各クエリの先頭にヒントを指定したとしても、そのヒントは無視します。ユーザ定義関数を実行するSELECTコマンドに指定したヒントを使用します。ただし、PL/pgSQLでは、関数定義内で指定したクエリがそのまま実行されるとは限らないため、ヒントを指定した場合の挙動は保証できません。</dd>
262 <dd>pg_hint_planでは、ECPGで実装したアプリケーションから発行するクエリは、基本的に実行計画を制御できません。これは、CプリプロセッサがCコードに変換するタイミングで、全てのブロックコメントを取り除いてしまうためです。ECPGでも例外的に、動的SQLの先頭にヒントを指定した場合は、実行計画を制御できます。</dd>
263 <dt>psqlのフェッチ件数指定</dt>
264 <dd>psqlコマンドのFETCH_COUNT変数に0より大きな整数値を指定すると、pg_hint_planでは実行計画を制御できなくなります。FETCH_COUNT変数に0より大きな整数値を指定すると、ユーザが指定したクエリの先頭に「DECLARE _psql_cursor NO SCROLL CURSOR FOR」が自動的に追加されてクエリが発行されることにより、ヒントがクエリの先頭ではなくなってしまうためです。</dd>
265 <dt>ヒントによる他の機能への影響</dt>
266 <dd>pg_stat_statementやSQL文フィンガープリントベースのクエリキャッシュなどでは、ヒントが異なれば別のSQL文として扱われます。</dd>
267 <dt>FROM句にVALUESコマンドを指定した場合の制限</dt>
268 <dd>FROM句にVALUESコマンドを指定した場合は、ヒントのオブジェクト名に「*VALUES*」を指定してください。これは、VALUESの結果に別名を指定しても、PostgreSQL本体側で「*VALUES*」に名称が置き換えられるためです。このため、複数のVALUESを使用する場合は、ヒントの対象を特定できないため、実行計画を制御できません。</dd>
270 postgres=# /*+ <span class="strong">MergeJoin(a *VALUES*)</span> */
271 postgres-# EXPLAIN SELECT *
272 postgres-# FROM pgbench_accounts a
273 postgres-# JOIN (VALUES (1,1),(2,2)) <span class="strong">v</span> (vid, vbalance) ON a.aid = v.vid
274 postgres-# ORDER BY a.aid;
276 ---------------------------------------------------------------------------------------------------------------
277 <span class="strong">Merge Join</span> (cost=0.04..4497.33 rows=2 width=105)
278 Merge Cond: (a.aid = "*VALUES*".column1)
279 -> Index Scan using pgbench_accounts_pkey on pgbench_accounts a (cost=0.00..4247.26 rows=100000 width=97)
280 -> Sort (cost=0.04..0.04 rows=2 width=8)
281 Sort Key: "*VALUES*".column1
282 -> Values Scan on <span class="strong">"*VALUES*"</span> (cost=0.00..0.03 rows=2 width=8)
287 <dd>Setヒントに<a href="#hint-GUC">pg_hint_planのGUCパラメータ</a>を指定することはできますが、期待通りの動作をしないため、指定しないことをおすすめします。指定した場合の実際の動作を、以下に示します。
289 <li>pg_hint_plan.enableおよびpg_hint_plan.debug_printを指定した場合は、無視されます。</li>
290 <li>pg_hint_plan.message_levelを指定した場合は、構文エラーと一部のSetヒントのエラーについてはクエリ開始時の設定レベルで出力され、それ以外のメッセージについてはSetヒントで指定したレベルで出力されます。</li>
294 <dd>ヒントに誤りがあった場合に出力されるメッセージのレベルは、基本的には<a href="#hint-GUC"></a>に指定したレベルです。ただし、ヒントに指定したオブジェクトの長さが、識別子の最大長(デフォルトでは63バイト)を超えた際に切り詰めた場合は、NOTICEで出力します。</dd>
295 <dt>内部的にSPI呼び出しを伴うクエリにおける制限</dt>
296 <dd>pg_hint_planでは、実行計画の作成中に内部的にSPIによるクエリの実行が行なわれるクエリは、部分的にのみプランが制御されてしまいます。ユーザ定義関数をSQLやPL/pgSQLで作成した場合でも、内部的にはSPIが呼ばれるため、注意が必要です。例えば、IMMUTABLEを指定したSQL関数などがこの制限にふれます。この場合は、STABLEもしくはVOLATILEに変更することでプランを制御できるようになります。</dd>
300 <h2 id="seealso">関連項目</h2>
301 <h3 id="postgresql_document">PostgreSQLドキュメント</h3>
302 <a href="http://www.postgresql.org/docs/9.1/static/sql-explain.html">EXPLAIN</a>
303 <a href="http://www.postgresql.org/docs/9.1/static/sql-set.html">SET</a>
304 <a href="http://www.postgresql.org/docs/9.1/static/runtime-config.html">サーバの設定</a>
307 <div class="navigation">
308 <a href="pg_hint_plan-ja.html">pg_hint_plan</a>
311 <p class="footer">Copyright (c) 2012, NIPPON TELEGRAPH AND TELEPHONE CORPORATION</p>
314 <script type="text/javascript">
315 var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
316 document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
317 </script><script src="pg_statsinfo-ja_files/ga.js" type="text/javascript"></script>
318 <script type="text/javascript">
320 var pageTracker = _gat._getTracker("UA-10244036-6");
321 pageTracker._trackPageview();