#include "executor/executor.h"
#include "executor/spi.h"
#include "nodes/nodeFuncs.h"
+#include "optimizer/cost.h"
#include "optimizer/planmain.h"
#include "optimizer/prep.h"
#include "parser/analyze.h"
ParamListInfo boundParams);
static bool choose_custom_plan(CachedPlanSource *plansource,
ParamListInfo boundParams);
-static double cached_plan_cost(CachedPlan *plan);
+static double cached_plan_cost(CachedPlan *plan, bool include_planner);
static void AcquireExecutorLocks(List *stmt_list, bool acquire);
static void AcquirePlannerLocks(List *stmt_list, bool acquire);
static void ScanQueryForLocks(Query *parsetree, bool acquire);
avg_custom_cost = plansource->total_custom_cost / plansource->num_custom_plans;
/*
- * Prefer generic plan if it's less than 10% more expensive than average
- * custom plan. This threshold is a bit arbitrary; it'd be better if we
- * had some means of comparing planning time to the estimated runtime cost
- * differential.
+ * Prefer generic plan if it's less expensive than the average custom
+ * plan. (Because we include a charge for cost of planning in the
+ * custom-plan costs, this means the generic plan only has to be less
+ * expensive than the execution cost plus replan cost of the custom
+ * plans.)
*
* Note that if generic_cost is -1 (indicating we've not yet determined
* the generic plan cost), we'll always prefer generic at this point.
*/
- if (plansource->generic_cost < avg_custom_cost * 1.1)
+ if (plansource->generic_cost < avg_custom_cost)
return false;
return true;
/*
* cached_plan_cost: calculate estimated cost of a plan
+ *
+ * If include_planner is true, also include the estimated cost of constructing
+ * the plan. (We must factor that into the cost of using a custom plan, but
+ * we don't count it for a generic plan.)
*/
static double
-cached_plan_cost(CachedPlan *plan)
+cached_plan_cost(CachedPlan *plan, bool include_planner)
{
double result = 0;
ListCell *lc;
continue; /* Ignore utility statements */
result += plannedstmt->planTree->total_cost;
+
+ if (include_planner)
+ {
+ /*
+ * Currently we use a very crude estimate of planning effort based
+ * on the number of relations in the finished plan's rangetable.
+ * Join planning effort actually scales much worse than linearly
+ * in the number of relations --- but only until the join collapse
+ * limits kick in. Also, while inheritance child relations surely
+ * add to planning effort, they don't make the join situation
+ * worse. So the actual shape of the planning cost curve versus
+ * number of relations isn't all that obvious. It will take
+ * considerable work to arrive at a less crude estimate, and for
+ * now it's not clear that's worth doing.
+ *
+ * The other big difficulty here is that we don't have any very
+ * good model of how planning cost compares to execution costs.
+ * The current multiplier of 1000 * cpu_operator_cost is probably
+ * on the low side, but we'll try this for awhile before making a
+ * more aggressive correction.
+ *
+ * If we ever do write a more complicated estimator, it should
+ * probably live in src/backend/optimizer/ not here.
+ */
+ int nrelations = list_length(plannedstmt->rtable);
+
+ result += 1000.0 * cpu_operator_cost * (nrelations + 1);
+ }
}
return result;
MemoryContextGetParent(plansource->context));
}
/* Update generic_cost whenever we make a new generic plan */
- plansource->generic_cost = cached_plan_cost(plan);
+ plansource->generic_cost = cached_plan_cost(plan, false);
/*
* If, based on the now-known value of generic_cost, we'd not have
/* Accumulate total costs of custom plans, but 'ware overflow */
if (plansource->num_custom_plans < INT_MAX)
{
- plansource->total_custom_cost += cached_plan_cost(plan);
+ plansource->total_custom_cost += cached_plan_cost(plan, true);
plansource->num_custom_plans++;
}
}