<!-- doc/src/sgml/pgplanadvice.sgml -->

<sect1 id="pgplanadvice" xreflabel="pg_plan_advice">
 <title>pg_plan_advice &mdash; help the planner get the right plan</title>

 <indexterm zone="pgplanadvice">
  <primary>pg_plan_advice</primary>
 </indexterm>

 <para>
  The <filename>pg_plan_advice</filename> module allows key planner decisions
  to be described, reproduced, and altered using a special-purpose "plan
  advice" mini-language. It is intended to allow stabilization of plan choices
  that the user believes to be good, as well as experimentation with plans that
  the planner believes to be non-optimal.
 </para>

 <para>
  Note that, since the planner often makes good decisions, overriding its
  judgment can easily backfire. For example, if the distribution of the
  underlying data changes, the planner normally has the option to adjust the
  plan in an attempt to preserve good performance. If the plan advice prevents
  this, a very poor plan may be chosen. It is important to use plan advice
  only when the risks of constraining the planner's choices are outweighed by
  the benefits.
 </para>

 <sect2 id="pgplanadvice-getting-started">
  <title>Getting Started</title>

  <para>
   First, you must arrange to load the <literal>pg_plan_advice</literal>
   module. You can do this on a system-wide basis by adding
   <literal>pg_plan_advice</literal> to
   <xref linkend="guc-shared-preload-libraries"/> and restarting the
   server, or by adding it to
   <xref linkend="guc-session-preload-libraries"/> and starting a new session,
   or by loading it into an individual session using the
   <link linkend="sql-load"><literal>LOAD</literal></link> command.
  </para>

  <para>
   Once the <literal>pg_plan_advice</literal> module is loaded,
   <link linkend="sql-explain"><literal>EXPLAIN</literal></link> will support
   a <literal>PLAN_ADVICE</literal> option. You can use this option to see
   a plan advice string for the chosen plan. For example:
  </para>

<programlisting>
EXPLAIN (COSTS OFF, PLAN_ADVICE)
        SELECT * FROM join_fact f JOIN join_dim d ON f.dim_id = d.id;
             QUERY PLAN
------------------------------------
 Hash Join
   Hash Cond: (f.dim_id = d.id)
   ->  Seq Scan on join_fact f
   ->  Hash
         ->  Seq Scan on join_dim d
 Generated Plan Advice:
   JOIN_ORDER(f d)
   HASH_JOIN(d)
   SEQ_SCAN(f d)
   NO_GATHER(f d)
</programlisting>

  <para>
   In this example, the user has not specified any advice; instead, the
   planner has been permitted to make whatever decisions it thinks best, and
   those decisions are memorialized in the form of an advice string.
   <literal>JOIN_ORDER(f d)</literal> means that <literal>f</literal> should
   be the driving table, and the first table to which it should be joined is
   <literal>d</literal>. <literal>HASH_JOIN(d)</literal> means that
   <literal>d</literal> should appear on the inner side of a hash join.
   <literal>SEQ_SCAN(f d)</literal> means that both <literal>f</literal>
   and <literal>d</literal> should be accessed via a sequential scan.
   <literal>NO_GATHER(f d)</literal> means that neither <literal>f</literal>
   nor <literal>d</literal> should appear beneath a <literal>Gather</literal>
   or <literal>Gather Merge</literal> node. For more details on the plan
   advice mini-language, see the information on
   <link linkend="pgplanadvice-targets">advice targets</link> and
   <link linkend="pgplanadvice-tags">advice tags</link>, below.
  </para>

  <para>
   Once you have an advice string for a query, you can use it to control how
   that query is planned. You can do this by setting
   <literal>pg_plan_advice.advice</literal> to the advice string you've
   chosen. This can be an advice string that was generated by the system,
   or one you've written yourself. One good way of creating your own advice
   string is to take the string generated by the system and pick out just
   those elements that you wish to enforce. In the example above,
   <literal>pg_plan_advice</literal> emits advice for the join order, the
   join method, the scan method, and the use of parallelism, but you might
   only want to control the join order:
  </para>

<programlisting>
SET pg_plan_advice.advice = 'JOIN_ORDER(f d)';
EXPLAIN (COSTS OFF)
        SELECT * FROM join_fact f JOIN join_dim d ON f.dim_id = d.id;
             QUERY PLAN
------------------------------------
 Hash Join
   Hash Cond: (f.dim_id = d.id)
   ->  Seq Scan on join_fact f
   ->  Hash
         ->  Seq Scan on join_dim d
 Supplied Plan Advice:
   JOIN_ORDER(f d) /* matched */
</programlisting>

  <para>
   Since the <literal>PLAN_ADVICE</literal> option to
   <literal>EXPLAIN</literal> was not specified, no advice string is generated
   for the plan. However, the supplied plan advice is still shown so that
   anyone looking at the <literal>EXPLAIN</literal> output knows that the
   chosen plan was influenced by plan advice. If information about supplied
   plan advice is not desired, it can be suppressed by configuring
   <literal>pg_plan_advice.always_explain_supplied_advice = false</literal>.
   For each piece of supplied advice, the output shows
   <link linkend="pgplanadvice-feedback">advice feedback</link> indicating
   whether or not the advice was successfully applied to the query. In this
   case, the feedback says <literal>/* matched */</literal>, which means that
   <literal>f</literal> and <literal>d</literal> were found in the query and
   that the resulting query plan conforms to the specified advice.
  </para>

 </sect2>

 <sect2 id="pgplanadvice-how-it-works">
  <title>How It Works</title>

  <para>
   Plan advice is written imperatively; that is, it specifies what should be
   done. However, at an implementation level,
   <literal>pg_plan_advice</literal> works by telling the core planner what
   should not be done. In other words, it operates by constraining the
   planner's choices, not by replacing it. Therefore, no matter what advice
   you provide, you will only ever get a plan that the core planner would have
   considered for the query in question. If you attempt to force what you
   believe to be the correct plan by supplying an advice string, and the
   planner still fails to produce the desired plan, this means that either
   there is a bug in your advice string, or the plan in question was not
   considered viable by the core planner. This commonly happens for one of two
   reasons. First, it might be that the planner believes that the plan you're
   trying to force would be semantically incorrect - that is, it would produce
   the wrong results - and for that reason it wasn't considered. Second, it
   might be that the planner rejected the plan you were hoping to generate on
   some grounds other than cost. For example, given a very simple query such as
   <literal>SELECT * FROM some_table</literal>, the query planner will
   decide that the use of an index is worthless here before it performs any
   costing calculations. You cannot force it to use an index for this query
   even if you set <literal>enable_seqscan = false</literal>, and you can't
   force it to use an index using plan advice, either.
  </para>

  <para>
   Specifying plan advice should never cause planner failure. However, if you
   specify plan advice that asks for something impossible, you may get a plan
   where some plan nodes are flagged as <literal>Disabled: true</literal> in
   the <literal>EXPLAIN</literal> output. In some cases, such plans will be
   basically the same plan you would have gotten with no supplied advice at
   all, but in other cases, they may be much worse. For example:
  </para>

<programlisting>
SET pg_plan_advice.advice = 'JOIN_ORDER(x f d)';
EXPLAIN (COSTS OFF)
        SELECT * FROM join_fact f JOIN join_dim d ON f.dim_id = d.id;
                     QUERY PLAN
----------------------------------------------------
 Nested Loop
   Disabled: true
   ->  Seq Scan on join_fact f
   ->  Index Scan using join_dim_pkey on join_dim d
         Index Cond: (id = f.dim_id)
 Supplied Plan Advice:
   JOIN_ORDER(x f d) /* partially matched */
</programlisting>

  <para>
   Because neither <literal>f</literal> nor <literal>d</literal> is the
   first table in the <literal>JOIN_ORDER()</literal> specification, the
   planner disables all direct joins between the two of them, thinking that
   the join to <literal>x</literal> should happen first. Since planning isn't
   allowed to fail, a disabled plan between the two relations is eventually
   selected anyway, but here it's a <literal>Nested Loop</literal> rather than
   the <literal>Hash Join</literal> that was chosen in the above example where
   no advice was specified. There are several different ways that this kind
   of thing can happen; when it does, the resulting plan is generally worse
   than if no advice had been specified at all. Therefore, it is a good idea
   to validate that the advice you specify applies to the query to which it
   is applied and that the results are as expected.
  </para>

 </sect2>

 <sect2 id="pgplanadvice-targets">
  <title>Advice Targets</title>

  <para>
   An <firstterm>advice target</firstterm> uniquely identifies a particular
   instance of a particular relation involved in a particular query. In simple
   cases, such as the examples shown above, the advice target is simply the
   relation alias. However, a more complex syntax is required when subqueries
   are used, when tables are partitioned, or when the same relation alias is
   mentioned more than once in the same subquery (e.g., <literal>(foo JOIN bar
   ON foo.a = bar.a) x JOIN foo ON x.b = foo.b</literal>). Any combination of
   these three things can occur simultaneously: a relation could be mentioned
   more than once, be partitioned, and be used inside of a subquery.
  </para>

  <para>
   Because of this, the general syntax for a relation identifier is:
  </para>

<programlisting>
alias_name#occurrence_number/partition_schema.partition_name@plan_name
</programlisting>

  <para>
   All components except for the <literal>alias_name</literal> are optional
   and are included only when required. When a component is omitted, the
   preceding punctuation must also be omitted. For the first occurrence of a
   relation within a given subquery, generated advice will omit the occurrence
   number, but it is legal to write <literal>#1</literal>, if desired. The
   partition schema and partition name are included only for children of
   partitioned tables. In generated advice, <literal>pg_plan_advice</literal>
   always includes both, but it is legal to omit the schema. The plan name is
   omitted for the top-level plan, and must be included for any subplan.
  </para>

  <para>
   It is not always easy to determine the correct advice target by examining
   the query. For instance, if the planner pulls up a subquery into the parent
   query level, everything inside of it becomes part of the parent query level,
   and uses the parent query's subplan name (or no subplan name, if pulled up
   to the top level). Furthermore, the correct subquery name is sometimes not
   obvious. For example, when two queries are joined using an operation such as
   <literal>UNION</literal> or <literal>INTERSECT</literal>, no name for the
   subqueries is present in the SQL syntax; instead, a system-generated name is
   assigned to each branch. The easiest way to discover the proper advice
   targets is to use <literal>EXPLAIN (PLAN_ADVICE)</literal> and examine the
   generated advice.
  </para>

 </sect2>

 <sect2 id="pgplanadvice-tags">
  <title>Advice Tags</title>

  <para>
   An <firstterm>advice tag</firstterm> specifies a particular behavior that
   should be enforced for some portion of the query, such as a particular
   join order or join method. All advice tags take
   <link linkend="pgplanadvice-targets">advice targets</link> as arguments,
   and many allow lists of advice targets, which in some cases can be nested
   multiple levels deep. Several different classes of advice tags exist,
   each controlling a different aspect of query planning.
  </para>

  <sect3 id="pgplanadvice-scan-method">
  <title>Scan Method Advice</title>
   <synopsis>
SEQ_SCAN(<replaceable>target</replaceable> [ ... ])
TID_SCAN(<replaceable>target</replaceable> [ ... ])
INDEX_SCAN(<replaceable>target</replaceable> <replaceable>index_name</replaceable> [ ... ])
INDEX_ONLY_SCAN(<replaceable>target</replaceable> <replaceable>index_name</replaceable> [ ... ])
FOREIGN_JOIN((<replaceable>target</replaceable> [ ... ]) [ ... ])
BITMAP_HEAP_SCAN(<replaceable>target</replaceable> [ ... ])
DO_NOT_SCAN(<replaceable>target</replaceable> [ ... ])</synopsis>

   <para>
    <literal>SEQ_SCAN</literal> specifies that each target should be
    scanned using a <literal>Seq Scan</literal>. <literal>TID_SCAN</literal>
    specifies that each target should be scanned using a
    <literal>TID Scan</literal> or <literal>TID Range Scan</literal>.
    <literal>BITMAP_HEAP_SCAN</literal> specifies that each target
    should be scanned using a <literal>Bitmap Heap Scan</literal>.
   </para>

   <para>
    <literal>INDEX_SCAN</literal> specifies that each target should
    be scanned using an <literal>Index Scan</literal> on the given index
    name. <literal>INDEX_ONLY_SCAN</literal> is similar, but specifies the
    use of an <literal>Index Only Scan</literal>. In either case, the index
    name can be, but does not have to be, schema-qualified.
   </para>

   <para>
    <literal>FOREIGN_JOIN</literal> specifies that a join between two or
    more foreign tables should be pushed down to a remote server so
    that it can be implemented as a single <literal>Foreign Scan</literal>.
    Specifying <literal>FOREIGN_JOIN</literal> for a single foreign table is
    neither necessary nor permissible: a <literal>Foreign Scan</literal> will
    need to be used regardless. If you want to prevent a join from being
    pushed down, consider using the <literal>JOIN_ORDER</literal> tag for
    that purpose.
   </para>

   <para>
    <literal>DO_NOT_SCAN</literal> specifies that a particular target
    should not appear in the final plan at all. In most cases, this is
    impossible, and will simply cause the scan of the target relation to
    be marked disabled. However, in certain cases, the planner considers
    optimizations where a portion of the plan tree is copied and mutated,
    and then considered as an alternative to the original. In those cases,
    <literal>DO_NOT_SCAN</literal> can be used to exclude the non-preferred
    alternative.
   </para>

   <para>
    The planner supports many types of scans other than those listed here;
    however, in most of those cases, there is no meaningful decision to be
    made, and hence no need for advice. For example, the output of a
    set-returning function that appears in the <literal>FROM</literal> clause
    can only ever be scanned using a <literal>Function Scan</literal>, so
    there is no opportunity for advice to change anything.
   </para>

  </sect3>

  <sect3 id="pgplanadvice-join-order">
  <title>Join Order Advice</title>
   <synopsis>
JOIN_ORDER(<replaceable>join_order_item</replaceable> [ ... ])

<phrase>where <replaceable>join_order_item</replaceable> is:</phrase>

<replaceable>advice_target</replaceable> |
( <replaceable>join_order_item</replaceable> [ ... ] ) |
{ <replaceable>join_order_item</replaceable> [ ... ] }</synopsis>

   <para>
    When <literal>JOIN_ORDER</literal> is used without any sublists, it
    specifies an outer-deep join with the first advice target as the driving
    table, joined to each subsequent advice target in turn in the order
    specified. For instance, <literal>JOIN_ORDER(a b c)</literal> means that
    <literal>a</literal> should be the driving table, and that it should be
    joined first to <literal>b</literal> and then to <literal>c</literal>.
    If there are more relations in the query than <literal>a</literal>,
    <literal>b</literal>, and <literal>c</literal>, the rest can be joined
    afterwards in any manner.
   </para>

   <para>
    If a <literal>JOIN_ORDER</literal> list contains a parenthesized sublist,
    it specifies a non-outer-deep join. The relations in the sublist must first
    be joined to each other much as if the sublist were a top-level
    <literal>JOIN_ORDER</literal> list, and the resulting join product must
    then appear on the inner side of a join at the appropriate point in the
    join order. For example, <literal>JOIN_ORDER(a (b c) d)</literal> requires
    a plan of this form:
   </para>

<programlisting>
Join
  ->  Join
        -> Scan on a
        -> Join
             -> Scan on b
             -> Scan on c
  ->  Scan on d
</programlisting>

   <para>
    If a <literal>JOIN_ORDER</literal> list contains a sublist surrounded by
    curly braces, this also specifies a non-outer-deep join. However, the join
    order within the sublist is not constrained. For example, specifying
    <literal>JOIN_ORDER(a {b c} d)</literal> would allow the scans of
    <literal>b</literal> and <literal>c</literal> to be swapped in the
    previous example, which is not allowed when parentheses are used.
   </para>

   <para>
    Parenthesized sublists can be arbitrarily nested, but sublists surrounded
    by curly braces cannot themselves contain sublists.
   </para>

   <para>
    Multiple instances of <literal>JOIN_ORDER()</literal> can sometimes be
    needed in order to fully constrain the join order. This occurs when there
    are multiple join problems that are optimized separately by the planner.
    This can happen due to the presence of subqueries, or because there is a
    partitionwise join. In the latter case, each branch of the partitionwise
    join can have its own join order, independent of every other branch.
   </para>

  </sect3>

  <sect3 id="pgplanadvice-join-method">
  <title>Join Method Advice</title>
   <synopsis>
join_method_name(<replaceable>join_method_item</replaceable> [ ... ])

<phrase>where <replaceable>join_method_name</replaceable> is:</phrase>

{ MERGE_JOIN_MATERIALIZE | MERGE_JOIN_PLAIN | NESTED_LOOP_MATERIALIZE | NESTED_LOOP_MEMOIZE | NESTED_LOOP_PLAIN | HASH_JOIN }

<phrase>and <replaceable>join_method_item</replaceable> is:</phrase>

{ <replaceable>advice_target</replaceable> |
( <replaceable>advice_target</replaceable> [ ... ] ) }</synopsis>

   <para>
    Join method advice specifies the relation, or set of relations, that should
    appear on the inner side of a join using the named join method. For
    example, <literal>HASH_JOIN(a b)</literal> means that each of
    <literal>a</literal> and <literal>b</literal> should appear on the inner
    side of a hash join; a conforming plan must contain at least two hash
    joins, one of which has <literal>a</literal> and nothing else on the
    inner side, and the other of which has <literal>b</literal> and nothing
    else on the inner side. On the other hand,
    <literal>HASH_JOIN((a b))</literal> means that the join product of
    <literal>a</literal> and <literal>b</literal> should appear together
    on the inner side of a single hash join.
   </para>

   <para>
    Note that join method advice implies a negative join order constraint.
    Since the named relation or relations must be on the inner side of a join
    using the specified method, none of them can be the driving table for the
    entire join problem. Moreover, no relation inside the set should be joined
    to any relation outside the set until all relations within the set have
    been joined to each other. For example, if the advice specifies
    <literal>HASH_JOIN((a b))</literal> and the system begins by joining either
    of those to some third relation <literal>c</literal>, the resulting
    plan could never be compliant with the request to put exactly those two
    relations on the inner side of a hash join. When using both join order
    advice and join method advice for the same query, it is a good idea to make
    sure that they do not mandate incompatible join orders.
   </para>

  </sect3>

  <sect3 id="pgplanadvice-partitionwise">
  <title>Partitionwise Advice</title>
   <synopsis>
PARTITIONWISE(<replaceable>partitionwise_item</replaceable> [ ... ])

<phrase>where <replaceable>partitionwise_item</replaceable> is:</phrase>

{ <replaceable>advice_target</replaceable> |
( <replaceable>advice_target</replaceable> [ ... ] ) }</synopsis>

   <para>
    When applied to a single target, <literal>PARTITIONWISE</literal>
    specifies that the specified table should not be part of any partitionwise
    join. When applied to a list of targets, <literal>PARTITIONWISE</literal>
    specifies that exactly that set of relations should be joined in
    partitionwise fashion. Note that, regardless of what advice is specified,
    no partitionwise joins will be possible if
    <literal>enable_partitionwise_join = off</literal>.
   </para>

  </sect3>

  <sect3 id="pgplanadvice-semijoin-unique">
  <title>Semijoin Uniqueness Advice</title>
   <synopsis>
SEMIJOIN_UNIQUE(<replaceable>sj_unique_item</replaceable> [ ... ])
SEMIJOIN_NON_UNIQUE(<replaceable>sj_unique_item</replaceable> [ ... ])

<phrase>where <replaceable>sj_unique_item</replaceable> is:</phrase>

{ <replaceable>advice_target</replaceable> |
( <replaceable>advice_target</replaceable> [ ... ] ) }</synopsis>

   <para>
    The planner sometimes has a choice between implementing a semijoin
    directly and implementing a semijoin by making the nullable side unique
    and then performing an inner join. <literal>SEMIJOIN_UNIQUE</literal>
    specifies the latter strategy, while <literal>SEMIJOIN_NON_UNIQUE</literal>
    specifies the former strategy. In either case, the argument is the single
    relation or list of relations that appear beneath the nullable side of the
    join.
   </para>

  </sect3>

  <sect3 id="pgplanadvice-parallel-query">
  <title>Parallel Query Advice</title>
   <synopsis>
GATHER(<replaceable>gather_item</replaceable> [ ... ])
GATHER_MERGE(<replaceable>gather_item</replaceable> [ ... ])
NO_GATHER(<replaceable>advice_target</replaceable> [ ... ])

<phrase>where <replaceable>gather_item</replaceable> is:</phrase>

{ <replaceable>advice_target</replaceable> |
( <replaceable>advice_target</replaceable> [ ... ] ) }</synopsis>

   <para>
    <literal>GATHER</literal> or <literal>GATHER_MERGE</literal> specifies
    that <literal>Gather</literal> or <literal>Gather Merge</literal>,
    respectively, should be placed on top of the single relation specified as
    a target, or on top of the join between the list of relations specified as
    a target. This means that <literal>GATHER(a b c)</literal> is a request
    for three different <literal>Gather</literal> nodes, while
    <literal>GATHER((a b c))</literal> is a request for a single
    <literal>Gather</literal> node on top of a 3-way join.
   </para>

   <para>
    <literal>NO_GATHER</literal> specifies that no <literal>Gather</literal> or
    <literal>Gather Merge</literal> node should appear above any of the
    targets, but it only constrains the planning of an individual subquery,
    and outer subquery levels can still use parallel query. For example,
    <literal>NO_GATHER(inner_example@any_1)</literal> precludes using a
    <literal>Parallel Seq Scan</literal> to access the
    <literal>inner_example</literal> table within the <literal>any_1</literal>
    subquery, but it does not prevent the planner from placing
    <literal>SubPlan any_1</literal> beneath a <literal>Gather</literal>
    or <literal>Gather Merge</literal> node. The following plan is
    compatible with <literal>NO_GATHER(inner_example@any_1)</literal>, but
    not with <literal>NO_GATHER(outer_example)</literal>:
   </para>

<programlisting>
Finalize Aggregate
  ->  Gather
        ->  Partial Aggregate
              ->  Parallel Seq Scan on outer_example
                    Filter: (something = (hashed SubPlan any_1).col1)
                    SubPlan any_1
                      ->  Seq Scan on inner_example
                            Filter: (something_else > 100)
</programlisting>

   <para>
    Here is the reverse case, that is, a plan compatible with
    <literal>NO_GATHER(outer_example)</literal> but not with
    <literal>NO_GATHER(inner_example@any_1)</literal>:
   </para>

<programlisting>
Aggregate
  ->  Seq Scan on outer_example
        Filter: (something = (hashed SubPlan any_1).col1)
        SubPlan any_1
          ->  Gather
                -> Parallel Seq Scan on inner_example
                     Filter: (something_else > 100)
</programlisting>

  </sect3>
 </sect2>

 <sect2 id="pgplanadvice-feedback">
  <title>Advice Feedback</title>

  <para>
   <literal>EXPLAIN</literal> provides feedback on whether supplied advice was
   successfully applied to the query in the form of a comment on each piece
   of supplied advice. For example:
  </para>

<programlisting>
SET pg_plan_advice.advice = 'hash_join(f g) join_order(f g) index_scan(f no_such_index)';
EXPLAIN (COSTS OFF)
    SELECT * FROM jo_fact f
    LEFT JOIN jo_dim1 d1 ON f.dim1_id = d1.id
    LEFT JOIN jo_dim2 d2 ON f.dim2_id = d2.id
    WHERE val1 = 1 AND val2 = 1;
                            QUERY PLAN
-------------------------------------------------------------------
 Hash Join
   Hash Cond: ((d1.id = f.dim1_id) AND (d2.id = f.dim2_id))
   ->  Nested Loop
         ->  Seq Scan on jo_dim2 d2
               Filter: (val2 = 1)
         ->  Materialize
               ->  Seq Scan on jo_dim1 d1
                     Filter: (val1 = 1)
   ->  Hash
         ->  Seq Scan on jo_fact f
 Supplied Plan Advice:
   INDEX_SCAN(f no_such_index) /* matched, inapplicable, failed */
   HASH_JOIN(f) /* matched */
   HASH_JOIN(g) /* not matched */
   JOIN_ORDER(f g) /* partially matched */
</programlisting>

  <para>
   For this query, <literal>f</literal> is a valid advice target, but
   <literal>g</literal> is not. Therefore, the request to place
   <literal>f</literal> on the inner side of a hash join is listed as
   <literal>matched</literal>, but the request to place <literal>g</literal>
   on the inner side of a hash join is listed as
   <literal>not matched</literal>. The <literal>JOIN_ORDER</literal> advice
   tag involves one valid target and one invalid target, and so is listed as
   <literal>partially matched</literal>. Note that
   <literal>HASH_JOIN(f g)</literal> is actually a request for two logically
   separate behaviors, so in the feedback it is decomposed into
   <literal>HASH_JOIN(f)</literal> and <literal>HASH_JOIN(g)</literal>.
   By contrast, <literal>JOIN_ORDER(f g)</literal> is a single request and
   appears as-is.
  </para>

  <para>
   Advice feedback can include any of the following:
  </para>

  <itemizedlist>

   <listitem>
    <para>
     <literal>matched</literal> means that all of the specified advice targets
     were observed together during query planning, at a time at which the
     advice could be enforced.
    </para>
   </listitem>

   <listitem>
    <para>
     <literal>partially matched</literal> means that some but not all of the
     specified advice targets were observed during query planning, or all
     of the advice targets were observed but not together. For example, this
     may happen if all the targets of <literal>JOIN_ORDER</literal> advice
     individually match the query, but the proposed join order is not legal.
    </para>
   </listitem>

   <listitem>
    <para>
     <literal>not matched</literal> means that none of the
     specified advice targets were observed during query planning. This may
     happen if the advice simply doesn't match the query, or it may
     occur if the relevant portion of the query was not planned, perhaps
     because it was gated by a condition that was simplified to constant false.
    </para>
   </listitem>

   <listitem>
    <para>
     <literal>inapplicable</literal> means that the advice tag could not
     be applied to the advice targets for some reason. For example, this will
     happen if the use of a nonexistent index is requested, or if an attempt
     is made to control semijoin uniqueness for a non-semijoin.
    </para>
   </listitem>

   <listitem>
    <para>
     <literal>conflicting</literal> means that two or more pieces of advice
     request incompatible behaviors. For example, if you advise a sequential
     scan and an index scan for the same table, both requests will be flagged
     as conflicting. This also commonly happens if join method advice or
     semijoin uniqueness advice implies a join order incompatible with the
     one explicitly specified; see
     <xref linkend="pgplanadvice-join-method" />.
    </para>
   </listitem>

   <listitem>
    <para>
     <literal>failed</literal> means that the query plan does not comply with
     the advice. This only occurs for entries that are also shown as
     <literal>matched</literal>. It frequently occurs for entries that are
     also marked as <literal>conflicting</literal> or
     <literal>inapplicable</literal>. However, it can also occur when the
     advice is valid insofar as <literal>pg_plan_advice</literal> is able
     to determine, but the planner is not able to construct a legal
     plan that can comply with the advice. It is important to note that the
     sanity checks performed by <literal>pg_plan_advice</literal> are fairly
     superficial and focused mostly on looking for logical inconsistencies in
     the advice string; only the planner knows what will actually work.
    </para>
   </listitem>

  </itemizedlist>

  <para>
   All advice should be marked as exactly one of <literal>matched</literal>,
   <literal>partially matched</literal>, or <literal>not matched</literal>.
  </para>

 </sect2>

 <sect2 id="pgplanadvice-config-params">
  <title>Configuration Parameters</title>

  <variablelist>

   <varlistentry>
    <term>
     <varname>pg_plan_advice.advice</varname> (<type>string</type>)
     <indexterm>
      <primary><varname>pg_plan_advice.advice</varname> configuration parameter</primary>
     </indexterm>
    </term>

    <listitem>
     <para>
      <varname>pg_plan_advice.advice</varname> is an advice string to be
      used during query planning.
     </para>
    </listitem>
   </varlistentry>

   <varlistentry>
    <term>
     <varname>pg_plan_advice.always_explain_supplied_advice</varname> (<type>boolean</type>)
     <indexterm>
      <primary><varname>pg_plan_advice.always_explain_supplied_advice</varname> configuration parameter</primary>
     </indexterm>
    </term>

    <listitem>
     <para>
      <varname>pg_plan_advice.always_explain_supplied_advice</varname> causes
      <literal>EXPLAIN</literal> to always show any supplied advice and the
      associated
      <link linkend="pgplanadvice-feedback">advice feedback</link>.
      The default value is <literal>true</literal>. If set to
      <literal>false</literal>, this information will be displayed only when
      <literal>EXPLAIN (PLAN_ADVICE)</literal> is used.
     </para>
    </listitem>
   </varlistentry>

   <varlistentry>
    <term>
     <varname>pg_plan_advice.always_store_advice_details</varname> (<type>boolean</type>)
     <indexterm>
      <primary><varname>pg_plan_advice.always_store_advice_details</varname> configuration parameter</primary>
     </indexterm>
    </term>

    <listitem>
     <para>
      <varname>pg_plan_advice.always_store_advice_details</varname> allows
      <literal>EXPLAIN</literal> to show details related to plan advice even
      when prepared queries are used. The default value is
      <literal>false</literal>. When planning a prepared query, it is not
      possible to know whether <literal>EXPLAIN</literal> will later be used,
      so by default, to reduce overhead, <literal>pg_plan_advice</literal>
      will not generate plan advice or feedback on supplied advice. This means
      that if <literal>EXPLAIN EXECUTE</literal> is used on the prepared query,
      it will not be able to show this information. Changing this setting to
      <literal>true</literal> avoids this problem, but adds additional
      overhead. It is probably a good idea to enable this option only in
      sessions where it is needed, rather than on a system-wide basis.
     </para>
    </listitem>
   </varlistentry>

   <varlistentry>
    <term>
     <varname>pg_plan_advice.feedback_warnings</varname> (<type>boolean</type>)
     <indexterm>
      <primary><varname>pg_plan_advice.feedback_warnings</varname> configuration parameter</primary>
     </indexterm>
    </term>

    <listitem>
     <para>
      When set to true, <varname>pg_plan_advice.feedback_warnings</varname>
      emits a warning whenever supplied plan advice is not successfully
      enforced. The default value is <literal>false</literal>.
     </para>
    </listitem>
   </varlistentry>

   <varlistentry>
    <term>
     <varname>pg_plan_advice.trace_mask</varname> (<type>boolean</type>)
     <indexterm>
      <primary><varname>pg_plan_advice.trace_mask</varname> configuration parameter</primary>
     </indexterm>
    </term>

    <listitem>
     <para>
      When <varname>pg_plan_advice.trace_mask</varname> is
      <literal>true</literal>, <literal>pg_plan_advice</literal> will print
      messages during query planning each time that
      <literal>pg_plan_advice</literal> alters the mask of allowable query
      plan types in response to supplied plan advice. The default value is
      <literal>false</literal>. The messages printed by this setting are not
      expected to be useful except for purposes of debugging this module.
     </para>
    </listitem>
   </varlistentry>

  </variablelist>

 </sect2>

 <sect2 id="pgplanadvice-limitations">
  <title>Limitations</title>

  <para>
   It is currently not possible to control any aspect of the planner's behavior
   with respect to aggregation. This includes both whether aggregates are
   computed by sorting or hashing, and also whether strategies such as
   <link linkend="guc-enable-eager-aggregate">eager aggregation</link> or
   <link linkend="guc-enable-partitionwise-aggregate">partitionwise
   aggregation</link> are used.
  </para>

  <para>
   It also is currently not possible to control any aspect of the planner's
   behavior with respect to set operations such as <literal>UNION</literal>
   or <literal>INTERSECT</literal>.
  </para>

  <para>
   As discussed above under <link linkend="pgplanadvice-how-it-works">How
   It Works</link>, the use of plan advice can only affect which plan
   the planner chooses from among those it believes to be viable. It can never
   force the choice of a plan which the planner refused to consider in the
   first place.
  </para>
 </sect2>

 <sect2 id="pgplanadvice-author">
  <title>Author</title>

  <para>
   Robert Haas <email>rhaas@postgresql.org</email>
  </para>
 </sect2>

</sect1>
