skewedparam.patch

text/plain

Filename: skewedparam.patch
Type: text/plain
Part: 0
Message: Re: Improvement discussion of custom and generic plans

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
src/backend/optimizer/util/clauses.c 2 0
src/backend/utils/adt/selfuncs.c 67 4
src/backend/utils/cache/plancache.c 17 0
src/include/Makefile 1 0
src/include/nodes/params.h 7 1
src/include/nodes/primnodes.h 6 0
src/include/utils/plancache.h 1 0
src/include/utils/selfuncs.h 4 0
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 94eb56a1e7..3384520dc1 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -2489,6 +2489,8 @@ eval_const_expressions_mutator(Node *node,
 											pval,
 											prm->isnull,
 											typByVal);
+							if (paramLI->paramFetch == NULL)
+								con->paramid = param->paramid;
 							con->location = param->location;
 							return (Node *) con;
 						}
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index cea777e9d4..62de124643 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -273,10 +273,32 @@ eqsel_internal(PG_FUNCTION_ARGS, bool negate)
 	 * in the query.)
 	 */
 	if (IsA(other, Const))
-		selec = var_eq_const(&vardata, operator, collation,
-							 ((Const *) other)->constvalue,
-							 ((Const *) other)->constisnull,
-							 varonleft, negate);
+	{
+		Const * con = (Const *) other;
+
+		if (con->paramid > 0)
+		{
+			bool	skewed_stat = false;
+
+			selec = var_eq_const_ext(&vardata, operator, collation,
+								((Const *) other)->constvalue,
+								((Const *) other)->constisnull,
+								varonleft, negate, &skewed_stat);
+
+			if (skewed_stat)
+			{
+				ParamExternData *prm;
+
+				prm = &root->glob->boundParams->params[con->paramid - 1];
+				prm->pflags |= PARAM_FLAG_SKEWEDSTAT;
+			}
+		}
+		else
+			selec = var_eq_const(&vardata, operator, collation,
+								((Const *) other)->constvalue,
+								((Const *) other)->constisnull,
+								varonleft, negate);
+	}
 	else
 		selec = var_eq_non_const(&vardata, operator, collation, other,
 								 varonleft, negate);
@@ -295,6 +317,16 @@ double
 var_eq_const(VariableStatData *vardata, Oid oproid, Oid collation,
 			 Datum constval, bool constisnull,
 			 bool varonleft, bool negate)
+{
+	return var_eq_const_ext(vardata, oproid, collation,
+			 constval, constisnull,
+			 varonleft, negate, NULL);
+}
+
+double
+var_eq_const_ext(VariableStatData *vardata, Oid oproid, Oid collation,
+			 Datum constval, bool constisnull,
+			 bool varonleft, bool negate, bool *skewed_stat)
 {
 	double		selec;
 	double		nullfrac = 0.0;
@@ -387,6 +419,37 @@ var_eq_const(VariableStatData *vardata, Oid oproid, Oid collation,
 					break;
 				}
 			}
+
+			Assert(sslot.nvalues > 0);
+			if (skewed_stat)
+			{
+				/* Check whether the values of the field is skewed according to the MCVs. */
+				if (sslot.nvalues > 1 &&
+						sslot.numbers[0] > sslot.numbers[sslot.nvalues - 1] * 10)
+					/* Compare the maximum and minimum quantities in the MCVs. */
+					*skewed_stat = true;
+				else
+				{
+					/*
+					 * Compare the maximum number in the MCVs with the average number of
+					 * other values(not in the MCVs).
+					 */
+					double		sumcommon = 0.0;
+					double		otherdistinct;
+
+					for (i = 0; i < sslot.nnumbers; i++)
+						sumcommon += sslot.numbers[i];
+
+					otherdistinct = get_variable_numdistinct(vardata, &isdefault) -
+						sslot.nnumbers;
+
+					if (otherdistinct > 0)
+					{
+						if (sslot.numbers[0] > ((1.0 - sumcommon - nullfrac) / otherdistinct) * 10)
+							*skewed_stat = true;
+					}
+				}
+			}
 		}
 		else
 		{
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 5194cbf2cc..401418319b 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -991,6 +991,20 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist,
 	else
 		plan_context = CurrentMemoryContext;
 
+	if (boundParams)
+	{
+		int i;
+
+		for (i =0; i < boundParams->numParams; i++)
+		{
+			if (boundParams->params[i].pflags & PARAM_FLAG_SKEWEDSTAT)
+			{
+				plansource->hasSkewedparam = true;
+				break;
+			}
+		}
+	}
+
 	/*
 	 * Create and fill the CachedPlan struct within the new context.
 	 */
@@ -1066,6 +1080,9 @@ choose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams)
 	if (plan_cache_mode == PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN)
 		return true;
 
+	if (plansource->hasSkewedparam)
+		return true;
+
 	/* See if caller wants to force the decision */
 	if (plansource->cursor_options & CURSOR_OPT_GENERIC_PLAN)
 		return false;
diff --git a/src/include/Makefile b/src/include/Makefile
index 584d0300d9..080bf81867 100644
--- a/src/include/Makefile
+++ b/src/include/Makefile
@@ -51,6 +51,7 @@ install: all installdirs
 	$(INSTALL_DATA) utils/fmgrprotos.h '$(DESTDIR)$(includedir_server)/utils'
 	$(INSTALL_DATA) $(srcdir)/*.h '$(DESTDIR)$(includedir_server)'
 	for dir in $(SUBDIRS); do \
+	  pwd \
 	  $(INSTALL_DATA) $(srcdir)/$$dir/*.h '$(DESTDIR)$(includedir_server)'/$$dir || exit; \
 	done
 ifeq ($(vpath_build),yes)
diff --git a/src/include/nodes/params.h b/src/include/nodes/params.h
index 10c9fc5413..051a12bb1d 100644
--- a/src/include/nodes/params.h
+++ b/src/include/nodes/params.h
@@ -85,7 +85,13 @@ struct ParseState;
  *	  and paramCompileArg is rather arbitrary.
  */
 
-#define PARAM_FLAG_CONST	0x0001	/* parameter is constant */
+/* parameter is constant */
+#define PARAM_FLAG_CONST			0x0001
+/*
+ * The var side of 'var eq param' or 'param eq var' expression
+ * corresponding to the parameter contains skewed data.
+ */
+#define PARAM_FLAG_SKEWEDSTAT		0x0002
 
 typedef struct ParamExternData
 {
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 4a154606d2..7e6762de47 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -314,6 +314,12 @@ typedef struct Const
 	 */
 	bool		constbyval pg_node_attr(query_jumble_ignore);
 
+	/*
+	 * >0 indicates that the constant is extracted from Param.
+	 * Its value is paramid of the Param struct.
+	 */
+	int			paramid pg_node_attr(query_jumble_ignore);
+
 	/*
 	 * token location, or -1 if unknown.  All constants are tracked as
 	 * locations in query jumbling, to be marked as parameters.
diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h
index a90dfdf906..71209e029f 100644
--- a/src/include/utils/plancache.h
+++ b/src/include/utils/plancache.h
@@ -124,6 +124,7 @@ typedef struct CachedPlanSource
 	bool		is_complete;	/* has CompleteCachedPlan been done? */
 	bool		is_saved;		/* has CachedPlanSource been "saved"? */
 	bool		is_valid;		/* is the query_list currently valid? */
+	bool		hasSkewedparam; /* see the definition of PARAM FLAG SKEWEDSTAT */
 	int			generation;		/* increments each time we create a plan */
 	/* If CachedPlanSource has been saved, it is a member of a global list */
 	dlist_node	node;			/* list link, if is_saved */
diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h
index 2fa4c4fc1b..a7532b8d7b 100644
--- a/src/include/utils/selfuncs.h
+++ b/src/include/utils/selfuncs.h
@@ -184,6 +184,10 @@ extern double var_eq_const(VariableStatData *vardata,
 						   Oid oproid, Oid collation,
 						   Datum constval, bool constisnull,
 						   bool varonleft, bool negate);
+extern double var_eq_const_ext(VariableStatData *vardata,
+						   Oid oproid, Oid collation,
+						   Datum constval, bool constisnull,
+						   bool varonleft, bool negate, bool *skewed_stat);
 extern double var_eq_non_const(VariableStatData *vardata,
 							   Oid oproid, Oid collation,
 							   Node *other,