mirror of
https://github.com/postgres/postgres.git
synced 2026-06-13 10:40:09 -04:00
Add an alternative_plan_name field to PlannerInfo.
Typically, we have only one PlannerInfo for any given subquery, but when we are considering a MinMaxAggPath or a hashed subplan, we end up creating a second PlannerInfo for the same portion of the query, with a clone of the original range table. In fact, in the MinMaxAggPath case, we might end up creating several clones, one per aggregate. At present, there's no easy way for a plugin, such as pg_plan_advice, to understand the relationships between the original range table and the copies of it that are created in these cases. To fix, add an alternative_plan_name field to PlannerInfo. For a hashed subplan, this is the plan name for the non-hashed alternative; for minmax aggregates, this is the plan_name from the parent PlannerInfo; otherwise, it's the same as plan_name. Discussion: http://postgr.es/m/CA+TgmoYuWmN-00Ec5pY7zAcpSFQUQLbgAdVWGR9kOR-HM-fHrA@mail.gmail.com Reviewed-by: Lukas Fittl <lukas@fittl.com>
This commit is contained in:
parent
10e2a8ac6a
commit
26255a3207
8 changed files with 31 additions and 9 deletions
|
|
@ -2833,7 +2833,7 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
|
|||
/* Generate a subroot and Paths for the subquery */
|
||||
plan_name = choose_plan_name(root->glob, rte->eref->aliasname, false);
|
||||
rel->subroot = subquery_planner(root->glob, subquery, plan_name,
|
||||
root, false, tuple_fraction, NULL);
|
||||
root, NULL, false, tuple_fraction, NULL);
|
||||
|
||||
/* Isolate the params needed by this specific subplan */
|
||||
rel->subplan_params = root->plan_params;
|
||||
|
|
|
|||
|
|
@ -341,6 +341,7 @@ build_minmax_path(PlannerInfo *root, MinMaxAggInfo *mminfo,
|
|||
subroot->query_level++;
|
||||
subroot->parent_root = root;
|
||||
subroot->plan_name = choose_plan_name(root->glob, "minmax", true);
|
||||
subroot->alternative_plan_name = root->plan_name;
|
||||
|
||||
/* reset subplan-related stuff */
|
||||
subroot->plan_params = NIL;
|
||||
|
|
|
|||
|
|
@ -515,8 +515,8 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
|
|||
&tuple_fraction, es);
|
||||
|
||||
/* primary planning entry point (may recurse for subqueries) */
|
||||
root = subquery_planner(glob, parse, NULL, NULL, false, tuple_fraction,
|
||||
NULL);
|
||||
root = subquery_planner(glob, parse, NULL, NULL, NULL, false,
|
||||
tuple_fraction, NULL);
|
||||
|
||||
/* Select best Path and turn it into a Plan */
|
||||
final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
|
||||
|
|
@ -715,6 +715,8 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
|
|||
* parse is the querytree produced by the parser & rewriter.
|
||||
* plan_name is the name to assign to this subplan (NULL at the top level).
|
||||
* parent_root is the immediate parent Query's info (NULL at the top level).
|
||||
* alternative_root is a previously created PlannerInfo for which this query
|
||||
* level is an alternative implementation, or else NULL.
|
||||
* hasRecursion is true if this is a recursive WITH query.
|
||||
* tuple_fraction is the fraction of tuples we expect will be retrieved.
|
||||
* tuple_fraction is interpreted as explained for grouping_planner, below.
|
||||
|
|
@ -741,8 +743,9 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
|
|||
*/
|
||||
PlannerInfo *
|
||||
subquery_planner(PlannerGlobal *glob, Query *parse, char *plan_name,
|
||||
PlannerInfo *parent_root, bool hasRecursion,
|
||||
double tuple_fraction, SetOperationStmt *setops)
|
||||
PlannerInfo *parent_root, PlannerInfo *alternative_root,
|
||||
bool hasRecursion, double tuple_fraction,
|
||||
SetOperationStmt *setops)
|
||||
{
|
||||
PlannerInfo *root;
|
||||
List *newWithCheckOptions;
|
||||
|
|
@ -758,6 +761,10 @@ subquery_planner(PlannerGlobal *glob, Query *parse, char *plan_name,
|
|||
root->glob = glob;
|
||||
root->query_level = parent_root ? parent_root->query_level + 1 : 1;
|
||||
root->plan_name = plan_name;
|
||||
if (alternative_root != NULL)
|
||||
root->alternative_plan_name = alternative_root->plan_name;
|
||||
else
|
||||
root->alternative_plan_name = plan_name;
|
||||
root->parent_root = parent_root;
|
||||
root->plan_params = NIL;
|
||||
root->outer_params = NULL;
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ make_subplan(PlannerInfo *root, Query *orig_subquery,
|
|||
/* Generate Paths for the subquery */
|
||||
subroot = subquery_planner(root->glob, subquery,
|
||||
choose_plan_name(root->glob, sublinkstr, true),
|
||||
root, false, tuple_fraction, NULL);
|
||||
root, NULL, false, tuple_fraction, NULL);
|
||||
|
||||
/* Isolate the params needed by this specific subplan */
|
||||
plan_params = root->plan_params;
|
||||
|
|
@ -274,7 +274,7 @@ make_subplan(PlannerInfo *root, Query *orig_subquery,
|
|||
/* Generate Paths for the ANY subquery; we'll need all rows */
|
||||
plan_name = choose_plan_name(root->glob, sublinkstr, true);
|
||||
subroot = subquery_planner(root->glob, subquery, plan_name,
|
||||
root, false, 0.0, NULL);
|
||||
root, subroot, false, 0.0, NULL);
|
||||
|
||||
/* Isolate the params needed by this specific subplan */
|
||||
plan_params = root->plan_params;
|
||||
|
|
@ -971,7 +971,7 @@ SS_process_ctes(PlannerInfo *root)
|
|||
*/
|
||||
subroot = subquery_planner(root->glob, subquery,
|
||||
choose_plan_name(root->glob, cte->ctename, false),
|
||||
root, cte->cterecursive, 0.0, NULL);
|
||||
root, NULL, cte->cterecursive, 0.0, NULL);
|
||||
|
||||
/*
|
||||
* Since the current query level doesn't yet contain any RTEs, it
|
||||
|
|
|
|||
|
|
@ -1418,6 +1418,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
|
|||
subroot->glob = root->glob;
|
||||
subroot->query_level = root->query_level;
|
||||
subroot->plan_name = root->plan_name;
|
||||
subroot->alternative_plan_name = root->alternative_plan_name;
|
||||
subroot->parent_root = root->parent_root;
|
||||
subroot->plan_params = NIL;
|
||||
subroot->outer_params = NULL;
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
|
|||
*/
|
||||
plan_name = choose_plan_name(root->glob, "setop", true);
|
||||
subroot = rel->subroot = subquery_planner(root->glob, subquery,
|
||||
plan_name, root,
|
||||
plan_name, root, NULL,
|
||||
false, root->tuple_fraction,
|
||||
parentOp);
|
||||
|
||||
|
|
|
|||
|
|
@ -320,6 +320,18 @@ struct PlannerInfo
|
|||
/* Subplan name for EXPLAIN and debugging purposes (NULL at top level) */
|
||||
char *plan_name;
|
||||
|
||||
/*
|
||||
* If this PlannerInfo exists to consider an alternative implementation
|
||||
* strategy for a portion of the query that could also be implemented by
|
||||
* some other PlannerInfo, this is the plan_name for that other
|
||||
* PlannerInfo. When we are considering the first or only alternative,
|
||||
* it is the same as plan_name.
|
||||
*
|
||||
* Currently, we set this to a value other than plan_name only when
|
||||
* considering a MinMaxAggPath or a hashed SubPlan.
|
||||
*/
|
||||
char *alternative_plan_name;
|
||||
|
||||
/*
|
||||
* plan_params contains the expressions that this query level needs to
|
||||
* make available to a lower query level that is currently being planned.
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ extern PlannedStmt *standard_planner(Query *parse, const char *query_string,
|
|||
extern PlannerInfo *subquery_planner(PlannerGlobal *glob, Query *parse,
|
||||
char *plan_name,
|
||||
PlannerInfo *parent_root,
|
||||
PlannerInfo *alternative_root,
|
||||
bool hasRecursion, double tuple_fraction,
|
||||
SetOperationStmt *setops);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue