mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
In the planner, replace an empty FROM clause with a dummy RTE.
The fact that "SELECT expression" has no base relations has long been a thorn in the side of the planner. It makes it hard to flatten a sub-query that looks like that, or is a trivial VALUES() item, because the planner generally uses relid sets to identify sub-relations, and such a sub-query would have an empty relid set if we flattened it. prepjointree.c contains some baroque logic that works around this in certain special cases --- but there is a much better answer. We can replace an empty FROM clause with a dummy RTE that acts like a table of one row and no columns, and then there are no such corner cases to worry about. Instead we need some logic to get rid of useless dummy RTEs, but that's simpler and covers more cases than what was there before. For really trivial cases, where the query is just "SELECT expression" and nothing else, there's a hazard that adding the extra RTE makes for a noticeable slowdown; even though it's not much processing, there's not that much for the planner to do overall. However testing says that the penalty is very small, close to the noise level. In more complex queries, this is able to find optimizations that we could not find before. The new RTE type is called RTE_RESULT, since the "scan" plan type it gives rise to is a Result node (the same plan we produced for a "SELECT expression" query before). To avoid confusion, rename the old ResultPath path type to GroupResultPath, reflecting that it's only used in degenerate grouping cases where we know the query produces just one grouped row. (It wouldn't work to unify the two cases, because there are different rules about where the associated quals live during query_planner.) Note: although this touches readfuncs.c, I don't think a catversion bump is required, because the added case can't occur in stored rules, only plans. Patch by me, reviewed by David Rowley and Mark Dilger Discussion: https://postgr.es/m/15944.1521127664@sss.pgh.pa.us
This commit is contained in:
@ -117,6 +117,8 @@ static void set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel,
|
||||
RangeTblEntry *rte);
|
||||
static void set_namedtuplestore_pathlist(PlannerInfo *root, RelOptInfo *rel,
|
||||
RangeTblEntry *rte);
|
||||
static void set_result_pathlist(PlannerInfo *root, RelOptInfo *rel,
|
||||
RangeTblEntry *rte);
|
||||
static void set_worktable_pathlist(PlannerInfo *root, RelOptInfo *rel,
|
||||
RangeTblEntry *rte);
|
||||
static RelOptInfo *make_rel_from_joinlist(PlannerInfo *root, List *joinlist);
|
||||
@ -437,8 +439,13 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
|
||||
set_cte_pathlist(root, rel, rte);
|
||||
break;
|
||||
case RTE_NAMEDTUPLESTORE:
|
||||
/* Might as well just build the path immediately */
|
||||
set_namedtuplestore_pathlist(root, rel, rte);
|
||||
break;
|
||||
case RTE_RESULT:
|
||||
/* Might as well just build the path immediately */
|
||||
set_result_pathlist(root, rel, rte);
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unexpected rtekind: %d", (int) rel->rtekind);
|
||||
break;
|
||||
@ -510,6 +517,9 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
|
||||
case RTE_NAMEDTUPLESTORE:
|
||||
/* tuplestore reference --- fully handled during set_rel_size */
|
||||
break;
|
||||
case RTE_RESULT:
|
||||
/* simple Result --- fully handled during set_rel_size */
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unexpected rtekind: %d", (int) rel->rtekind);
|
||||
break;
|
||||
@ -712,6 +722,10 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel,
|
||||
* infrastructure to support that.
|
||||
*/
|
||||
return;
|
||||
|
||||
case RTE_RESULT:
|
||||
/* RESULT RTEs, in themselves, are no problem. */
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2509,6 +2523,36 @@ set_namedtuplestore_pathlist(PlannerInfo *root, RelOptInfo *rel,
|
||||
set_cheapest(rel);
|
||||
}
|
||||
|
||||
/*
|
||||
* set_result_pathlist
|
||||
* Build the (single) access path for an RTE_RESULT RTE
|
||||
*
|
||||
* There's no need for a separate set_result_size phase, since we
|
||||
* don't support join-qual-parameterized paths for these RTEs.
|
||||
*/
|
||||
static void
|
||||
set_result_pathlist(PlannerInfo *root, RelOptInfo *rel,
|
||||
RangeTblEntry *rte)
|
||||
{
|
||||
Relids required_outer;
|
||||
|
||||
/* Mark rel with estimated output rows, width, etc */
|
||||
set_result_size_estimates(root, rel);
|
||||
|
||||
/*
|
||||
* We don't support pushing join clauses into the quals of a Result scan,
|
||||
* but it could still have required parameterization due to LATERAL refs
|
||||
* in its tlist.
|
||||
*/
|
||||
required_outer = rel->lateral_relids;
|
||||
|
||||
/* Generate appropriate path */
|
||||
add_path(rel, create_resultscan_path(root, rel, required_outer));
|
||||
|
||||
/* Select cheapest path (pretty easy in this case...) */
|
||||
set_cheapest(rel);
|
||||
}
|
||||
|
||||
/*
|
||||
* set_worktable_pathlist
|
||||
* Build the (single) access path for a self-reference CTE RTE
|
||||
@ -3677,9 +3721,6 @@ print_path(PlannerInfo *root, Path *path, int indent)
|
||||
case T_SampleScan:
|
||||
ptype = "SampleScan";
|
||||
break;
|
||||
case T_SubqueryScan:
|
||||
ptype = "SubqueryScan";
|
||||
break;
|
||||
case T_FunctionScan:
|
||||
ptype = "FunctionScan";
|
||||
break;
|
||||
@ -3692,6 +3733,12 @@ print_path(PlannerInfo *root, Path *path, int indent)
|
||||
case T_CteScan:
|
||||
ptype = "CteScan";
|
||||
break;
|
||||
case T_NamedTuplestoreScan:
|
||||
ptype = "NamedTuplestoreScan";
|
||||
break;
|
||||
case T_Result:
|
||||
ptype = "Result";
|
||||
break;
|
||||
case T_WorkTableScan:
|
||||
ptype = "WorkTableScan";
|
||||
break;
|
||||
@ -3716,7 +3763,7 @@ print_path(PlannerInfo *root, Path *path, int indent)
|
||||
ptype = "TidScan";
|
||||
break;
|
||||
case T_SubqueryScanPath:
|
||||
ptype = "SubqueryScanScan";
|
||||
ptype = "SubqueryScan";
|
||||
break;
|
||||
case T_ForeignPath:
|
||||
ptype = "ForeignScan";
|
||||
@ -3742,8 +3789,8 @@ print_path(PlannerInfo *root, Path *path, int indent)
|
||||
case T_MergeAppendPath:
|
||||
ptype = "MergeAppend";
|
||||
break;
|
||||
case T_ResultPath:
|
||||
ptype = "Result";
|
||||
case T_GroupResultPath:
|
||||
ptype = "GroupResult";
|
||||
break;
|
||||
case T_MaterialPath:
|
||||
ptype = "Material";
|
||||
|
Reference in New Issue
Block a user