pg_hint_plan -- 実行計画を示すヒントをクエリに指定することで、SQL文やGUCパラメータを変えずに実行計画を制御します。
PostgreSQLのプランナははコストベースでのオプティマイズを行なっており、SQL文と統計情報を元に可能な実行計画のコストを見積もり、最もコストの低い実行計画を選択します。プランナは可能な限りよい実行計画を作成しようとしますが、例えばカラム間の相関関係などは考慮しないため、複雑なクエリでは常に最適なプランを選択するとは限りません。
pg_hint_planを用いると、ヒントでスキャン方式や結合方式を指定することで、SQL文やGUCパラメータを変更することなく実行計画を制御することができます。
pg_hint_planの機能について説明するにあたり、まず文中で使用されている用語について説明します。
用語 | 説明 |
---|---|
ヒント句 | 実行計画を制御するための情報です。 |
ヒント | 実行計画を制御したいクエリに適用するヒント句を列挙したものです。 |
ヒントは二つの方法で指定することができます。
特殊なSQLブロックコメント内にヒントを記述します。
ヒント用のテーブルにヒントを登録します。
特定のアプリケーションではヒントをコメントで指定することができないため、「テーブルでの指定」でヒントを指定します。なお、「コメントでの指定」と異なり、アプリケーションのソースコードに手を入れずに指定するヒントを変更することができます。
指定したいヒントを、実行計画を制御したいクエリの先頭または途中のSQLブロックコメントの中に記述します。
ヒント用コメントと通常のコメントを区別するために、ヒント用のブロックコメントは「/*+」で始めます。ヒントの対象は、カッコ内にオブジェクト名または別名で指定します。オブジェクト名は、スペース、タブ、または改行のいずれかで区切って指定します。
以下の例では、HashJoinとSeqScanヒント句により、pgbench_accountsテーブルに対するSeq Scanの結果をHash Joinする実行計画が選択されています。なおかつ、Setヒント句によりこのクエリの実行計画を作成する間だけrandom_page_costが2.0に変更されています。
postgres=# EXPLAIN (VERBOSE, COSTS) postgres-# /*+ postgres*# SeqScan(a) postgres*# HashJoin(a b) postgres*# Set(random_page_cost 2.0) postgres*# */ postgres-# SELECT * postgres-# FROM pgbench_accounts a postgres-# JOIN pgbench_branches b postgres-# ON a.bid = b.bid postgres-# ORDER BY a.aid postgres-# LIMIT 10; QUERY PLAN ---------------------------------------------------------------------------------------------------- Limit (cost=6176.99..6177.01 rows=10 width=461) Output: a.aid, a.bid, a.abalance, a.filler, b.bid, b.bbalance, b.filler, a.aid -> Sort (cost=6176.99..6426.99 rows=100000 width=461) Output: a.aid, a.bid, a.abalance, a.filler, b.bid, b.bbalance, b.filler, a.aid Sort Key: a.aid -> Hash Join (cost=1.02..4016.02 rows=100000 width=461) Output: a.aid, a.bid, a.abalance, a.filler, b.bid, b.bbalance, b.filler, a.aid Hash Cond: (a.bid = b.bid) -> Seq Scan on public.pgbench_accounts a (cost=0.00..2640.00 rows=100000 width=97) Output: a.aid, a.bid, a.abalance, a.filler -> Hash (cost=1.01..1.01 rows=1 width=364) Output: b.bid, b.bbalance, b.filler -> Seq Scan on public.pgbench_branches b (cost=0.00..1.01 rows=1 width=364) Output: b.bid, b.bbalance, b.filler (14 rows) postgres=#
指定したいヒントを、実行計画を制御したいクエリと併せてヒント用のテーブルに登録します。
デフォルトでは無効なので、テーブルで指定したヒントは適用されません。そのため、ヒントをテーブルで指定する場合は、pg_hint_planのGUCパラメータpg_hint_plan.enable_hint_tableの設定を変更します。
ヒント用のテーブルは「hint_plan.hints」です。hint_plan.hintsテーブルには、以下の情報を登録します。
列名 | 説明 |
---|---|
id | ユーザがヒントを識別するための番号です。連番型ですので、新しいヒントを登録するときにはこの列を指定しないでください。 |
norm_query_string | 実行計画を制御したいクエリを指定します。対象のクエリに定数があるときは、下記の例のように「?」に置き換えます。キーワード間の空白の数が、登録するクエリと実行するクエリで異なると別のSQL文として扱われます。 |
application_name | ヒント適用対象のアプリケーション名を指定します。下記の例では「psql」から実行されたクエリのみがヒント適用対象となります。全てのアプリケーションにヒントを適用したいときは、空文字列を登録します。アプリケーション名は、セッションの「application_name」GUCパラメータと等しいか判断します。 |
hints | ヒントを指定します。SQLコメント記号を除いた内容のみを登録します。 |
ヒントの登録情報を変更する場合は、変更したい登録情報のidを指定して登録情報を更新してください。 ヒントの登録を解除する場合は、解除したい登録情報のidを指定してテーブルから削除してください。
以下の例では、ヒントの登録、ヒント登録情報の変更、ヒントの解除の順に、クエリの実行結果を示しています。
postgres=# INSERT INTO hint_plan.hints(norm_query_string, application_name, hints) postgres-# VALUES ( postgres(# 'EXPLAIN (COSTS false) SELECT * FROM t1 WHERE t1.id = ?;', postgres(# '', postgres(# 'SeqScan(t1)' postgres(# ); INSERT 0 1 postgres=# UPDATE hint_plan.hints postgres-# SET hints = 'IndexScan(t1)' postgres-# WHERE id = 1; UPDATE 1 postgres=# DELETE FROM hint_plan.hints postgres-# WHERE id = 1; DELETE 1 postgres=#
なお、ヒントの登録や変更や解除はスーパーユーザでのみ可能です。一般ユーザでヒントの登録や変更や解除を実施したい場合は、スーパーユーザから一般ユーザにhint_plan.hintsテーブルの各権限を付与してください。
以下の例では、hint_plan.hintsテーブルに対してINSERT権限を持たない一般ユーザがヒントの登録を実施しようとしたときの結果を示しています。
postgres=> INSERT INTO hint_plan.hints(norm_query_string, application_name, hints) postgres-> VALUES ( postgres(> 'EXPLAIN (COSTS false) SELECT * FROM t1 WHERE t1.id = ?;', postgres(> '', postgres(> 'SeqScan(t1)' postgres(> ); ERROR: permission denied for relation hints postgres=>
以下の例では、テーブルに登録した「コメントでの指定」の例と同じヒントと、登録したクエリの実行結果を示しています。
postgres=# SELECT * FROM hint_plan.hints; id | norm_query_string | application_name | hints ----+----------------------------+------------------+-------------------------------------------------- 1 | EXPLAIN (VERBOSE, COSTS) +| psql | SeqScan(a)HashJoin(a b)Set(random_page_cost 2.0) | SELECT * +| | | FROM pgbench_accounts a+| | | JOIN pgbench_branches b+| | | ON a.bid = b.bid +| | | ORDER BY a.aid +| | | LIMIT ?; +| | | | | ... postgres=# SET pg_hint_plan.enable_hint_table TO on; postgres=# EXPLAIN (VERBOSE, COSTS) postgres-# SELECT * postgres-# FROM pgbench_accounts a postgres-# JOIN pgbench_branches b postgres-# ON a.bid = b.bid postgres-# ORDER BY a.aid postgres-# LIMIT 10; QUERY PLAN ---------------------------------------------------------------------------------------------------- Limit (cost=6176.99..6177.01 rows=10 width=461) Output: a.aid, a.bid, a.abalance, a.filler, b.bid, b.bbalance, b.filler, a.aid -> Sort (cost=6176.99..6426.99 rows=100000 width=461) Output: a.aid, a.bid, a.abalance, a.filler, b.bid, b.bbalance, b.filler, a.aid Sort Key: a.aid -> Hash Join (cost=1.02..4016.02 rows=100000 width=461) Output: a.aid, a.bid, a.abalance, a.filler, b.bid, b.bbalance, b.filler, a.aid Hash Cond: (a.bid = b.bid) -> Seq Scan on public.pgbench_accounts a (cost=0.00..2640.00 rows=100000 width=97) Output: a.aid, a.bid, a.abalance, a.filler -> Hash (cost=1.01..1.01 rows=1 width=364) Output: b.bid, b.bbalance, b.filler -> Seq Scan on public.pgbench_branches b (cost=0.00..1.01 rows=1 width=364) Output: b.bid, b.bbalance, b.filler (14 rows) postgres=#
ヒントをコメントとテーブルの両方で指定した場合、テーブルで指定したヒントが適用され、コメントで指定したヒントは無視されます。
以下の例では、コメントでヒントを指定して実行計画を制御しているクエリに対して、テーブルに空文字列のヒントを登録しています。テーブルで指定したヒントが優先されるので、コメントで指定したヒントを取り消すことができます。
postgres=# select * from hint_plan.hints; id | norm_query_string | application_name | hints ----+--------------------------------------------+------------------+------- 1 | EXPLAIN (VERBOSE, COSTS) +| psql | | /*+ +| | | HashJoin(a b) +| | | SeqScan(a) +| | | */ +| | | SELECT * +| | | FROM pgbench_accounts a +| | | JOIN pgbench_branches b ON a.bid = b.bid+| | | ORDER BY a.aid; | | ... postgres=# EXPLAIN (VERBOSE, COSTS) postgres-# /*+ postgres*# HashJoin(a b) postgres*# SeqScan(a) postgres*# */ postgres-# SELECT * postgres-# FROM pgbench_accounts a postgres-# JOIN pgbench_branches b ON a.bid = b.bid postgres-# ORDER BY a.aid; QUERY PLAN ---------------------------------------------------------------------------------------------------------------------- Nested Loop (cost=0.00..5750.47 rows=100000 width=461) Output: a.aid, a.bid, a.abalance, a.filler, b.bid, b.bbalance, b.filler, a.aid Join Filter: (a.bid = b.bid) -> Index Scan using pgbench_accounts_pkey on public.pgbench_accounts a (cost=0.00..4249.45 rows=100000 width=97) Output: a.aid, a.bid, a.abalance, a.filler -> Materialize (cost=0.00..1.01 rows=1 width=364) Output: b.bid, b.bbalance, b.filler -> Seq Scan on public.pgbench_branches b (cost=0.00..1.01 rows=1 width=364) Output: b.bid, b.bbalance, b.filler (9 rows)
pg_hint_planで使えるヒント句の種類は、スキャン方式と結合方式、結合順序、見積もり件数補正、並列実行の設定、GUCパラメータの6グループです。各グループの具体的なヒント句は、ヒント句一覧を参照してください。
あるオブジェクトでどのスキャン方式を選択するかを指定できるヒント句のグループです。「SeqScan」や「IndexScan」などを含みます。
スキャン方式を指定できるオブジェクトは、通常のテーブル、継承テーブル、UNLOGGEDテーブル、一時テーブル、システムカタログです。スキャン方式を指定できないオブジェクトは、外部テーブル、テーブル関数、VALUESコマンド結果、CTE(共通テーブル式)、ビュー、副問い合わせ結果です。
特定のオブジェクトについてあるスキャン方式を選択して欲しい場合は、そのスキャン方式のヒント句と、対象となるオブジェクトの名前を指定します。逆に、特定のオブジェクトについてあるスキャン方式を選択して欲しくない場合は、Noで始まるヒント句を指定します。同じオブジェクトに対して複数のスキャン方式のヒント句を指定した場合は、最後に指定したヒント句が適用されます。
あるオブジェクトの組み合わせでどの結合方式を選択するかを指定できるヒント句のグループです。「MergeJoin」や「NestLoop」などを含みます。
結合方式を指定できるオブジェクトは、通常のテーブル、継承テーブル、UNLOGGEDテーブル、一時テーブル、外部テーブル、システムカタログ、テーブル関数、VALUESコマンド結果、CTE(共通テーブル式)です。結合方式を指定できないオブジェクトは、ビュー、副問い合わせ結果です。
特定のオブジェクトの組み合わせについてある結合方式を選択して欲しい場合は、その結合方式のヒント句と、対象となる2つ以上のオブジェクトの名前を指定します。逆に、特定のオブジェクトの組み合わせについてある結合方式を選択して欲しくない場合は、Noで始まるヒント句を指定します。同じオブジェクトの組み合わせに対して複数の結合方式のヒント句を指定した場合は、最後に指定したヒント句が適用されます。
あるオブジェクトの組み合わせでどのような順番で結合するかを指定できるヒント句のグループです。「Leading」のみを含みます。
結合順序を指定できるオブジェクトは結合方式と同じです。
先に結合して欲しいオブジェクトから順にオブジェクト名または別名を指定します。同じ問合せブロックのオブジェクトに対して複数の結合順序のヒント句を指定した場合は、最後に指定したヒント句が適用されます。
結合対象のテーブルが3つ以上ある場合、結合方式のヒント句を指定したとしてもコスト見積もりによっては対象のテーブルが直接結合されないことがあります。対象のテーブルが直接結合されない場合は、結合順序のヒント句を併せて指定します。
以下の例では、table1とtable2を直接結合する場合はNested Loopを、table1とtable2とtable3を結合する場合はMerge Joinを指定しています。また、コスト見積もりによってはtable1とtable2が直接結合されない場合を避けるため、table1とtable2を結合してからtable3を結合するようにLeadingヒント句を併用しています。
postgres=# /*+ postgres*# NestLoop(t1 t2) postgres*# MergeJoin(t1 t2 t3) postgres*# Leading(t1 t2 t3) postgres*# */ postgres-# SELECT * FROM table1 t1 postgres-# JOIN table table2 t2 ON (t1.key = t2.key) postgres-# JOIN table table3 t3 ON (t2.key = t3.key); ...
上記の結合順序の指定を行なった際にはプランナの都合により結合方向(外部表/内部表もしくは駆動表/被駆動表の別)が期待とは異なるものになる場合があります。このような状況に対して結合方向を固定したい場合はもうひとつの書式を使う必要があります。
postgres=# /*+ Leading((t1 (t2 t3))) */ SELECT...
この書式では2つの要素を丸括弧で囲ったものがネストする形になっており、一つの括弧内では1つ目の要素が外部/駆動表、2番めの要素が内部/被駆動表として結合されます。
あるオブジェクトの結合結果の件数を補正できるヒント句のグループです。「Rows」のみを含みます。
見積もり件数補正対象として指定できるオブジェクトは結合方式と同じです。補正できるのは結合結果の見積もり件数だけで、スキャンの見積もり件数を補正することはできません。
以下の例では、テーブルaとテーブルbの結合結果の件数を、ヒント句で指定した値に補正しています。
postgres=# /*+ Rows(a b #10) */ postgres-# EXPLAIN SELECT * postgres-# FROM pgbench_branches b postgres-# JOIN pgbench_accounts a ON b.bid = a.bid postgres-# WHERE aid < 20 postgres-# ORDER BY a.aid; QUERY PLAN -------------------------------------------------------------------------------------------------------- Nested Loop (cost=0.29..9.92 rows=10 width=461) Join Filter: (b.bid = a.bid) -> Index Scan using pgbench_accounts_pkey on pgbench_accounts a (cost=0.29. .8.62 rows=19 width=97) Index Cond: (aid < 20) -> Materialize (cost=0.00..1.01 rows=1 width=364) -> Seq Scan on pgbench_branches b (cost=0.00..1.01 rows=1 width=364) (6 行)
スキャンの並列実行の方法を指定します。最初のパラメータは対象とするオブジェクトの指定で、2番目に指定する数だけ並列処理ワーカを起動するように指定します。
3番目のパラメータは強制の程度を指定します。 "soft" は max_parallel_workers_per_gather のみを変更して適用はプランナに任せます。"hard" は他のプランナ変数も変更するなどしてワーカ数を強制します。
以下の例では、テーブル c1 とテーブル c2 の結合で各々異なるワーカ数を強制します。
postgres=# explain /*+ Parallel(c1 3 hard) Parallel(c2 5 hard) */ select c2.a from c1 join c2 on (c1.a = c2.a); QUERY PLAN ------------------------------------------------------------------------------- Hash Join (cost=2.86..11406.38 rows=101 width=4) Hash Cond: (c1.a = c2.a) -> Gather (cost=0.00..7652.13 rows=1000101 width=4) Workers Planned: 3 -> Parallel Seq Scan on c1 (cost=0.00..7652.13 rows=322613 width=4) -> Hash (cost=1.59..1.59 rows=101 width=4) -> Gather (cost=0.00..1.59 rows=101 width=4) Workers Planned: 5 -> Parallel Seq Scan on c2 (cost=0.00..1.59 rows=59 width=4)
そのクエリの実行計画を作成している間だけGUCパラメータを変更できるヒント句のグループです。「Set」のみを含みます。
設定したいGUCパラメータとそのパラメータの値を指定します。指定できるGUCパラメータは問い合わせ計画のGUCパラメータのみです。同じGUCパラメータのヒント句を2回以上指定した場合は、最後に指定したヒント句が適用されます。
Setヒント句に問い合わせ計画のGUCパラメータ以外を指定した場合の動作は保証できません。問い合わせ計画以外のGUCパラメータを指定した場合の例の一つとして、pg_hint_planのGUCパラメータを指定した場合の動作を、以下に示します。
pg_hint_planの動作を制御するGUCパラメータを以下に記述します。
GUCパラメータ | 説明 | デフォルト値 |
---|---|---|
pg_hint_plan.enable_hint | pg_hint_planの機能を有効または無効にします。 | on |
pg_hint_plan.enable_hint_table | ヒントをテーブルで指定する機能を有効または無効にします。 | off |
pg_hint_plan.parse_messages | 指定したヒントを解釈できなかった場合のログメッセージのレベルを指定します。有効な値は、debug5、debug4、debug3、debug2、debug1、log、info、notice、warning、またはerrorです。 | INFO |
pg_hint_plan.debug_print | 動作状況を示すログメッセージの出力を制御します。指定可能な値は off, on, verbose, detailed です。 | off |
pg_hint_plan.message_level | 動作ログメッセージのログレベルを指定します。有効な値は、debug5、debug4、debug3、debug2、debug1、log、info、notice、warning、またはerrorです。 | LOG |
pg_hint_planのインストール方法について説明します。
pg_hint_planをソースコードからビルドする場合、pg_hint_planのソースを展開したディレクトリでmake → make installの順に実行します。make installはPostgreSQLをインストールしたOSユーザで実行します。なお、pg_hint_planのビルドにはpgxsを使用するので、RPM版のPostgreSQLを使用している環境では、postgresql-devel パッケージが必要です。
以下にビルドの例を示します。
$ tar xzvf pg_hint_plan-1.0.0.tar.gz $ cd pg_hint_plan-1.0.0 $ make $ su # make install
pg_hint_planはPostgreSQLの拡張(EXTENSION)を使用しているので、pg_hint_planを利用するデータベースにスーパーユーザもしくはそのデータベースの所有者で接続してCREATE EXTENSIONコマンドを実行します。
以下にデータベースへの登録の例を示します。 dbnameは対象となるデータベース名を意味します。
$ psql -d dbname -c "CREATE EXTENSION pg_hint_plan"
特定のセッションでのみpg_hint_planを使う場合は、以下の例のようにpg_hint_planの共有ライブラリをLOADコマンドでロードします。一般ユーザで利用する場合は$libdir/pluginsにもインストールする必要があるので注意してください。
postgres=# LOAD 'pg_hint_plan'; LOAD postgres=#
全てのセッションでpg_hint_planを有効にするには、shared_preload_libraries GUCパラメータに'pg_hint_plan'を追加してからサーバを再起動します。
注意: pg_hint_planをデータベースに登録せずに、ロード後にSQL文を実行すると以下に示す例のようなエラーとなります。 pg_hint_planを使うときは、データベースへの登録を忘れないように注意してください。
postgres=# EXPLAIN SELECT * FROM pgbench_accounts a WHERE aid = 1; ERROR: schema "hint_plan" does not exist LINE 1: SELECT hints FROM hint_plan.hints WHERE norm_query_string... ^ QUERY: SELECT hints FROM hint_plan.hints WHERE norm_query_string = $1 AND ( application_name = $2 OR application_name = '' ) ORDER BY application_name DESC postgres=#
pg_hint_planをアンインストールするときは、以下の手順を実行します。 dbnameは対象となるデータベース名を意味します。
$ cd pg_hint_plan-1.0.0 $ su # make uninstall
$ psql -d dbname -c "DROP EXTENSION pg_hint_plan" $ psql -d dbname -c "DROP SCHEMA hint_plan"
以下にいくつかのトピックに関してヒントの動作について説明します。
指定したヒントが無視される例を以下に示します。
postgres=# SELECT bid AS "BID" postgres-# /*+ postgres*# SeqScan(b) postgres*# */ postgres-# FROM pgbench_branches b; ...
postgres=# WITH avg_aid AS ( postgres(# SELECT avg(aid) FROM pgbench_history h postgres(# WHERE delta >= 0 postgres(# ) postgres-# /*+ postgres*# SeqScan(h) postgres*# */ postgres-# SELECT * FROM avg_aid; ...
postgres=# /*+ postgres*# HashJoin(a b) postgres*# SeqScan(a) postgres*# */ postgres-# /*+ IndexScan(a) */ postgres-# EXPLAIN SELECT /*+ MergeJoin(a b) */ * postgres-# FROM pgbench_branches b postgres-# JOIN pgbench_accounts a ON b.bid = a.bid postgres-# ORDER BY a.aid; QUERY PLAN --------------------------------------------------------------------------------------- Sort (cost=31465.84..31715.84 rows=100000 width=197) Sort Key: a.aid -> Hash Join (cost=1.02..4016.02 rows=100000 width=197) Hash Cond: (a.bid = b.bid) -> Seq Scan on pgbench_accounts a (cost=0.00..2640.00 rows=100000 width=97) -> Hash (cost=1.01..1.01 rows=1 width=100) -> Seq Scan on pgbench_branches b (cost=0.00..1.01 rows=1 width=100) (7 rows) postgres=#
以下の例では、一つ目のクエリにNoIndexScanを、二つ目のクエリにSeqScanをそれぞれ指定しています。
postgres=# CREATE FUNCTION hints_func(integer) RETURNS integer AS $$ postgres$# DECLARE postgres$# id integer; postgres$# cnt integer; postgres$# BEGIN postgres$# SELECT /*+ NoIndexScan(a) */ aid postgres$# INTO id FROM pgbench_accounts a WHERE aid = $1; postgres$# SELECT /*+ SeqScan(a) */ count(*) postgres$# INTO cnt FROM pgbench_accounts a; postgres$# RETURN id + cnt; postgres$# END; postgres$# $$ LANGUAGE plpgsql;
postgres=# /*+ HashJoin(t1 t1)*/ postgres-# EXPLAIN SELECT * FROM s1.t1 postgres-# JOIN public.t1 ON (s1.t1.id=public.t1.id); INFO: hint syntax error at or near "HashJoin(t1 t1)" DETAIL: Relation name "t1" is ambiguous. QUERY PLAN ------------------------------------------------------------------ Merge Join (cost=337.49..781.49 rows=28800 width=8) Merge Cond: (s1.t1.id = public.t1.id) -> Sort (cost=168.75..174.75 rows=2400 width=4) Sort Key: s1.t1.id -> Seq Scan on t1 (cost=0.00..34.00 rows=2400 width=4) -> Sort (cost=168.75..174.75 rows=2400 width=4) Sort Key: public.t1.id -> Seq Scan on t1 (cost=0.00..34.00 rows=2400 width=4) (8 行) postgres=# /*+ HashJoin(pt st) */ postgres-# EXPLAIN SELECT * FROM s1.t1 st postgres-# JOIN public.t1 pt ON (st.id=pt.id); QUERY PLAN --------------------------------------------------------------------- Hash Join (cost=64.00..1112.00 rows=28800 width=8) Hash Cond: (st.id = pt.id) -> Seq Scan on t1 st (cost=0.00..34.00 rows=2400 width=4) -> Hash (cost=34.00..34.00 rows=2400 width=4) -> Seq Scan on t1 pt (cost=0.00..34.00 rows=2400 width=4) (5 行) postgres=#
postgres=# CREATE VIEW view1 AS SELECT * FROM table1 t1; CREATE TABLE postgres=# /*+ SeqScan(t1) */ postgres=# EXPLAIN SELECT * FROM table1 t1 JOIN view1 t2 ON (t1.key = t2.key) WHERE t2.key = 1; QUERY PLAN ----------------------------------------------------------------- Nested Loop (cost=0.00..358.01 rows=1 width=16) -> Seq Scan on table1 t1 (cost=0.00..179.00 rows=1 width=8) Filter: (key = 1) -> Seq Scan on table1 t1 (cost=0.00..179.00 rows=1 width=8) Filter: (key = 1)
postgres=# /*+ MergeJoin(a *VALUES*) */ postgres-# EXPLAIN SELECT * postgres-# FROM pgbench_accounts a postgres-# JOIN (VALUES (1,1),(2,2)) v (vid, vbalance) ON a.aid = v.vid postgres-# ORDER BY a.aid; QUERY PLAN --------------------------------------------------------------------------------------------------------------- Merge Join (cost=0.04..4497.33 rows=2 width=105) Merge Cond: (a.aid = "*VALUES*".column1) -> Index Scan using pgbench_accounts_pkey on pgbench_accounts a (cost=0.00..4247.26 rows=100000 width=97) -> Sort (cost=0.04..0.04 rows=2 width=8) Sort Key: "*VALUES*".column1 -> Values Scan on "*VALUES*" (cost=0.00..0.03 rows=2 width=8) postgres=#
postgres=# /*+HashJoin(a1 ANY_subquery)*/ postgres=# EXPLAIN SELECT * postgres=# FROM pgbench_accounts a1 postgres=# WHERE aid IN (SELECT bid FROM pgbench_accounts a2 LIMIT 10); QUERY PLAN --------------------------------------------------------------------------------------------- Hash Semi Join (cost=0.49..2903.00 rows=1 width=97) Hash Cond: (a1.aid = a2.bid) -> Seq Scan on pgbench_accounts a1 (cost=0.00..2640.00 rows=100000 width=97) -> Hash (cost=0.36..0.36 rows=10 width=4) -> Limit (cost=0.00..0.26 rows=10 width=4) -> Seq Scan on pgbench_accounts a2 (cost=0.00..2640.00 rows=100000 width=4) (6 rows) postgres=#