mirror of
https://github.com/postgres/postgres.git
synced 2025-06-26 12:21:12 +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:
@ -867,9 +867,9 @@ _copyAgg(const Agg *from)
|
||||
CopyPlanFields((const Plan *) from, (Plan *) newnode);
|
||||
|
||||
COPY_SCALAR_FIELD(aggstrategy);
|
||||
COPY_SCALAR_FIELD(numCols);
|
||||
COPY_SCALAR_FIELD(combineStates);
|
||||
COPY_SCALAR_FIELD(finalizeAggs);
|
||||
COPY_SCALAR_FIELD(numCols);
|
||||
if (from->numCols > 0)
|
||||
{
|
||||
COPY_POINTER_FIELD(grpColIdx, from->numCols * sizeof(AttrNumber));
|
||||
|
@ -706,21 +706,19 @@ _outAgg(StringInfo str, const Agg *node)
|
||||
_outPlanInfo(str, (const Plan *) node);
|
||||
|
||||
WRITE_ENUM_FIELD(aggstrategy, AggStrategy);
|
||||
WRITE_BOOL_FIELD(combineStates);
|
||||
WRITE_BOOL_FIELD(finalizeAggs);
|
||||
WRITE_INT_FIELD(numCols);
|
||||
|
||||
appendStringInfoString(str, " :grpColIdx");
|
||||
for (i = 0; i < node->numCols; i++)
|
||||
appendStringInfo(str, " %d", node->grpColIdx[i]);
|
||||
|
||||
WRITE_BOOL_FIELD(combineStates);
|
||||
WRITE_BOOL_FIELD(finalizeAggs);
|
||||
|
||||
appendStringInfoString(str, " :grpOperators");
|
||||
for (i = 0; i < node->numCols; i++)
|
||||
appendStringInfo(str, " %u", node->grpOperators[i]);
|
||||
|
||||
WRITE_LONG_FIELD(numGroups);
|
||||
|
||||
WRITE_NODE_FIELD(groupingSets);
|
||||
WRITE_NODE_FIELD(chain);
|
||||
}
|
||||
@ -1603,6 +1601,15 @@ _outPathInfo(StringInfo str, const Path *node)
|
||||
if (node->pathtarget != &(node->parent->reltarget))
|
||||
{
|
||||
WRITE_NODE_FIELD(pathtarget->exprs);
|
||||
if (node->pathtarget->sortgrouprefs)
|
||||
{
|
||||
int i;
|
||||
|
||||
appendStringInfoString(str, " :pathtarget->sortgrouprefs");
|
||||
for (i = 0; i < list_length(node->pathtarget->exprs); i++)
|
||||
appendStringInfo(str, " %u",
|
||||
node->pathtarget->sortgrouprefs[i]);
|
||||
}
|
||||
WRITE_FLOAT_FIELD(pathtarget->cost.startup, "%.2f");
|
||||
WRITE_FLOAT_FIELD(pathtarget->cost.per_tuple, "%.2f");
|
||||
WRITE_INT_FIELD(pathtarget->width);
|
||||
@ -1703,6 +1710,16 @@ _outTidPath(StringInfo str, const TidPath *node)
|
||||
WRITE_NODE_FIELD(tidquals);
|
||||
}
|
||||
|
||||
static void
|
||||
_outSubqueryScanPath(StringInfo str, const SubqueryScanPath *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("SUBQUERYSCANPATH");
|
||||
|
||||
_outPathInfo(str, (const Path *) node);
|
||||
|
||||
WRITE_NODE_FIELD(subpath);
|
||||
}
|
||||
|
||||
static void
|
||||
_outForeignPath(StringInfo str, const ForeignPath *node)
|
||||
{
|
||||
@ -1793,6 +1810,174 @@ _outGatherPath(StringInfo str, const GatherPath *node)
|
||||
WRITE_BOOL_FIELD(single_copy);
|
||||
}
|
||||
|
||||
static void
|
||||
_outProjectionPath(StringInfo str, const ProjectionPath *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("PROJECTIONPATH");
|
||||
|
||||
_outPathInfo(str, (const Path *) node);
|
||||
|
||||
WRITE_NODE_FIELD(subpath);
|
||||
}
|
||||
|
||||
static void
|
||||
_outSortPath(StringInfo str, const SortPath *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("SORTPATH");
|
||||
|
||||
_outPathInfo(str, (const Path *) node);
|
||||
|
||||
WRITE_NODE_FIELD(subpath);
|
||||
}
|
||||
|
||||
static void
|
||||
_outGroupPath(StringInfo str, const GroupPath *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("GROUPPATH");
|
||||
|
||||
_outPathInfo(str, (const Path *) node);
|
||||
|
||||
WRITE_NODE_FIELD(subpath);
|
||||
WRITE_NODE_FIELD(groupClause);
|
||||
WRITE_NODE_FIELD(qual);
|
||||
}
|
||||
|
||||
static void
|
||||
_outUpperUniquePath(StringInfo str, const UpperUniquePath *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("UPPERUNIQUEPATH");
|
||||
|
||||
_outPathInfo(str, (const Path *) node);
|
||||
|
||||
WRITE_NODE_FIELD(subpath);
|
||||
WRITE_INT_FIELD(numkeys);
|
||||
}
|
||||
|
||||
static void
|
||||
_outAggPath(StringInfo str, const AggPath *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("AGGPATH");
|
||||
|
||||
_outPathInfo(str, (const Path *) node);
|
||||
|
||||
WRITE_NODE_FIELD(subpath);
|
||||
WRITE_ENUM_FIELD(aggstrategy, AggStrategy);
|
||||
WRITE_FLOAT_FIELD(numGroups, "%.0f");
|
||||
WRITE_NODE_FIELD(groupClause);
|
||||
WRITE_NODE_FIELD(qual);
|
||||
}
|
||||
|
||||
static void
|
||||
_outGroupingSetsPath(StringInfo str, const GroupingSetsPath *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("GROUPINGSETSPATH");
|
||||
|
||||
_outPathInfo(str, (const Path *) node);
|
||||
|
||||
WRITE_NODE_FIELD(subpath);
|
||||
/* we don't bother to print groupColIdx */
|
||||
WRITE_NODE_FIELD(rollup_groupclauses);
|
||||
WRITE_NODE_FIELD(rollup_lists);
|
||||
WRITE_NODE_FIELD(qual);
|
||||
}
|
||||
|
||||
static void
|
||||
_outMinMaxAggPath(StringInfo str, const MinMaxAggPath *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("MINMAXAGGPATH");
|
||||
|
||||
_outPathInfo(str, (const Path *) node);
|
||||
|
||||
WRITE_NODE_FIELD(mmaggregates);
|
||||
WRITE_NODE_FIELD(quals);
|
||||
}
|
||||
|
||||
static void
|
||||
_outWindowAggPath(StringInfo str, const WindowAggPath *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("WINDOWAGGPATH");
|
||||
|
||||
_outPathInfo(str, (const Path *) node);
|
||||
|
||||
WRITE_NODE_FIELD(subpath);
|
||||
WRITE_NODE_FIELD(winclause);
|
||||
WRITE_NODE_FIELD(winpathkeys);
|
||||
}
|
||||
|
||||
static void
|
||||
_outSetOpPath(StringInfo str, const SetOpPath *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("SETOPPATH");
|
||||
|
||||
_outPathInfo(str, (const Path *) node);
|
||||
|
||||
WRITE_NODE_FIELD(subpath);
|
||||
WRITE_ENUM_FIELD(cmd, SetOpCmd);
|
||||
WRITE_ENUM_FIELD(strategy, SetOpStrategy);
|
||||
WRITE_NODE_FIELD(distinctList);
|
||||
WRITE_INT_FIELD(flagColIdx);
|
||||
WRITE_INT_FIELD(firstFlag);
|
||||
WRITE_FLOAT_FIELD(numGroups, "%.0f");
|
||||
}
|
||||
|
||||
static void
|
||||
_outRecursiveUnionPath(StringInfo str, const RecursiveUnionPath *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("RECURSIVEUNIONPATH");
|
||||
|
||||
_outPathInfo(str, (const Path *) node);
|
||||
|
||||
WRITE_NODE_FIELD(leftpath);
|
||||
WRITE_NODE_FIELD(rightpath);
|
||||
WRITE_NODE_FIELD(distinctList);
|
||||
WRITE_INT_FIELD(wtParam);
|
||||
WRITE_FLOAT_FIELD(numGroups, "%.0f");
|
||||
}
|
||||
|
||||
static void
|
||||
_outLockRowsPath(StringInfo str, const LockRowsPath *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("LOCKROWSPATH");
|
||||
|
||||
_outPathInfo(str, (const Path *) node);
|
||||
|
||||
WRITE_NODE_FIELD(subpath);
|
||||
WRITE_NODE_FIELD(rowMarks);
|
||||
WRITE_INT_FIELD(epqParam);
|
||||
}
|
||||
|
||||
static void
|
||||
_outModifyTablePath(StringInfo str, const ModifyTablePath *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("MODIFYTABLEPATH");
|
||||
|
||||
_outPathInfo(str, (const Path *) node);
|
||||
|
||||
WRITE_ENUM_FIELD(operation, CmdType);
|
||||
WRITE_BOOL_FIELD(canSetTag);
|
||||
WRITE_UINT_FIELD(nominalRelation);
|
||||
WRITE_NODE_FIELD(resultRelations);
|
||||
WRITE_NODE_FIELD(subpaths);
|
||||
WRITE_NODE_FIELD(subroots);
|
||||
WRITE_NODE_FIELD(withCheckOptionLists);
|
||||
WRITE_NODE_FIELD(returningLists);
|
||||
WRITE_NODE_FIELD(rowMarks);
|
||||
WRITE_NODE_FIELD(onconflict);
|
||||
WRITE_INT_FIELD(epqParam);
|
||||
}
|
||||
|
||||
static void
|
||||
_outLimitPath(StringInfo str, const LimitPath *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("LIMITPATH");
|
||||
|
||||
_outPathInfo(str, (const Path *) node);
|
||||
|
||||
WRITE_NODE_FIELD(subpath);
|
||||
WRITE_NODE_FIELD(limitOffset);
|
||||
WRITE_NODE_FIELD(limitCount);
|
||||
}
|
||||
|
||||
static void
|
||||
_outNestPath(StringInfo str, const NestPath *node)
|
||||
{
|
||||
@ -1881,6 +2066,7 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node)
|
||||
WRITE_NODE_FIELD(window_pathkeys);
|
||||
WRITE_NODE_FIELD(distinct_pathkeys);
|
||||
WRITE_NODE_FIELD(sort_pathkeys);
|
||||
WRITE_NODE_FIELD(processed_tlist);
|
||||
WRITE_NODE_FIELD(minmax_aggs);
|
||||
WRITE_FLOAT_FIELD(total_table_pages, "%.0f");
|
||||
WRITE_FLOAT_FIELD(tuple_fraction, "%.4f");
|
||||
@ -1910,6 +2096,7 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node)
|
||||
WRITE_BOOL_FIELD(consider_param_startup);
|
||||
WRITE_BOOL_FIELD(consider_parallel);
|
||||
WRITE_NODE_FIELD(reltarget.exprs);
|
||||
/* reltarget.sortgrouprefs is never interesting, at present anyway */
|
||||
WRITE_FLOAT_FIELD(reltarget.cost.startup, "%.2f");
|
||||
WRITE_FLOAT_FIELD(reltarget.cost.per_tuple, "%.2f");
|
||||
WRITE_INT_FIELD(reltarget.width);
|
||||
@ -1933,7 +2120,6 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node)
|
||||
WRITE_UINT_FIELD(pages);
|
||||
WRITE_FLOAT_FIELD(tuples, "%.0f");
|
||||
WRITE_FLOAT_FIELD(allvisfrac, "%.6f");
|
||||
WRITE_NODE_FIELD(subplan);
|
||||
WRITE_NODE_FIELD(subroot);
|
||||
WRITE_NODE_FIELD(subplan_params);
|
||||
WRITE_OID_FIELD(serverid);
|
||||
@ -3331,6 +3517,9 @@ _outNode(StringInfo str, const void *obj)
|
||||
case T_TidPath:
|
||||
_outTidPath(str, obj);
|
||||
break;
|
||||
case T_SubqueryScanPath:
|
||||
_outSubqueryScanPath(str, obj);
|
||||
break;
|
||||
case T_ForeignPath:
|
||||
_outForeignPath(str, obj);
|
||||
break;
|
||||
@ -3355,6 +3544,45 @@ _outNode(StringInfo str, const void *obj)
|
||||
case T_GatherPath:
|
||||
_outGatherPath(str, obj);
|
||||
break;
|
||||
case T_ProjectionPath:
|
||||
_outProjectionPath(str, obj);
|
||||
break;
|
||||
case T_SortPath:
|
||||
_outSortPath(str, obj);
|
||||
break;
|
||||
case T_GroupPath:
|
||||
_outGroupPath(str, obj);
|
||||
break;
|
||||
case T_UpperUniquePath:
|
||||
_outUpperUniquePath(str, obj);
|
||||
break;
|
||||
case T_AggPath:
|
||||
_outAggPath(str, obj);
|
||||
break;
|
||||
case T_GroupingSetsPath:
|
||||
_outGroupingSetsPath(str, obj);
|
||||
break;
|
||||
case T_MinMaxAggPath:
|
||||
_outMinMaxAggPath(str, obj);
|
||||
break;
|
||||
case T_WindowAggPath:
|
||||
_outWindowAggPath(str, obj);
|
||||
break;
|
||||
case T_SetOpPath:
|
||||
_outSetOpPath(str, obj);
|
||||
break;
|
||||
case T_RecursiveUnionPath:
|
||||
_outRecursiveUnionPath(str, obj);
|
||||
break;
|
||||
case T_LockRowsPath:
|
||||
_outLockRowsPath(str, obj);
|
||||
break;
|
||||
case T_ModifyTablePath:
|
||||
_outModifyTablePath(str, obj);
|
||||
break;
|
||||
case T_LimitPath:
|
||||
_outLimitPath(str, obj);
|
||||
break;
|
||||
case T_NestPath:
|
||||
_outNestPath(str, obj);
|
||||
break;
|
||||
|
@ -1997,10 +1997,10 @@ _readAgg(void)
|
||||
ReadCommonPlan(&local_node->plan);
|
||||
|
||||
READ_ENUM_FIELD(aggstrategy, AggStrategy);
|
||||
READ_INT_FIELD(numCols);
|
||||
READ_ATTRNUMBER_ARRAY(grpColIdx, local_node->numCols);
|
||||
READ_BOOL_FIELD(combineStates);
|
||||
READ_BOOL_FIELD(finalizeAggs);
|
||||
READ_INT_FIELD(numCols);
|
||||
READ_ATTRNUMBER_ARRAY(grpColIdx, local_node->numCols);
|
||||
READ_OID_ARRAY(grpOperators, local_node->numCols);
|
||||
READ_LONG_FIELD(numGroups);
|
||||
READ_NODE_FIELD(groupingSets);
|
||||
|
Reference in New Issue
Block a user