mirror of
https://github.com/postgres/postgres.git
synced 2025-11-18 02:02:55 +03:00
Make the upper part of the planner work by generating and comparing Paths.
I've been saying we needed to do this for more than five years, and here it finally is. This patch removes the ever-growing tangle of spaghetti logic that grouping_planner() used to use to try to identify the best plan for post-scan/join query steps. Now, there is (nearly) independent consideration of each execution step, and entirely separate construction of Paths to represent each of the possible ways to do that step. We choose the best Path or set of Paths using the same add_path() logic that's been used inside query_planner() for years. In addition, this patch removes the old restriction that subquery_planner() could return only a single Plan. It now returns a RelOptInfo containing a set of Paths, just as query_planner() does, and the parent query level can use each of those Paths as the basis of a SubqueryScanPath at its level. This allows finding some optimizations that we missed before, wherein a subquery was capable of returning presorted data and thereby avoiding a sort in the parent level, making the overall cost cheaper even though delivering sorted output was not the cheapest plan for the subquery in isolation. (A couple of regression test outputs change in consequence of that. However, there is very little change in visible planner behavior overall, because the point of this patch is not to get immediate planning benefits but to create the infrastructure for future improvements.) There is a great deal left to do here. This patch unblocks a lot of planner work that was basically impractical in the old code structure, such as allowing FDWs to implement remote aggregation, or rewriting plan_set_operations() to allow consideration of multiple implementation orders for set operations. (The latter will likely require a full rewrite of plan_set_operations(); what I've done here is only to fix it to return Paths not Plans.) I have also left unfinished some localized refactoring in createplan.c and planner.c, because it was not necessary to get this patch to a working state. Thanks to Robert Haas, David Rowley, and Amit Kapila for review.
This commit is contained in:
@@ -85,7 +85,7 @@ extern void cost_bitmap_or_node(BitmapOrPath *path, PlannerInfo *root);
|
||||
extern void cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec);
|
||||
extern void cost_tidscan(Path *path, PlannerInfo *root,
|
||||
RelOptInfo *baserel, List *tidquals, ParamPathInfo *param_info);
|
||||
extern void cost_subqueryscan(Path *path, PlannerInfo *root,
|
||||
extern void cost_subqueryscan(SubqueryScanPath *path, PlannerInfo *root,
|
||||
RelOptInfo *baserel, ParamPathInfo *param_info);
|
||||
extern void cost_functionscan(Path *path, PlannerInfo *root,
|
||||
RelOptInfo *baserel, ParamPathInfo *param_info);
|
||||
@@ -93,7 +93,7 @@ extern void cost_valuesscan(Path *path, PlannerInfo *root,
|
||||
RelOptInfo *baserel, ParamPathInfo *param_info);
|
||||
extern void cost_ctescan(Path *path, PlannerInfo *root,
|
||||
RelOptInfo *baserel, ParamPathInfo *param_info);
|
||||
extern void cost_recursive_union(Plan *runion, Plan *nrterm, Plan *rterm);
|
||||
extern void cost_recursive_union(Path *runion, Path *nrterm, Path *rterm);
|
||||
extern void cost_sort(Path *path, PlannerInfo *root,
|
||||
List *pathkeys, Cost input_cost, double tuples, int width,
|
||||
Cost comparison_cost, int sort_mem,
|
||||
@@ -180,8 +180,9 @@ extern void set_subquery_size_estimates(PlannerInfo *root, RelOptInfo *rel);
|
||||
extern void set_function_size_estimates(PlannerInfo *root, RelOptInfo *rel);
|
||||
extern void set_values_size_estimates(PlannerInfo *root, RelOptInfo *rel);
|
||||
extern void set_cte_size_estimates(PlannerInfo *root, RelOptInfo *rel,
|
||||
Plan *cteplan);
|
||||
double cte_rows);
|
||||
extern void set_foreign_size_estimates(PlannerInfo *root, RelOptInfo *rel);
|
||||
extern PathTarget *set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target);
|
||||
|
||||
/*
|
||||
* prototypes for clausesel.c
|
||||
|
||||
@@ -68,13 +68,15 @@ extern MergeAppendPath *create_merge_append_path(PlannerInfo *root,
|
||||
List *subpaths,
|
||||
List *pathkeys,
|
||||
Relids required_outer);
|
||||
extern ResultPath *create_result_path(RelOptInfo *rel, List *quals);
|
||||
extern ResultPath *create_result_path(RelOptInfo *rel,
|
||||
PathTarget *target, List *quals);
|
||||
extern MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath);
|
||||
extern UniquePath *create_unique_path(PlannerInfo *root, RelOptInfo *rel,
|
||||
Path *subpath, SpecialJoinInfo *sjinfo);
|
||||
extern GatherPath *create_gather_path(PlannerInfo *root,
|
||||
RelOptInfo *rel, Path *subpath, Relids required_outer);
|
||||
extern Path *create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel,
|
||||
extern SubqueryScanPath *create_subqueryscan_path(PlannerInfo *root,
|
||||
RelOptInfo *rel, Path *subpath,
|
||||
List *pathkeys, Relids required_outer);
|
||||
extern Path *create_functionscan_path(PlannerInfo *root, RelOptInfo *rel,
|
||||
List *pathkeys, Relids required_outer);
|
||||
@@ -132,6 +134,96 @@ extern HashPath *create_hashjoin_path(PlannerInfo *root,
|
||||
Relids required_outer,
|
||||
List *hashclauses);
|
||||
|
||||
extern ProjectionPath *create_projection_path(PlannerInfo *root,
|
||||
RelOptInfo *rel,
|
||||
Path *subpath,
|
||||
PathTarget *target);
|
||||
extern Path *apply_projection_to_path(PlannerInfo *root,
|
||||
RelOptInfo *rel,
|
||||
Path *path,
|
||||
PathTarget *target);
|
||||
extern SortPath *create_sort_path(PlannerInfo *root,
|
||||
RelOptInfo *rel,
|
||||
Path *subpath,
|
||||
List *pathkeys,
|
||||
double limit_tuples);
|
||||
extern GroupPath *create_group_path(PlannerInfo *root,
|
||||
RelOptInfo *rel,
|
||||
Path *subpath,
|
||||
PathTarget *target,
|
||||
List *groupClause,
|
||||
List *qual,
|
||||
double numGroups);
|
||||
extern UpperUniquePath *create_upper_unique_path(PlannerInfo *root,
|
||||
RelOptInfo *rel,
|
||||
Path *subpath,
|
||||
int numCols,
|
||||
double numGroups);
|
||||
extern AggPath *create_agg_path(PlannerInfo *root,
|
||||
RelOptInfo *rel,
|
||||
Path *subpath,
|
||||
PathTarget *target,
|
||||
AggStrategy aggstrategy,
|
||||
List *groupClause,
|
||||
List *qual,
|
||||
const AggClauseCosts *aggcosts,
|
||||
double numGroups);
|
||||
extern GroupingSetsPath *create_groupingsets_path(PlannerInfo *root,
|
||||
RelOptInfo *rel,
|
||||
Path *subpath,
|
||||
PathTarget *target,
|
||||
List *having_qual,
|
||||
AttrNumber *groupColIdx,
|
||||
List *rollup_lists,
|
||||
List *rollup_groupclauses,
|
||||
const AggClauseCosts *agg_costs,
|
||||
double numGroups);
|
||||
extern MinMaxAggPath *create_minmaxagg_path(PlannerInfo *root,
|
||||
RelOptInfo *rel,
|
||||
PathTarget *target,
|
||||
List *mmaggregates,
|
||||
List *quals);
|
||||
extern WindowAggPath *create_windowagg_path(PlannerInfo *root,
|
||||
RelOptInfo *rel,
|
||||
Path *subpath,
|
||||
PathTarget *target,
|
||||
List *windowFuncs,
|
||||
WindowClause *winclause,
|
||||
List *winpathkeys);
|
||||
extern SetOpPath *create_setop_path(PlannerInfo *root,
|
||||
RelOptInfo *rel,
|
||||
Path *subpath,
|
||||
SetOpCmd cmd,
|
||||
SetOpStrategy strategy,
|
||||
List *distinctList,
|
||||
AttrNumber flagColIdx,
|
||||
int firstFlag,
|
||||
double numGroups,
|
||||
double outputRows);
|
||||
extern RecursiveUnionPath *create_recursiveunion_path(PlannerInfo *root,
|
||||
RelOptInfo *rel,
|
||||
Path *leftpath,
|
||||
Path *rightpath,
|
||||
PathTarget *target,
|
||||
List *distinctList,
|
||||
int wtParam,
|
||||
double numGroups);
|
||||
extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
|
||||
Path *subpath, List *rowMarks, int epqParam);
|
||||
extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
|
||||
RelOptInfo *rel,
|
||||
CmdType operation, bool canSetTag,
|
||||
Index nominalRelation,
|
||||
List *resultRelations, List *subpaths,
|
||||
List *subroots,
|
||||
List *withCheckOptionLists, List *returningLists,
|
||||
List *rowMarks, OnConflictExpr *onconflict,
|
||||
int epqParam);
|
||||
extern LimitPath *create_limit_path(PlannerInfo *root, RelOptInfo *rel,
|
||||
Path *subpath,
|
||||
Node *limitOffset, Node *limitCount,
|
||||
int64 offset_est, int64 count_est);
|
||||
|
||||
extern Path *reparameterize_path(PlannerInfo *root, Path *path,
|
||||
Relids required_outer,
|
||||
double loop_count);
|
||||
@@ -155,6 +247,8 @@ extern Relids min_join_parameterization(PlannerInfo *root,
|
||||
RelOptInfo *outer_rel,
|
||||
RelOptInfo *inner_rel);
|
||||
extern RelOptInfo *build_empty_join_rel(PlannerInfo *root);
|
||||
extern RelOptInfo *fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind,
|
||||
Relids relids);
|
||||
extern AppendRelInfo *find_childrel_appendrelinfo(PlannerInfo *root,
|
||||
RelOptInfo *rel);
|
||||
extern RelOptInfo *find_childrel_top_parent(PlannerInfo *root, RelOptInfo *rel);
|
||||
|
||||
@@ -47,6 +47,7 @@ extern PGDLLIMPORT join_search_hook_type join_search_hook;
|
||||
|
||||
|
||||
extern RelOptInfo *make_one_rel(PlannerInfo *root, List *joinlist);
|
||||
extern void set_dummy_rel_pathlist(RelOptInfo *rel);
|
||||
extern RelOptInfo *standard_join_search(PlannerInfo *root, int levels_needed,
|
||||
List *initial_rels);
|
||||
|
||||
@@ -137,10 +138,6 @@ extern void add_child_rel_equivalences(PlannerInfo *root,
|
||||
AppendRelInfo *appinfo,
|
||||
RelOptInfo *parent_rel,
|
||||
RelOptInfo *child_rel);
|
||||
extern void mutate_eclass_expressions(PlannerInfo *root,
|
||||
Node *(*mutator) (),
|
||||
void *context,
|
||||
bool include_child_exprs);
|
||||
extern List *generate_implied_equalities_for_column(PlannerInfo *root,
|
||||
RelOptInfo *rel,
|
||||
ec_matches_callback_type callback,
|
||||
@@ -182,7 +179,8 @@ extern List *build_expression_pathkey(PlannerInfo *root, Expr *expr,
|
||||
Relids nullable_relids, Oid opno,
|
||||
Relids rel, bool create_it);
|
||||
extern List *convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
|
||||
List *subquery_pathkeys);
|
||||
List *subquery_pathkeys,
|
||||
List *subquery_tlist);
|
||||
extern List *build_join_pathkeys(PlannerInfo *root,
|
||||
RelOptInfo *joinrel,
|
||||
JoinType jointype,
|
||||
|
||||
@@ -43,60 +43,17 @@ extern RelOptInfo *query_planner(PlannerInfo *root, List *tlist,
|
||||
* prototypes for plan/planagg.c
|
||||
*/
|
||||
extern void preprocess_minmax_aggregates(PlannerInfo *root, List *tlist);
|
||||
extern Plan *optimize_minmax_aggregates(PlannerInfo *root, List *tlist,
|
||||
const AggClauseCosts *aggcosts, Path *best_path);
|
||||
|
||||
/*
|
||||
* prototypes for plan/createplan.c
|
||||
*/
|
||||
extern Plan *create_plan(PlannerInfo *root, Path *best_path);
|
||||
extern SubqueryScan *make_subqueryscan(List *qptlist, List *qpqual,
|
||||
Index scanrelid, Plan *subplan);
|
||||
extern ForeignScan *make_foreignscan(List *qptlist, List *qpqual,
|
||||
Index scanrelid, List *fdw_exprs, List *fdw_private,
|
||||
List *fdw_scan_tlist, List *fdw_recheck_quals,
|
||||
Plan *outer_plan);
|
||||
extern Append *make_append(List *appendplans, List *tlist);
|
||||
extern RecursiveUnion *make_recursive_union(List *tlist,
|
||||
Plan *lefttree, Plan *righttree, int wtParam,
|
||||
List *distinctList, long numGroups);
|
||||
extern Sort *make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree,
|
||||
List *pathkeys, double limit_tuples);
|
||||
extern Sort *make_sort_from_sortclauses(PlannerInfo *root, List *sortcls,
|
||||
Plan *lefttree);
|
||||
extern Sort *make_sort_from_groupcols(PlannerInfo *root, List *groupcls,
|
||||
AttrNumber *grpColIdx, Plan *lefttree);
|
||||
extern Agg *make_agg(PlannerInfo *root, List *tlist, List *qual,
|
||||
AggStrategy aggstrategy, const AggClauseCosts *aggcosts,
|
||||
int numGroupCols, AttrNumber *grpColIdx, Oid *grpOperators,
|
||||
List *groupingSets, long numGroups, bool combineStates,
|
||||
bool finalizeAggs, Plan *lefttree);
|
||||
extern WindowAgg *make_windowagg(PlannerInfo *root, List *tlist,
|
||||
List *windowFuncs, Index winref,
|
||||
int partNumCols, AttrNumber *partColIdx, Oid *partOperators,
|
||||
int ordNumCols, AttrNumber *ordColIdx, Oid *ordOperators,
|
||||
int frameOptions, Node *startOffset, Node *endOffset,
|
||||
Plan *lefttree);
|
||||
extern Group *make_group(PlannerInfo *root, List *tlist, List *qual,
|
||||
int numGroupCols, AttrNumber *grpColIdx, Oid *grpOperators,
|
||||
double numGroups,
|
||||
Plan *lefttree);
|
||||
extern Plan *materialize_finished_plan(Plan *subplan);
|
||||
extern Unique *make_unique(Plan *lefttree, List *distinctList);
|
||||
extern LockRows *make_lockrows(Plan *lefttree, List *rowMarks, int epqParam);
|
||||
extern Limit *make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount,
|
||||
int64 offset_est, int64 count_est);
|
||||
extern SetOp *make_setop(SetOpCmd cmd, SetOpStrategy strategy, Plan *lefttree,
|
||||
List *distinctList, AttrNumber flagColIdx, int firstFlag,
|
||||
long numGroups, double outputRows);
|
||||
extern Result *make_result(PlannerInfo *root, List *tlist,
|
||||
Node *resconstantqual, Plan *subplan);
|
||||
extern ModifyTable *make_modifytable(PlannerInfo *root,
|
||||
CmdType operation, bool canSetTag,
|
||||
Index nominalRelation,
|
||||
List *resultRelations, List *subplans,
|
||||
List *withCheckOptionLists, List *returningLists,
|
||||
List *rowMarks, OnConflictExpr *onconflict, int epqParam);
|
||||
extern bool is_projection_capable_path(Path *path);
|
||||
extern bool is_projection_capable_plan(Plan *plan);
|
||||
|
||||
/*
|
||||
|
||||
@@ -30,19 +30,18 @@ extern PlannedStmt *planner(Query *parse, int cursorOptions,
|
||||
extern PlannedStmt *standard_planner(Query *parse, int cursorOptions,
|
||||
ParamListInfo boundParams);
|
||||
|
||||
extern Plan *subquery_planner(PlannerGlobal *glob, Query *parse,
|
||||
extern PlannerInfo *subquery_planner(PlannerGlobal *glob, Query *parse,
|
||||
PlannerInfo *parent_root,
|
||||
bool hasRecursion, double tuple_fraction,
|
||||
PlannerInfo **subroot);
|
||||
|
||||
extern void add_tlist_costs_to_plan(PlannerInfo *root, Plan *plan,
|
||||
List *tlist);
|
||||
bool hasRecursion, double tuple_fraction);
|
||||
|
||||
extern bool is_dummy_plan(Plan *plan);
|
||||
|
||||
extern RowMarkType select_rowmark_type(RangeTblEntry *rte,
|
||||
LockClauseStrength strength);
|
||||
|
||||
extern Path *get_cheapest_fractional_path(RelOptInfo *rel,
|
||||
double tuple_fraction);
|
||||
|
||||
extern Expr *expression_planner(Expr *expr);
|
||||
|
||||
extern Expr *preprocess_phv_expression(PlannerInfo *root, Expr *expr);
|
||||
|
||||
@@ -53,8 +53,7 @@ extern PlanRowMark *get_plan_rowmark(List *rowmarks, Index rtindex);
|
||||
/*
|
||||
* prototypes for prepunion.c
|
||||
*/
|
||||
extern Plan *plan_set_operations(PlannerInfo *root, double tuple_fraction,
|
||||
List **sortClauses);
|
||||
extern RelOptInfo *plan_set_operations(PlannerInfo *root);
|
||||
|
||||
extern void expand_inherited_tables(PlannerInfo *root);
|
||||
|
||||
|
||||
@@ -26,11 +26,15 @@ extern JoinExpr *convert_EXISTS_sublink_to_join(PlannerInfo *root,
|
||||
extern Node *SS_replace_correlation_vars(PlannerInfo *root, Node *expr);
|
||||
extern Node *SS_process_sublinks(PlannerInfo *root, Node *expr, bool isQual);
|
||||
extern void SS_identify_outer_params(PlannerInfo *root);
|
||||
extern void SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel);
|
||||
extern void SS_attach_initplans(PlannerInfo *root, Plan *plan);
|
||||
extern void SS_finalize_plan(PlannerInfo *root, Plan *plan);
|
||||
extern Param *SS_make_initplan_from_plan(PlannerInfo *root,
|
||||
extern Param *SS_make_initplan_output_param(PlannerInfo *root,
|
||||
Oid resulttype, int32 resulttypmod,
|
||||
Oid resultcollation);
|
||||
extern void SS_make_initplan_from_plan(PlannerInfo *root,
|
||||
PlannerInfo *subroot, Plan *plan,
|
||||
Oid resulttype, int32 resulttypmod, Oid resultcollation);
|
||||
Param *prm);
|
||||
extern Param *assign_nestloop_param_var(PlannerInfo *root, Var *var);
|
||||
extern Param *assign_nestloop_param_placeholdervar(PlannerInfo *root,
|
||||
PlaceHolderVar *phv);
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
extern TargetEntry *tlist_member(Node *node, List *targetlist);
|
||||
extern TargetEntry *tlist_member_ignore_relabel(Node *node, List *targetlist);
|
||||
extern TargetEntry *tlist_member_match_var(Var *var, List *targetlist);
|
||||
|
||||
extern List *flatten_tlist(List *tlist, PVCAggregateBehavior aggbehavior,
|
||||
PVCPlaceHolderBehavior phbehavior);
|
||||
@@ -34,6 +33,8 @@ extern bool tlist_same_exprs(List *tlist1, List *tlist2);
|
||||
extern bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK);
|
||||
extern bool tlist_same_collations(List *tlist, List *colCollations, bool junkOK);
|
||||
|
||||
extern void apply_tlist_labeling(List *dest_tlist, List *src_tlist);
|
||||
|
||||
extern TargetEntry *get_sortgroupref_tle(Index sortref,
|
||||
List *targetList);
|
||||
extern TargetEntry *get_sortgroupclause_tle(SortGroupClause *sgClause,
|
||||
@@ -51,4 +52,12 @@ extern AttrNumber *extract_grouping_cols(List *groupClause, List *tlist);
|
||||
extern bool grouping_is_sortable(List *groupClause);
|
||||
extern bool grouping_is_hashable(List *groupClause);
|
||||
|
||||
extern PathTarget *make_pathtarget_from_tlist(List *tlist);
|
||||
extern List *make_tlist_from_pathtarget(PathTarget *target);
|
||||
extern void apply_pathtarget_labeling_to_tlist(List *tlist, PathTarget *target);
|
||||
|
||||
/* Convenience macro to get a PathTarget with valid cost/width fields */
|
||||
#define create_pathtarget(root, tlist) \
|
||||
set_pathtarget_cost_width(root, make_pathtarget_from_tlist(tlist))
|
||||
|
||||
#endif /* TLIST_H */
|
||||
|
||||
Reference in New Issue
Block a user