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,