Hi

2018-07-10 12:01 GMT+02:00 Peter Eisentraut <
peter.eisentr...@2ndquadrant.com>:

> On 23.01.18 17:08, Pavel Stehule wrote:
> > attached updated patch
>
> This appears to be the patch of record in this thread.  I think there is
> general desire for adding a setting like this, and the implementation is
> simple enough.
>
> One change perhaps: How about naming the default setting "auto" instead
> of "default".  That makes it clearer what it does.
>

I changed "default" to "auto"

updated patch attached

Regards

Pavel


>
> --
> Peter Eisentraut              http://www.2ndQuadrant.com/
> PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
>
commit 456e1f284cdc7b5a024004e69deb53effccf7427
Author: Pavel Stehule <pavel.steh...@gmail.com>
Date:   Thu Jul 12 11:09:54 2018 +0200

    initial

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index e307bb4e8e..dc254b067c 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -4616,6 +4616,31 @@ SELECT * FROM parent WHERE key = 2400;
       </listitem>
      </varlistentry>
 
+     </variablelist>
+    </sect2>
+
+     <sect2 id="runtime-config-query-plancache">
+     <title>Plan Cache Options</title>
+
+     <variablelist>
+
+     <varlistentry id="guc-plancache_mode" xreflabel="plancache_mode">
+      <term><varname>plancache_mode</varname> (<type>enum</type>)
+      <indexterm>
+       <primary><varname>plancache_mode</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Prepared queries have custom and generic plans and the planner 
+        will attempt to choose which is better; this can be set to override 
+        the default behavior. The allowed values are <literal>auto</literal>,
+        <literal>force_custom_plan</literal> and <literal>force_generic_plan</literal>.
+        The default value is <literal>auto</literal>.
+       </para>
+      </listitem>
+     </varlistentry>
+
      </variablelist>
     </sect2>
    </sect1>
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 0ad3e3c736..67cdfb63b1 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -106,6 +106,8 @@ static void PlanCacheRelCallback(Datum arg, Oid relid);
 static void PlanCacheFuncCallback(Datum arg, int cacheid, uint32 hashvalue);
 static void PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue);
 
+/* GUC parameter */
+int	plancache_mode;
 
 /*
  * InitPlanCache: initialize module during InitPostgres.
@@ -1033,6 +1035,12 @@ choose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams)
 	if (IsTransactionStmtPlan(plansource))
 		return false;
 
+	/* See if settings wants to force the decision */
+	if (plancache_mode == PLANCACHE_FORCE_GENERIC_PLAN)
+		return false;
+	if (plancache_mode == PLANCACHE_FORCE_CUSTOM_PLAN)
+		return true;
+
 	/* See if caller wants to force the decision */
 	if (plansource->cursor_options & CURSOR_OPT_GENERIC_PLAN)
 		return false;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 17292e04fe..7b1a2921b4 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -405,6 +405,13 @@ static const struct config_enum_entry force_parallel_mode_options[] = {
 	{NULL, 0, false}
 };
 
+static const struct config_enum_entry plancache_mode_options[] = {
+	{"auto", PLANCACHE_AUTO, false},
+	{"force_generic_plan", PLANCACHE_FORCE_GENERIC_PLAN, false},
+	{"force_custom_plan", PLANCACHE_FORCE_CUSTOM_PLAN, false},
+	{NULL, 0, false}
+};
+
 /*
  * password_encryption used to be a boolean, so accept all the likely
  * variants of "on", too. "off" used to store passwords in plaintext,
@@ -4150,6 +4157,18 @@ static struct config_enum ConfigureNamesEnum[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"plancache_mode", PGC_USERSET, QUERY_TUNING_OTHER,
+			gettext_noop("Controls the planner's selection of custom or generic plan."),
+			gettext_noop("Prepared queries have custom and generic plans and the planner "
+						 "will attempt to choose which is better; this can be set to override "
+						 "the default behavior.")
+		},
+		&plancache_mode,
+		PLANCACHE_AUTO, plancache_mode_options,
+		NULL, NULL, NULL
+	},
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL
diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h
index ab20aa04b0..cf8a0dd020 100644
--- a/src/include/utils/plancache.h
+++ b/src/include/utils/plancache.h
@@ -182,4 +182,16 @@ extern CachedPlan *GetCachedPlan(CachedPlanSource *plansource,
 			  QueryEnvironment *queryEnv);
 extern void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner);
 
+/* possible values for plancache_mode */
+typedef enum
+{
+	PLANCACHE_AUTO,
+	PLANCACHE_FORCE_GENERIC_PLAN,
+	PLANCACHE_FORCE_CUSTOM_PLAN
+}			PlanCacheMode;
+
+
+/* GUC parameter */
+extern int plancache_mode;
+
 #endif							/* PLANCACHE_H */
diff --git a/src/test/regress/expected/plancache.out b/src/test/regress/expected/plancache.out
index 3086c68566..d8255915d6 100644
--- a/src/test/regress/expected/plancache.out
+++ b/src/test/regress/expected/plancache.out
@@ -278,3 +278,82 @@ drop table pc_list_part_1;
 execute pstmt_def_insert(1);
 drop table pc_list_parted, pc_list_part_null;
 deallocate pstmt_def_insert;
+--
+-- Test plan cache strategy
+--
+create table test_strategy(a int);
+insert into test_strategy select 1 from generate_series(1,1000) union all select 2;
+create index on test_strategy(a);
+analyze test_strategy;
+prepare test_strategy_pp(int) as select count(*) from test_strategy where a = $1;
+-- without 5 evaluation pg uses custom plan
+explain (costs off) execute test_strategy_pp(2);
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Aggregate
+   ->  Index Only Scan using test_strategy_a_idx on test_strategy
+         Index Cond: (a = 2)
+(3 rows)
+
+-- we can force to generic plan
+set plancache_mode to force_generic_plan;
+explain (costs off) execute test_strategy_pp(2);
+           QUERY PLAN            
+---------------------------------
+ Aggregate
+   ->  Seq Scan on test_strategy
+         Filter: (a = $1)
+(3 rows)
+
+-- we can fix generic plan by 5 execution
+set plancache_mode to default;
+execute test_strategy_pp(1); -- 1x
+ count 
+-------
+  1000
+(1 row)
+
+execute test_strategy_pp(1); -- 2x
+ count 
+-------
+  1000
+(1 row)
+
+execute test_strategy_pp(1); -- 3x
+ count 
+-------
+  1000
+(1 row)
+
+execute test_strategy_pp(1); -- 4x
+ count 
+-------
+  1000
+(1 row)
+
+execute test_strategy_pp(1); -- 5x
+ count 
+-------
+  1000
+(1 row)
+
+-- we should to get really bad plan
+explain (costs off) execute test_strategy_pp(2);
+           QUERY PLAN            
+---------------------------------
+ Aggregate
+   ->  Seq Scan on test_strategy
+         Filter: (a = $1)
+(3 rows)
+
+-- but we can force to custom plan
+set plancache_mode to force_custom_plan;
+explain (costs off) execute test_strategy_pp(2);
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Aggregate
+   ->  Index Only Scan using test_strategy_a_idx on test_strategy
+         Index Cond: (a = 2)
+(3 rows)
+
+drop table test_strategy;
diff --git a/src/test/regress/sql/plancache.sql b/src/test/regress/sql/plancache.sql
index d9439b83ab..f47e3b3279 100644
--- a/src/test/regress/sql/plancache.sql
+++ b/src/test/regress/sql/plancache.sql
@@ -177,3 +177,37 @@ drop table pc_list_part_1;
 execute pstmt_def_insert(1);
 drop table pc_list_parted, pc_list_part_null;
 deallocate pstmt_def_insert;
+
+--
+-- Test plan cache strategy
+--
+create table test_strategy(a int);
+insert into test_strategy select 1 from generate_series(1,1000) union all select 2;
+create index on test_strategy(a);
+analyze test_strategy;
+
+prepare test_strategy_pp(int) as select count(*) from test_strategy where a = $1;
+
+-- without 5 evaluation pg uses custom plan
+explain (costs off) execute test_strategy_pp(2);
+
+-- we can force to generic plan
+set plancache_mode to force_generic_plan;
+explain (costs off) execute test_strategy_pp(2);
+
+-- we can fix generic plan by 5 execution
+set plancache_mode to default;
+execute test_strategy_pp(1); -- 1x
+execute test_strategy_pp(1); -- 2x
+execute test_strategy_pp(1); -- 3x
+execute test_strategy_pp(1); -- 4x
+execute test_strategy_pp(1); -- 5x
+
+-- we should to get really bad plan
+explain (costs off) execute test_strategy_pp(2);
+
+-- but we can force to custom plan
+set plancache_mode to force_custom_plan;
+explain (costs off) execute test_strategy_pp(2);
+
+drop table test_strategy;

Reply via email to