diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2022-03-24 11:47:41 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2022-03-24 11:47:41 -0400 |
commit | 0bd7af082ace135581bb13a6bd2d88e68c66a3e0 (patch) | |
tree | 412ad873ef762b761baaab0577cb4d36b6c0a240 | |
parent | a47651447f01562dac2e007db03733e750d45b6b (diff) | |
download | postgresql-0bd7af082ace135581bb13a6bd2d88e68c66a3e0.tar.gz postgresql-0bd7af082ace135581bb13a6bd2d88e68c66a3e0.zip |
Invent recursive_worktable_factor GUC to replace hard-wired constant.
Up to now, the planner estimated the size of a recursive query's
worktable as 10 times the size of the non-recursive term. It's hard
to see how to do significantly better than that automatically, but
we can give users control over the multiplier to allow tuning for
specific use-cases. The default behavior remains the same.
Simon Riggs
Discussion: https://postgr.es/m/CANbhV-EuaLm4H3g0+BSTYHEGxJj3Kht0R+rJ8vT57Dejnh=_nA@mail.gmail.com
-rw-r--r-- | doc/src/sgml/config.sgml | 23 | ||||
-rw-r--r-- | src/backend/optimizer/path/costsize.c | 8 | ||||
-rw-r--r-- | src/backend/utils/misc/guc.c | 12 | ||||
-rw-r--r-- | src/backend/utils/misc/postgresql.conf.sample | 1 | ||||
-rw-r--r-- | src/include/optimizer/cost.h | 2 | ||||
-rw-r--r-- | src/include/optimizer/optimizer.h | 1 |
6 files changed, 44 insertions, 3 deletions
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 7a48973b3c8..05df48131d7 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -5919,6 +5919,29 @@ SELECT * FROM parent WHERE key = 2400; </listitem> </varlistentry> + <varlistentry id="guc-recursive-worktable-factor" xreflabel="recursive_worktable_factor"> + <term><varname>recursive_worktable_factor</varname> (<type>floating point</type>) + <indexterm> + <primary><varname>recursive_worktable_factor</varname> configuration parameter</primary> + </indexterm> + </term> + <listitem> + <para> + Sets the planner's estimate of the average size of the working + table of a <link linkend="queries-with-recursive">recursive + query</link>, as a multiple of the estimated size of the initial + non-recursive term of the query. This helps the planner choose + the most appropriate method for joining the working table to the + query's other tables. + The default value is <literal>10.0</literal>. A smaller value + such as <literal>1.0</literal> can be helpful when the recursion + has low <quote>fan-out</quote> from one step to the next, as for + example in shortest-path queries. Graph analytics queries may + benefit from larger-than-default values. + </para> + </listitem> + </varlistentry> + </variablelist> </sect2> </sect1> diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 4d9f3b4bb6b..1b07ea392d9 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -123,6 +123,7 @@ double cpu_index_tuple_cost = DEFAULT_CPU_INDEX_TUPLE_COST; double cpu_operator_cost = DEFAULT_CPU_OPERATOR_COST; double parallel_tuple_cost = DEFAULT_PARALLEL_TUPLE_COST; double parallel_setup_cost = DEFAULT_PARALLEL_SETUP_COST; +double recursive_worktable_factor = DEFAULT_RECURSIVE_WORKTABLE_FACTOR; int effective_cache_size = DEFAULT_EFFECTIVE_CACHE_SIZE; @@ -5665,10 +5666,11 @@ set_cte_size_estimates(PlannerInfo *root, RelOptInfo *rel, double cte_rows) if (rte->self_reference) { /* - * In a self-reference, arbitrarily assume the average worktable size - * is about 10 times the nonrecursive term's size. + * In a self-reference, we assume the average worktable size is a + * multiple of the nonrecursive term's size. The best multiplier will + * vary depending on query "fan-out", so make its value adjustable. */ - rel->tuples = 10 * cte_rows; + rel->tuples = clamp_row_est(recursive_worktable_factor * cte_rows); } else { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index f70f7f5c01e..b86137dc385 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -3741,6 +3741,18 @@ static struct config_real ConfigureNamesReal[] = }, { + {"recursive_worktable_factor", PGC_USERSET, QUERY_TUNING_OTHER, + gettext_noop("Sets the planner's estimate of the average size " + "of a recursive query's working table."), + NULL, + GUC_EXPLAIN + }, + &recursive_worktable_factor, + DEFAULT_RECURSIVE_WORKTABLE_FACTOR, 0.001, 1000000.0, + NULL, NULL, NULL + }, + + { {"geqo_selection_bias", PGC_USERSET, QUERY_TUNING_GEQO, gettext_noop("GEQO: selective pressure within the population."), NULL, diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 4cf5b26a363..b933fade8c6 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -426,6 +426,7 @@ # JOIN clauses #plan_cache_mode = auto # auto, force_generic_plan or # force_custom_plan +#recursive_worktable_factor = 10.0 # range 0.001-1000000 #------------------------------------------------------------------------------ diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h index 356a51f370a..bc12071af6e 100644 --- a/src/include/optimizer/cost.h +++ b/src/include/optimizer/cost.h @@ -29,6 +29,8 @@ #define DEFAULT_PARALLEL_TUPLE_COST 0.1 #define DEFAULT_PARALLEL_SETUP_COST 1000.0 +/* defaults for non-Cost parameters */ +#define DEFAULT_RECURSIVE_WORKTABLE_FACTOR 10.0 #define DEFAULT_EFFECTIVE_CACHE_SIZE 524288 /* measured in pages */ typedef enum diff --git a/src/include/optimizer/optimizer.h b/src/include/optimizer/optimizer.h index 6b8ee0c69fa..2302ab6d546 100644 --- a/src/include/optimizer/optimizer.h +++ b/src/include/optimizer/optimizer.h @@ -91,6 +91,7 @@ extern PGDLLIMPORT double cpu_index_tuple_cost; extern PGDLLIMPORT double cpu_operator_cost; extern PGDLLIMPORT double parallel_tuple_cost; extern PGDLLIMPORT double parallel_setup_cost; +extern PGDLLIMPORT double recursive_worktable_factor; extern PGDLLIMPORT int effective_cache_size; extern double clamp_row_est(double nrows); |