Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
332 changes: 264 additions & 68 deletions src/backend/optimizer/path/allpaths.c

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/backend/optimizer/path/costsize.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ bool enable_parallel_hash = true;
bool enable_partition_pruning = true;
bool enable_presorted_aggregate = true;
bool enable_async_append = true;
bool enable_join_predicate_pushdown = true;

typedef struct
{
Expand Down Expand Up @@ -5564,9 +5565,8 @@ get_foreign_key_join_selectivity(PlannerInfo *root,
* We set the same fields as set_baserel_size_estimates.
*/
void
set_subquery_size_estimates(PlannerInfo *root, RelOptInfo *rel)
set_subquery_size_estimates(PlannerInfo *root, RelOptInfo *rel, PlannerInfo *subroot)
{
PlannerInfo *subroot = rel->subroot;
RelOptInfo *sub_final_rel;
ListCell *lc;

Expand Down
58 changes: 56 additions & 2 deletions src/backend/optimizer/plan/createplan.c
Original file line number Diff line number Diff line change
Expand Up @@ -3689,17 +3689,69 @@ create_subqueryscan_plan(PlannerInfo *root, SubqueryScanPath *best_path,
RelOptInfo *rel = best_path->path.parent;
Index scan_relid = rel->relid;
Plan *subplan;
ListCell *l;
List *qpqual;
List *sq_quals = best_path->pushed_down_clauses;

/* it should be a subquery base rel... */
Assert(scan_relid > 0);
Assert(rel->rtekind == RTE_SUBQUERY);
Assert(rel->chosen_plan == NULL);

/*
* Recursively create Plan from Path for subquery. Since we are entering
* a different planner context (subroot), recurse to create_plan not
* create_plan_recurse.
*/
subplan = create_plan(rel->subroot, best_path->subpath);
subplan = create_plan(best_path->subroot, best_path->subpath);

/*
* If this path used join quals that were pushed down to the subquery,
* we don't need to re-check those quals on the SubqueryScan node itself.
*/
if (best_path->pushed_down_clauses)
{
List *new_clauses = NIL;
ListCell *l;

foreach(l, scan_clauses)
{
RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);

if (list_member_ptr(best_path->pushed_down_clauses, rinfo))
continue;

new_clauses = lappend(new_clauses, rinfo);
}
scan_clauses = new_clauses;
}

/*
* If we had pushed down any join clauses to the subquery, we don't need
* to re-check them in the SubqueryScan node.
*
* This only applies to join clauses derived from equivalence classes.
* Non-join quals, and non-EC-derived join clauses are immediately removed
* from 'baserestrictinfo' and 'joininfo' when they're pushed down, so we
* won't need to worry about them here.
*/
qpqual = NIL;
foreach (l, scan_clauses)
{
RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);

if (rinfo->pseudoconstant)
continue; /* we may drop pseudoconstants here */
if (list_member_ptr(sq_quals, rinfo))
continue; /* simple duplicate */
if (is_redundant_derived_clause(rinfo, sq_quals))
continue; /* derived from same EquivalenceClass */
if (!contain_mutable_functions((Node *) rinfo->clause) &&
predicate_implied_by(list_make1(rinfo->clause), sq_quals, false))
continue; /* provably implied by indexquals */
qpqual = lappend(qpqual, rinfo);
}
scan_clauses = qpqual;

/* Sort clauses into best execution order */
scan_clauses = order_qual_clauses(root, scan_clauses);
Expand All @@ -3713,7 +3765,7 @@ create_subqueryscan_plan(PlannerInfo *root, SubqueryScanPath *best_path,
scan_clauses = (List *)
replace_nestloop_params(root, (Node *) scan_clauses);
process_subquery_nestloop_params(root,
rel->subplan_params);
best_path->subplan_params);
}

scan_plan = make_subqueryscan(tlist,
Expand All @@ -3723,6 +3775,8 @@ create_subqueryscan_plan(PlannerInfo *root, SubqueryScanPath *best_path,

copy_generic_path_info(&scan_plan->scan.plan, &best_path->path);

rel->chosen_plan = best_path->subroot;

return scan_plan;
}

Expand Down
8 changes: 4 additions & 4 deletions src/backend/optimizer/plan/setrefs.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,12 +460,12 @@ add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
* that some upper query level is treating this one as dummy,
* and so we won't scan this level's plan tree at all.
*/
if (rel->subroot == NULL)
if (rel->chosen_plan == NULL)
flatten_unplanned_rtes(glob, rte);
else if (recursing ||
IS_DUMMY_REL(fetch_upper_rel(rel->subroot,
IS_DUMMY_REL(fetch_upper_rel(rel->chosen_plan,
UPPERREL_FINAL, NULL)))
add_rtes_to_flat_rtable(rel->subroot, true);
add_rtes_to_flat_rtable(rel->chosen_plan, true);
}
}
rti++;
Expand Down Expand Up @@ -1387,7 +1387,7 @@ set_subqueryscan_references(PlannerInfo *root,
rel = find_base_rel(root, plan->scan.scanrelid);

/* Recursively process the subplan */
plan->subplan = set_plan_references(rel->subroot, plan->subplan);
plan->subplan = set_plan_references(rel->chosen_plan, plan->subplan);

if (trivial_subqueryscan(plan))
{
Expand Down
4 changes: 2 additions & 2 deletions src/backend/optimizer/plan/subselect.c
Original file line number Diff line number Diff line change
Expand Up @@ -2392,11 +2392,11 @@ finalize_plan(PlannerInfo *root, Plan *plan,

/* We must run finalize_plan on the subquery */
rel = find_base_rel(root, sscan->scan.scanrelid);
subquery_params = rel->subroot->outer_params;
subquery_params = rel->chosen_plan->outer_params;
if (gather_param >= 0)
subquery_params = bms_add_member(bms_copy(subquery_params),
gather_param);
finalize_plan(rel->subroot, sscan->subplan, gather_param,
finalize_plan(rel->chosen_plan, sscan->subplan, gather_param,
subquery_params, NULL);

/* Now we can add its extParams to the parent's params */
Expand Down
21 changes: 12 additions & 9 deletions src/backend/optimizer/prep/prepunion.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,10 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
Assert(root->plan_params == NIL);

/* Generate a subroot and Paths for the subquery */
subroot = rel->subroot = subquery_planner(root->glob, subquery,
root,
false,
root->tuple_fraction);
subroot = subquery_planner(root->glob, subquery,
root,
false,
root->tuple_fraction);

/*
* It should not be possible for the primitive query to contain any
Expand All @@ -268,7 +268,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
* to do this before generating outer-query paths, else
* cost_subqueryscan is not happy.
*/
set_subquery_size_estimates(root, rel);
set_subquery_size_estimates(root, rel, subroot);

/*
* Since we may want to add a partial path to this relation, we must
Expand All @@ -293,9 +293,12 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
* the SubqueryScanPath with nil pathkeys. (XXX that should change
* soon too, likely.)
*/
path = (Path *) create_subqueryscan_path(root, rel, subpath,
path = (Path *) create_subqueryscan_path(root, rel,
subroot,
NIL,
subpath,
trivial_tlist,
NIL, NULL);
NIL, NULL, NIL);

add_path(rel, path);

Expand All @@ -312,9 +315,9 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,

partial_subpath = linitial(final_rel->partial_pathlist);
partial_path = (Path *)
create_subqueryscan_path(root, rel, partial_subpath,
create_subqueryscan_path(root, rel, subroot, NIL, partial_subpath,
trivial_tlist,
NIL, NULL);
NIL, NULL, NIL);
add_partial_path(rel, partial_path);
}

Expand Down
17 changes: 13 additions & 4 deletions src/backend/optimizer/util/pathnode.c
Original file line number Diff line number Diff line change
Expand Up @@ -2015,9 +2015,12 @@ create_gather_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
* efficiently (or at least amortize it over multiple calls).
*/
SubqueryScanPath *
create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel,
PlannerInfo *subroot,
List *subplan_params,
Path *subpath,
bool trivial_pathtarget,
List *pathkeys, Relids required_outer)
List *pathkeys, Relids required_outer, List *pushed_down_clauses)
{
SubqueryScanPath *pathnode = makeNode(SubqueryScanPath);

Expand All @@ -2032,6 +2035,9 @@ create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
pathnode->path.parallel_workers = subpath->parallel_workers;
pathnode->path.pathkeys = pathkeys;
pathnode->subpath = subpath;
pathnode->subplan_params = subplan_params;
pathnode->subroot = subroot;
pathnode->pushed_down_clauses = pushed_down_clauses;

cost_subqueryscan(pathnode, root, rel, pathnode->path.param_info,
trivial_pathtarget);
Expand Down Expand Up @@ -3954,10 +3960,13 @@ reparameterize_path(PlannerInfo *root, Path *path,

return (Path *) create_subqueryscan_path(root,
rel,
subpath,
spath->subroot,
spath->subplan_params,
spath->subpath,
trivial_pathtarget,
spath->path.pathkeys,
required_outer);
required_outer,
spath->pushed_down_clauses);
}
case T_Result:
/* Supported only for RTE_RESULT scan paths */
Expand Down
9 changes: 3 additions & 6 deletions src/backend/optimizer/util/relnode.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
rel->tuples = 0;
rel->allvisfrac = 0;
rel->eclass_indexes = NULL;
rel->subroot = NULL;
rel->subplan_params = NIL;

rel->rel_parallel_workers = -1; /* set up in get_relation_info */
rel->amflags = 0;
rel->serverid = InvalidOid;
Expand Down Expand Up @@ -716,8 +715,7 @@ build_join_rel(PlannerInfo *root,
joinrel->tuples = 0;
joinrel->allvisfrac = 0;
joinrel->eclass_indexes = NULL;
joinrel->subroot = NULL;
joinrel->subplan_params = NIL;

joinrel->rel_parallel_workers = -1;
joinrel->amflags = 0;
joinrel->serverid = InvalidOid;
Expand Down Expand Up @@ -913,9 +911,8 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
joinrel->tuples = 0;
joinrel->allvisfrac = 0;
joinrel->eclass_indexes = NULL;
joinrel->subroot = NULL;
joinrel->subplan_params = NIL;
joinrel->amflags = 0;
joinrel->chosen_plan = NULL;
joinrel->serverid = InvalidOid;
joinrel->userid = InvalidOid;
joinrel->useridiscurrent = false;
Expand Down
6 changes: 4 additions & 2 deletions src/backend/rewrite/rewriteManip.c
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,7 @@ typedef struct
List *targetlist;
ReplaceVarsNoMatchOption nomatch_option;
int nomatch_varno;
int min_sublevels_up;
} ReplaceVarsFromTargetList_context;

static Node *
Expand Down Expand Up @@ -1740,8 +1741,8 @@ ReplaceVarsFromTargetList_callback(Var *var,
Expr *newnode = copyObject(tle->expr);

/* Must adjust varlevelsup if tlist item is from higher query */
if (var->varlevelsup > 0)
IncrementVarSublevelsUp((Node *) newnode, var->varlevelsup, 0);
if (var->varlevelsup + rcon->min_sublevels_up > 0)
IncrementVarSublevelsUp((Node *) newnode, var->varlevelsup - rcon->min_sublevels_up, 0);

/*
* Check to see if the tlist item contains a PARAM_MULTIEXPR Param,
Expand Down Expand Up @@ -1777,6 +1778,7 @@ ReplaceVarsFromTargetList(Node *node,
context.targetlist = targetlist;
context.nomatch_option = nomatch_option;
context.nomatch_varno = nomatch_varno;
context.min_sublevels_up = sublevels_up;

return replace_rte_variables(node, target_varno, sublevels_up,
ReplaceVarsFromTargetList_callback,
Expand Down
25 changes: 20 additions & 5 deletions src/backend/utils/adt/selfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -5370,6 +5370,7 @@ examine_simple_variable(PlannerInfo *root, Var *var,
Query *subquery = rte->subquery;
RelOptInfo *rel;
TargetEntry *ste;
PlannerInfo *subroot;

/*
* Punt if it's a whole-row var rather than a plain column reference.
Expand Down Expand Up @@ -5399,10 +5400,24 @@ examine_simple_variable(PlannerInfo *root, Var *var,
*/
rel = find_base_rel(root, var->varno);

/* If the subquery hasn't been planned yet, we have to punt */
if (rel->subroot == NULL)
if (rel->chosen_plan)
subroot = rel->chosen_plan;
else if (rel->pathlist && IsA(linitial(rel->pathlist), SubqueryScanPath))
{
/*
* Use the estimates from the first path. XXX: what if it's a parameterized
* path?
*/
SubqueryScanPath *sqpath = (SubqueryScanPath *) linitial(rel->pathlist);

subroot = sqpath->subroot;
}
else
{
/* If the subquery hasn't been planned yet, we have to punt */
return;
Assert(IsA(rel->subroot, PlannerInfo));
}
Assert(IsA(subroot, PlannerInfo));

/*
* Switch our attention to the subquery as mangled by the planner. It
Expand All @@ -5412,7 +5427,7 @@ examine_simple_variable(PlannerInfo *root, Var *var,
* planning, Vars in the targetlist might have gotten replaced, and we
* need to see the replacement expressions.
*/
subquery = rel->subroot->parse;
subquery = subroot->parse;
Assert(IsA(subquery, Query));

/* Get the subquery output expression referenced by the upper Var */
Expand Down Expand Up @@ -5464,7 +5479,7 @@ examine_simple_variable(PlannerInfo *root, Var *var,
* if the underlying column is unique, the subquery may have
* joined to other tables in a way that creates duplicates.
*/
examine_simple_variable(rel->subroot, var, vardata);
examine_simple_variable(subroot, var, vardata);
}
}
else
Expand Down
10 changes: 10 additions & 0 deletions src/backend/utils/misc/guc_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,16 @@ struct config_bool ConfigureNamesBool[] =
true,
NULL, NULL, NULL
},
{
{"enable_join_predicate_pushdown", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's ability to push join quals down into LATERAL subqueries."),
NULL,
GUC_EXPLAIN
},
&enable_join_predicate_pushdown,
true,
NULL, NULL, NULL
},
{
{"geqo", PGC_USERSET, QUERY_TUNING_GEQO,
gettext_noop("Enables genetic query optimization."),
Expand Down
7 changes: 5 additions & 2 deletions src/include/nodes/pathnodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -929,8 +929,7 @@ typedef struct RelOptInfo
double allvisfrac;
/* indexes in PlannerInfo's eq_classes list of ECs that mention this rel */
Bitmapset *eclass_indexes;
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
PlannerInfo *chosen_plan;
/* wanted number of parallel workers */
int rel_parallel_workers;
/* Bitmask of optional features supported by the table AM */
Expand Down Expand Up @@ -1819,6 +1818,10 @@ typedef struct SubqueryScanPath
{
Path path;
Path *subpath; /* path representing subquery execution */
PlannerInfo *subroot; /* */
List *subplan_params; /* */

List *pushed_down_clauses; /* pushed-down join quals */
} SubqueryScanPath;

/*
Expand Down
Loading