From 85d1f50909864a2e56013ebfc20e619d801ff569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=80=E6=8C=83?= Date: Mon, 17 Aug 2020 21:49:40 +0800 Subject: [PATCH v1] Convert the AlternativeSubplan to Subplan as soon as we knows the num_calls --- src/backend/optimizer/path/allpaths.c | 34 ++++++++++++++++++++++++++ src/backend/optimizer/path/costsize.c | 6 ++--- src/backend/optimizer/plan/subselect.c | 28 +++++++++++++++++++++ src/backend/optimizer/util/relnode.c | 33 +++++++++++++++++++++++++ src/include/optimizer/planner.h | 1 + src/include/optimizer/subselect.h | 4 ++- 6 files changed, 102 insertions(+), 4 deletions(-) diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 6da0dcd61c..5aa466c80d 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -41,6 +41,7 @@ #include "optimizer/plancat.h" #include "optimizer/planner.h" #include "optimizer/restrictinfo.h" +#include "optimizer/subselect.h" #include "optimizer/tlist.h" #include "parser/parse_clause.h" #include "parser/parsetree.h" @@ -767,6 +768,39 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) { Relids required_outer; + /* + * We have known the size of the rel, if there is altPlan on this rel + * we can choose now. In this demo, I just track the alt plan in targetlist. + */ + ListCell *lc; + bool recost = false; + foreach(lc, rel->reltarget->exprs) + { + if (IsA(lfirst(lc), PlaceHolderVar)) + { + bool recost_expr = false; + PlaceHolderVar *phv = lfirst_node(PlaceHolderVar, lc); + if (bms_is_subset(phv->phrels, rel->relids) && + IsA(phv->phexpr, AlternativeSubPlan)) + { + phv->phexpr = (Expr *)choose_subplan((AlternativeSubPlan *)phv->phexpr, + rel->rows, + &recost_expr); + if (recost_expr) + recost = true; + } + } + } + + if (recost) + { + set_rel_width(root, rel); + } + + /* + * TODO: we can also check subplan in other places + */ + /* * We don't support pushing join clauses into the quals of a seqscan, but * it could still have required parameterization due to LATERAL refs in diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index fda4b2c6e8..c730d1bacf 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -91,6 +91,7 @@ #include "optimizer/plancat.h" #include "optimizer/planmain.h" #include "optimizer/restrictinfo.h" +#include "optimizer/planner.h" #include "parser/parsetree.h" #include "utils/lsyscache.h" #include "utils/selfuncs.h" @@ -175,7 +176,6 @@ static Selectivity get_foreign_key_join_selectivity(PlannerInfo *root, List **restrictlist); static Cost append_nonpartial_cost(List *subpaths, int numpaths, int parallel_workers); -static void set_rel_width(PlannerInfo *root, RelOptInfo *rel); static double relation_byte_size(double tuples, int width); static double page_size(double tuples, int width); static double get_parallel_divisor(Path *path); @@ -1774,7 +1774,7 @@ cost_tuplesort(Cost *startup_cost, Cost *run_cost, /* * cost_incremental_sort - * Determines and returns the cost of sorting a relation incrementally, when + * Determines and returns the cost of sorting a relation incrementally, when * the input path is presorted by a prefix of the pathkeys. * * 'presorted_keys' is the number of leading pathkeys by which the input path @@ -5438,7 +5438,7 @@ set_foreign_size_estimates(PlannerInfo *root, RelOptInfo *rel) * The per-attribute width estimates are cached for possible re-use while * building join relations or post-scan/join pathtargets. */ -static void +void set_rel_width(PlannerInfo *root, RelOptInfo *rel) { Oid reloid = planner_rt_fetch(rel->relid, root)->relid; diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 6eb794669f..721f8bd06d 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -2959,3 +2959,31 @@ SS_make_initplan_from_plan(PlannerInfo *root, /* Set costs of SubPlan using info from the plan tree */ cost_subplan(subroot, node, plan); } + + +/* + * Choose the subplan from AlternativeSubPlan as soon as possible. + */ +SubPlan * +choose_subplan(AlternativeSubPlan *altplan, double num_calls, bool *recost) +{ + + double cost1, cost2; + SubPlan *subplan1, *subplan2, *res; + subplan1 = linitial_node(SubPlan, altplan->subplans); + subplan2 = lsecond_node(SubPlan, altplan->subplans); + cost1 = subplan1->startup_cost + num_calls * subplan1->per_call_cost; + cost2 = subplan2->startup_cost + num_calls * subplan2->per_call_cost; + + if (cost1 < cost2) + { + res = subplan1; + *recost = false; + } + else + { + res = subplan2; + *recost = true; + } + return res; +} diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index a203e6f1ff..318546a4c4 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -27,6 +27,7 @@ #include "optimizer/placeholder.h" #include "optimizer/plancat.h" #include "optimizer/restrictinfo.h" +#include "optimizer/subselect.h" #include "optimizer/tlist.h" #include "utils/hsearch.h" #include "utils/lsyscache.h" @@ -728,6 +729,38 @@ build_join_rel(PlannerInfo *root, set_joinrel_size_estimates(root, joinrel, outer_rel, inner_rel, sjinfo, restrictlist); + /* Fix the AlternativeSubPlans */ + { + ListCell *lc; + bool recost = false; + foreach(lc, joinrel->reltarget->exprs) + { + if (IsA(lfirst(lc), PlaceHolderVar)) + { + bool recost_expr = false; + PlaceHolderVar *phv = lfirst_node(PlaceHolderVar, lc); + if (bms_is_subset(phv->phrels, joinrel->relids) && + IsA(phv->phexpr, AlternativeSubPlan)) + { + phv->phexpr = (Expr *)choose_subplan((AlternativeSubPlan *)phv->phexpr, + joinrel->rows, + &recost_expr); + if(recost_expr) + recost = true; + /* track how many exprs are changed, old_ones (AlternativeSubplans) + * and new_ones (SubPlans) + */ + } + } + } + + if (recost) + { + /* get the delta cost by old_costs and new_costs, and then + * modify the cost of the path in outer_rel and inner_rel. + */ + } + } /* * Set the consider_parallel flag if this joinrel could potentially be * scanned within a parallel worker. If this flag is false for either diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h index beb7dbbcbe..a7a7b32eff 100644 --- a/src/include/optimizer/planner.h +++ b/src/include/optimizer/planner.h @@ -58,4 +58,5 @@ extern Path *get_cheapest_fractional_path(RelOptInfo *rel, extern Expr *preprocess_phv_expression(PlannerInfo *root, Expr *expr); +extern void set_rel_width(PlannerInfo *root, RelOptInfo *rel); #endif /* PLANNER_H */ diff --git a/src/include/optimizer/subselect.h b/src/include/optimizer/subselect.h index d6a872bd2c..136d60b7c0 100644 --- a/src/include/optimizer/subselect.h +++ b/src/include/optimizer/subselect.h @@ -36,5 +36,7 @@ extern Param *SS_make_initplan_output_param(PlannerInfo *root, extern void SS_make_initplan_from_plan(PlannerInfo *root, PlannerInfo *subroot, Plan *plan, Param *prm); - +extern SubPlan *choose_subplan(AlternativeSubPlan *altplan, + double num_calls, + bool *recost); #endif /* SUBSELECT_H */ -- 2.21.0