Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4be058f

Browse files
committed
In the planner, replace an empty FROM clause with a dummy RTE.
The fact that "SELECT expression" has no base relations has long been athorn in the side of the planner. It makes it hard to flatten a sub-querythat looks like that, or is a trivial VALUES() item, because the plannergenerally uses relid sets to identify sub-relations, and such a sub-querywould have an empty relid set if we flattened it. prepjointree.c containssome baroque logic that works around this in certain special cases --- butthere is a much better answer. We can replace an empty FROM clause with adummy RTE that acts like a table of one row and no columns, and then thereare no such corner cases to worry about. Instead we need some logic toget rid of useless dummy RTEs, but that's simpler and covers more casesthan what was there before.For really trivial cases, where the query is just "SELECT expression" andnothing else, there's a hazard that adding the extra RTE makes for anoticeable slowdown; even though it's not much processing, there's notthat much for the planner to do overall. However testing says that thepenalty 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 itgives rise to is a Result node (the same plan we produced for a "SELECTexpression" query before). To avoid confusion, rename the old ResultPathpath type to GroupResultPath, reflecting that it's only used in degenerategrouping cases where we know the query produces just one grouped row.(It wouldn't work to unify the two cases, because there are differentrules about where the associated quals live during query_planner.)Note: although this touches readfuncs.c, I don't think a catversionbump is required, because the added case can't occur in stored rules,only plans.Patch by me, reviewed by David Rowley and Mark DilgerDiscussion:https://postgr.es/m/15944.1521127664@sss.pgh.pa.us
1 parent5c11867 commit4be058f

File tree

35 files changed

+1171
-446
lines changed

35 files changed

+1171
-446
lines changed

‎contrib/pg_stat_statements/pg_stat_statements.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2476,6 +2476,8 @@ JumbleRangeTable(pgssJumbleState *jstate, List *rtable)
24762476
caseRTE_NAMEDTUPLESTORE:
24772477
APP_JUMB_STRING(rte->enrname);
24782478
break;
2479+
caseRTE_RESULT:
2480+
break;
24792481
default:
24802482
elog(ERROR,"unrecognized RTE kind: %d", (int)rte->rtekind);
24812483
break;

‎contrib/postgres_fdw/expected/postgres_fdw.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5361,7 +5361,7 @@ INSERT INTO ft2 (c1,c2,c3) VALUES (1200,999,'foo') RETURNING tableoid::regclass;
53615361
QUERY PLAN
53625362
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
53635363
Insert on public.ft2
5364-
Output: (tableoid)::regclass
5364+
Output: (ft2.tableoid)::regclass
53655365
Remote SQL: INSERT INTO "S 1"."T 1"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
53665366
-> Result
53675367
Output: 1200, 999, NULL::integer, 'foo'::text, NULL::timestamp with time zone, NULL::timestamp without time zone, NULL::character varying, 'ft2 '::character(10), NULL::user_enum

‎src/backend/executor/execAmi.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,9 +437,12 @@ ExecSupportsMarkRestore(Path *pathnode)
437437
returnExecSupportsMarkRestore(((ProjectionPath*)pathnode)->subpath);
438438
elseif (IsA(pathnode,MinMaxAggPath))
439439
return false;/* childless Result */
440+
elseif (IsA(pathnode,GroupResultPath))
441+
return false;/* childless Result */
440442
else
441443
{
442-
Assert(IsA(pathnode,ResultPath));
444+
/* Simple RTE_RESULT base relation */
445+
Assert(IsA(pathnode,Path));
443446
return false;/* childless Result */
444447
}
445448

‎src/backend/nodes/nodeFuncs.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2329,10 +2329,6 @@ range_table_walker(List *rtable,
23292329
if (walker(rte->tablesample,context))
23302330
return true;
23312331
break;
2332-
caseRTE_CTE:
2333-
caseRTE_NAMEDTUPLESTORE:
2334-
/* nothing to do */
2335-
break;
23362332
caseRTE_SUBQUERY:
23372333
if (!(flags&QTW_IGNORE_RT_SUBQUERIES))
23382334
if (walker(rte->subquery,context))
@@ -2355,6 +2351,11 @@ range_table_walker(List *rtable,
23552351
if (walker(rte->values_lists,context))
23562352
return true;
23572353
break;
2354+
caseRTE_CTE:
2355+
caseRTE_NAMEDTUPLESTORE:
2356+
caseRTE_RESULT:
2357+
/* nothing to do */
2358+
break;
23582359
}
23592360

23602361
if (walker(rte->securityQuals,context))
@@ -3164,10 +3165,6 @@ range_table_mutator(List *rtable,
31643165
TableSampleClause*);
31653166
/* we don't bother to copy eref, aliases, etc; OK? */
31663167
break;
3167-
caseRTE_CTE:
3168-
caseRTE_NAMEDTUPLESTORE:
3169-
/* nothing to do */
3170-
break;
31713168
caseRTE_SUBQUERY:
31723169
if (!(flags&QTW_IGNORE_RT_SUBQUERIES))
31733170
{
@@ -3198,6 +3195,11 @@ range_table_mutator(List *rtable,
31983195
caseRTE_VALUES:
31993196
MUTATE(newrte->values_lists,rte->values_lists,List*);
32003197
break;
3198+
caseRTE_CTE:
3199+
caseRTE_NAMEDTUPLESTORE:
3200+
caseRTE_RESULT:
3201+
/* nothing to do */
3202+
break;
32013203
}
32023204
MUTATE(newrte->securityQuals,rte->securityQuals,List*);
32033205
newrt=lappend(newrt,newrte);

‎src/backend/nodes/outfuncs.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,9 +1855,9 @@ _outMergeAppendPath(StringInfo str, const MergeAppendPath *node)
18551855
}
18561856

18571857
staticvoid
1858-
_outResultPath(StringInfostr,constResultPath*node)
1858+
_outGroupResultPath(StringInfostr,constGroupResultPath*node)
18591859
{
1860-
WRITE_NODE_TYPE("RESULTPATH");
1860+
WRITE_NODE_TYPE("GROUPRESULTPATH");
18611861

18621862
_outPathInfo(str, (constPath*)node);
18631863

@@ -2213,7 +2213,6 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node)
22132213
WRITE_ENUM_FIELD(inhTargetKind,InheritanceKind);
22142214
WRITE_BOOL_FIELD(hasJoinRTEs);
22152215
WRITE_BOOL_FIELD(hasLateralRTEs);
2216-
WRITE_BOOL_FIELD(hasDeletedRTEs);
22172216
WRITE_BOOL_FIELD(hasHavingQual);
22182217
WRITE_BOOL_FIELD(hasPseudoConstantQuals);
22192218
WRITE_BOOL_FIELD(hasRecursion);
@@ -3060,6 +3059,9 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
30603059
WRITE_NODE_FIELD(coltypmods);
30613060
WRITE_NODE_FIELD(colcollations);
30623061
break;
3062+
caseRTE_RESULT:
3063+
/* no extra fields */
3064+
break;
30633065
default:
30643066
elog(ERROR,"unrecognized RTE kind: %d", (int)node->rtekind);
30653067
break;
@@ -3943,8 +3945,8 @@ outNode(StringInfo str, const void *obj)
39433945
caseT_MergeAppendPath:
39443946
_outMergeAppendPath(str,obj);
39453947
break;
3946-
caseT_ResultPath:
3947-
_outResultPath(str,obj);
3948+
caseT_GroupResultPath:
3949+
_outGroupResultPath(str,obj);
39483950
break;
39493951
caseT_MaterialPath:
39503952
_outMaterialPath(str,obj);

‎src/backend/nodes/print.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,10 @@ print_rt(const List *rtable)
295295
printf("%d\t%s\t[tuplestore]",
296296
i,rte->eref->aliasname);
297297
break;
298+
caseRTE_RESULT:
299+
printf("%d\t%s\t[result]",
300+
i,rte->eref->aliasname);
301+
break;
298302
default:
299303
printf("%d\t%s\t[unknown rtekind]",
300304
i,rte->eref->aliasname);

‎src/backend/nodes/readfuncs.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,6 +1411,9 @@ _readRangeTblEntry(void)
14111411
READ_NODE_FIELD(coltypmods);
14121412
READ_NODE_FIELD(colcollations);
14131413
break;
1414+
caseRTE_RESULT:
1415+
/* no extra fields */
1416+
break;
14141417
default:
14151418
elog(ERROR,"unrecognized RTE kind: %d",
14161419
(int)local_node->rtekind);

‎src/backend/optimizer/README

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,16 @@ RelOptInfo - a relation or joined relations
361361
join clauses)
362362

363363
Path - every way to generate a RelOptInfo(sequential,index,joins)
364-
SeqScan - represents a sequential scan plan
364+
A plain Path node can represent several simple plans, per its pathtype:
365+
T_SeqScan - sequential scan
366+
T_SampleScan - tablesample scan
367+
T_FunctionScan - function-in-FROM scan
368+
T_TableFuncScan - table function scan
369+
T_ValuesScan - VALUES scan
370+
T_CteScan - CTE (WITH) scan
371+
T_NamedTuplestoreScan - ENR scan
372+
T_WorkTableScan - scan worktable of a recursive CTE
373+
T_Result - childless Result plan node (used for FROM-less SELECT)
365374
IndexPath - index scan
366375
BitmapHeapPath - top of a bitmapped index scan
367376
TidPath - scan by CTID
@@ -370,7 +379,7 @@ RelOptInfo - a relation or joined relations
370379
CustomPath - for custom scan providers
371380
AppendPath - append multiple subpaths together
372381
MergeAppendPath - merge multiple subpaths, preserving their common sort order
373-
ResultPath - achildless Result plan node (used forFROM-less SELECT)
382+
GroupResultPath -childless Result plan node (used fordegenerate grouping)
374383
MaterialPath - a Material plan node
375384
UniquePath - remove duplicate rows (either by hashing or sorting)
376385
GatherPath - collect the results of parallel workers

‎src/backend/optimizer/path/allpaths.c

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ static void set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel,
117117
RangeTblEntry*rte);
118118
staticvoidset_namedtuplestore_pathlist(PlannerInfo*root,RelOptInfo*rel,
119119
RangeTblEntry*rte);
120+
staticvoidset_result_pathlist(PlannerInfo*root,RelOptInfo*rel,
121+
RangeTblEntry*rte);
120122
staticvoidset_worktable_pathlist(PlannerInfo*root,RelOptInfo*rel,
121123
RangeTblEntry*rte);
122124
staticRelOptInfo*make_rel_from_joinlist(PlannerInfo*root,List*joinlist);
@@ -437,8 +439,13 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
437439
set_cte_pathlist(root,rel,rte);
438440
break;
439441
caseRTE_NAMEDTUPLESTORE:
442+
/* Might as well just build the path immediately */
440443
set_namedtuplestore_pathlist(root,rel,rte);
441444
break;
445+
caseRTE_RESULT:
446+
/* Might as well just build the path immediately */
447+
set_result_pathlist(root,rel,rte);
448+
break;
442449
default:
443450
elog(ERROR,"unexpected rtekind: %d", (int)rel->rtekind);
444451
break;
@@ -510,6 +517,9 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
510517
caseRTE_NAMEDTUPLESTORE:
511518
/* tuplestore reference --- fully handled during set_rel_size */
512519
break;
520+
caseRTE_RESULT:
521+
/* simple Result --- fully handled during set_rel_size */
522+
break;
513523
default:
514524
elog(ERROR,"unexpected rtekind: %d", (int)rel->rtekind);
515525
break;
@@ -712,6 +722,10 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel,
712722
* infrastructure to support that.
713723
*/
714724
return;
725+
726+
caseRTE_RESULT:
727+
/* RESULT RTEs, in themselves, are no problem. */
728+
break;
715729
}
716730

717731
/*
@@ -2509,6 +2523,36 @@ set_namedtuplestore_pathlist(PlannerInfo *root, RelOptInfo *rel,
25092523
set_cheapest(rel);
25102524
}
25112525

2526+
/*
2527+
* set_result_pathlist
2528+
*Build the (single) access path for an RTE_RESULT RTE
2529+
*
2530+
* There's no need for a separate set_result_size phase, since we
2531+
* don't support join-qual-parameterized paths for these RTEs.
2532+
*/
2533+
staticvoid
2534+
set_result_pathlist(PlannerInfo*root,RelOptInfo*rel,
2535+
RangeTblEntry*rte)
2536+
{
2537+
Relidsrequired_outer;
2538+
2539+
/* Mark rel with estimated output rows, width, etc */
2540+
set_result_size_estimates(root,rel);
2541+
2542+
/*
2543+
* We don't support pushing join clauses into the quals of a Result scan,
2544+
* but it could still have required parameterization due to LATERAL refs
2545+
* in its tlist.
2546+
*/
2547+
required_outer=rel->lateral_relids;
2548+
2549+
/* Generate appropriate path */
2550+
add_path(rel,create_resultscan_path(root,rel,required_outer));
2551+
2552+
/* Select cheapest path (pretty easy in this case...) */
2553+
set_cheapest(rel);
2554+
}
2555+
25122556
/*
25132557
* set_worktable_pathlist
25142558
*Build the (single) access path for a self-reference CTE RTE
@@ -3677,9 +3721,6 @@ print_path(PlannerInfo *root, Path *path, int indent)
36773721
caseT_SampleScan:
36783722
ptype="SampleScan";
36793723
break;
3680-
caseT_SubqueryScan:
3681-
ptype="SubqueryScan";
3682-
break;
36833724
caseT_FunctionScan:
36843725
ptype="FunctionScan";
36853726
break;
@@ -3692,6 +3733,12 @@ print_path(PlannerInfo *root, Path *path, int indent)
36923733
caseT_CteScan:
36933734
ptype="CteScan";
36943735
break;
3736+
caseT_NamedTuplestoreScan:
3737+
ptype="NamedTuplestoreScan";
3738+
break;
3739+
caseT_Result:
3740+
ptype="Result";
3741+
break;
36953742
caseT_WorkTableScan:
36963743
ptype="WorkTableScan";
36973744
break;
@@ -3716,7 +3763,7 @@ print_path(PlannerInfo *root, Path *path, int indent)
37163763
ptype="TidScan";
37173764
break;
37183765
caseT_SubqueryScanPath:
3719-
ptype="SubqueryScanScan";
3766+
ptype="SubqueryScan";
37203767
break;
37213768
caseT_ForeignPath:
37223769
ptype="ForeignScan";
@@ -3742,8 +3789,8 @@ print_path(PlannerInfo *root, Path *path, int indent)
37423789
caseT_MergeAppendPath:
37433790
ptype="MergeAppend";
37443791
break;
3745-
caseT_ResultPath:
3746-
ptype="Result";
3792+
caseT_GroupResultPath:
3793+
ptype="GroupResult";
37473794
break;
37483795
caseT_MaterialPath:
37493796
ptype="Material";

‎src/backend/optimizer/path/costsize.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,6 +1570,40 @@ cost_namedtuplestorescan(Path *path, PlannerInfo *root,
15701570
path->total_cost=startup_cost+run_cost;
15711571
}
15721572

1573+
/*
1574+
* cost_resultscan
1575+
* Determines and returns the cost of scanning an RTE_RESULT relation.
1576+
*/
1577+
void
1578+
cost_resultscan(Path*path,PlannerInfo*root,
1579+
RelOptInfo*baserel,ParamPathInfo*param_info)
1580+
{
1581+
Coststartup_cost=0;
1582+
Costrun_cost=0;
1583+
QualCostqpqual_cost;
1584+
Costcpu_per_tuple;
1585+
1586+
/* Should only be applied to RTE_RESULT base relations */
1587+
Assert(baserel->relid>0);
1588+
Assert(baserel->rtekind==RTE_RESULT);
1589+
1590+
/* Mark the path with the correct row estimate */
1591+
if (param_info)
1592+
path->rows=param_info->ppi_rows;
1593+
else
1594+
path->rows=baserel->rows;
1595+
1596+
/* We charge qual cost plus cpu_tuple_cost */
1597+
get_restriction_qual_cost(root,baserel,param_info,&qpqual_cost);
1598+
1599+
startup_cost+=qpqual_cost.startup;
1600+
cpu_per_tuple=cpu_tuple_cost+qpqual_cost.per_tuple;
1601+
run_cost+=cpu_per_tuple*baserel->tuples;
1602+
1603+
path->startup_cost=startup_cost;
1604+
path->total_cost=startup_cost+run_cost;
1605+
}
1606+
15731607
/*
15741608
* cost_recursive_union
15751609
* Determines and returns the cost of performing a recursive union,
@@ -5044,6 +5078,29 @@ set_namedtuplestore_size_estimates(PlannerInfo *root, RelOptInfo *rel)
50445078
set_baserel_size_estimates(root,rel);
50455079
}
50465080

5081+
/*
5082+
* set_result_size_estimates
5083+
*Set the size estimates for an RTE_RESULT base relation
5084+
*
5085+
* The rel's targetlist and restrictinfo list must have been constructed
5086+
* already.
5087+
*
5088+
* We set the same fields as set_baserel_size_estimates.
5089+
*/
5090+
void
5091+
set_result_size_estimates(PlannerInfo*root,RelOptInfo*rel)
5092+
{
5093+
/* Should only be applied to RTE_RESULT base relations */
5094+
Assert(rel->relid>0);
5095+
Assert(planner_rt_fetch(rel->relid,root)->rtekind==RTE_RESULT);
5096+
5097+
/* RTE_RESULT always generates a single row, natively */
5098+
rel->tuples=1;
5099+
5100+
/* Now estimate number of output rows, etc */
5101+
set_baserel_size_estimates(root,rel);
5102+
}
5103+
50475104
/*
50485105
* set_foreign_size_estimates
50495106
*Set the size estimates for a base relation that is a foreign table.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp