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

Commit6fbc323

Browse files
committed
Further fallout from the MergeAppend patch.
Fix things so that top-N sorting can be used in child Sort nodes of aMergeAppend node, when there is a LIMIT and no intervening joins orgrouping. Actually doing this on the executor side isn't too bad,but it's a bit messier to get the planner to cost it properly.Per gripe from Robert Haas.In passing, fix an oversight in the original top-N-sorting patch:query_planner should not assume that a LIMIT can be used to make anexplicit sort cheaper when there will be grouping or aggregation inbetween. Possibly this should be back-patched, but I'm not sure themistake is serious enough to be a real problem in practice.
1 parent45768d1 commit6fbc323

File tree

7 files changed

+103
-21
lines changed

7 files changed

+103
-21
lines changed

‎src/backend/executor/nodeLimit.c

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include"executor/nodeLimit.h"
2626

2727
staticvoidrecompute_limits(LimitState*node);
28+
staticvoidpass_down_bound(LimitState*node,PlanState*child_node);
2829

2930

3031
/* ----------------------------------------------------------------
@@ -293,26 +294,35 @@ recompute_limits(LimitState *node)
293294
/* Set state-machine state */
294295
node->lstate=LIMIT_RESCAN;
295296

296-
/*
297-
* If we have a COUNT, and our input is a Sort node, notify it that it can
298-
* use bounded sort.
299-
*
300-
* This is a bit of a kluge, but we don't have any more-abstract way of
301-
* communicating between the two nodes; and it doesn't seem worth trying
302-
* to invent one without some more examples of special communication
303-
* needs.
304-
*
305-
* Note: it is the responsibility of nodeSort.c to react properly to
306-
* changes of these parameters. If we ever do redesign this, it'd be a
307-
* good idea to integrate this signaling with the parameter-change
308-
* mechanism.
309-
*/
310-
if (IsA(outerPlanState(node),SortState))
297+
/* Notify child node about limit, if useful */
298+
pass_down_bound(node,outerPlanState(node));
299+
}
300+
301+
/*
302+
* If we have a COUNT, and our input is a Sort node, notify it that it can
303+
* use bounded sort. Also, if our input is a MergeAppend, we can apply the
304+
* same bound to any Sorts that are direct children of the MergeAppend,
305+
* since the MergeAppend surely need read no more than that many tuples from
306+
* any one input. We also have to be prepared to look through a Result,
307+
* since the planner might stick one atop MergeAppend for projection purposes.
308+
*
309+
* This is a bit of a kluge, but we don't have any more-abstract way of
310+
* communicating between the two nodes; and it doesn't seem worth trying
311+
* to invent one without some more examples of special communication needs.
312+
*
313+
* Note: it is the responsibility of nodeSort.c to react properly to
314+
* changes of these parameters. If we ever do redesign this, it'd be a
315+
* good idea to integrate this signaling with the parameter-change mechanism.
316+
*/
317+
staticvoid
318+
pass_down_bound(LimitState*node,PlanState*child_node)
319+
{
320+
if (IsA(child_node,SortState))
311321
{
312-
SortState*sortState= (SortState*)outerPlanState(node);
322+
SortState*sortState= (SortState*)child_node;
313323
int64tuples_needed=node->count+node->offset;
314324

315-
/* negative test checks for overflow */
325+
/* negative test checks for overflowin sum*/
316326
if (node->noCount||tuples_needed<0)
317327
{
318328
/* make sure flag gets reset if needed upon rescan */
@@ -324,6 +334,19 @@ recompute_limits(LimitState *node)
324334
sortState->bound=tuples_needed;
325335
}
326336
}
337+
elseif (IsA(child_node,MergeAppendState))
338+
{
339+
MergeAppendState*maState= (MergeAppendState*)child_node;
340+
inti;
341+
342+
for (i=0;i<maState->ms_nplans;i++)
343+
pass_down_bound(node,maState->mergeplans[i]);
344+
}
345+
elseif (IsA(child_node,ResultState))
346+
{
347+
if (outerPlanState(child_node))
348+
pass_down_bound(node,outerPlanState(child_node));
349+
}
327350
}
328351

329352
/* ----------------------------------------------------------------

‎src/backend/nodes/outfuncs.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,6 +1493,7 @@ _outMergeAppendPath(StringInfo str, MergeAppendPath *node)
14931493
_outPathInfo(str, (Path*)node);
14941494

14951495
WRITE_NODE_FIELD(subpaths);
1496+
WRITE_FLOAT_FIELD(limit_tuples,"%.0f");
14961497
}
14971498

14981499
staticvoid
@@ -1611,6 +1612,7 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node)
16111612
WRITE_NODE_FIELD(minmax_aggs);
16121613
WRITE_FLOAT_FIELD(total_table_pages,"%.0f");
16131614
WRITE_FLOAT_FIELD(tuple_fraction,"%.4f");
1615+
WRITE_FLOAT_FIELD(limit_tuples,"%.0f");
16141616
WRITE_BOOL_FIELD(hasInheritedTarget);
16151617
WRITE_BOOL_FIELD(hasJoinRTEs);
16161618
WRITE_BOOL_FIELD(hasHavingQual);

‎src/backend/optimizer/plan/createplan.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
714714
if (!pathkeys_contained_in(pathkeys,subpath->pathkeys))
715715
subplan= (Plan*)make_sort(root,subplan,numsortkeys,
716716
sortColIdx,sortOperators,nullsFirst,
717-
-1.0);
717+
best_path->limit_tuples);
718718

719719
subplans=lappend(subplans,subplan);
720720
}

‎src/backend/optimizer/plan/planmain.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,9 @@ query_planner(PlannerInfo *root, List *tlist,
101101
ListCell*lc;
102102
doubletotal_pages;
103103

104-
/* Make tuple_fraction accessible to lower-level routines */
104+
/* Make tuple_fraction, limit_tuples accessible to lower-level routines */
105105
root->tuple_fraction=tuple_fraction;
106+
root->limit_tuples=limit_tuples;
106107

107108
*num_groups=1;/* default result */
108109

@@ -315,6 +316,9 @@ query_planner(PlannerInfo *root, List *tlist,
315316
!pathkeys_contained_in(root->distinct_pathkeys,root->group_pathkeys)||
316317
!pathkeys_contained_in(root->window_pathkeys,root->group_pathkeys))
317318
tuple_fraction=0.0;
319+
320+
/* In any case, limit_tuples shouldn't be specified here */
321+
Assert(limit_tuples<0);
318322
}
319323
elseif (parse->hasAggs||root->hasHavingQual)
320324
{
@@ -323,6 +327,9 @@ query_planner(PlannerInfo *root, List *tlist,
323327
* it will deliver a single result row (so leave *num_groups 1).
324328
*/
325329
tuple_fraction=0.0;
330+
331+
/* limit_tuples shouldn't be specified here */
332+
Assert(limit_tuples<0);
326333
}
327334
elseif (parse->distinctClause)
328335
{
@@ -347,6 +354,9 @@ query_planner(PlannerInfo *root, List *tlist,
347354
*/
348355
if (tuple_fraction >=1.0)
349356
tuple_fraction /=*num_groups;
357+
358+
/* limit_tuples shouldn't be specified here */
359+
Assert(limit_tuples<0);
350360
}
351361
else
352362
{

‎src/backend/optimizer/plan/planner.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
968968
{
969969
/* No set operations, do regular planning */
970970
List*sub_tlist;
971+
doublesub_limit_tuples;
971972
AttrNumber*groupColIdx=NULL;
972973
boolneed_tlist_eval= true;
973974
QualCosttlist_cost;
@@ -1119,13 +1120,28 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
11191120
else
11201121
root->query_pathkeys=NIL;
11211122

1123+
/*
1124+
* Figure out whether there's a hard limit on the number of rows that
1125+
* query_planner's result subplan needs to return. Even if we know a
1126+
* hard limit overall, it doesn't apply if the query has any
1127+
* grouping/aggregation operations.
1128+
*/
1129+
if (parse->groupClause||
1130+
parse->distinctClause||
1131+
parse->hasAggs||
1132+
parse->hasWindowFuncs||
1133+
root->hasHavingQual)
1134+
sub_limit_tuples=-1.0;
1135+
else
1136+
sub_limit_tuples=limit_tuples;
1137+
11221138
/*
11231139
* Generate the best unsorted and presorted paths for this Query (but
11241140
* note there may not be any presorted path). query_planner will also
11251141
* estimate the number of groups in the query, and canonicalize all
11261142
* the pathkeys.
11271143
*/
1128-
query_planner(root,sub_tlist,tuple_fraction,limit_tuples,
1144+
query_planner(root,sub_tlist,tuple_fraction,sub_limit_tuples,
11291145
&cheapest_path,&sorted_path,&dNumGroups);
11301146

11311147
/*

‎src/backend/optimizer/util/pathnode.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,35 @@ create_merge_append_path(PlannerInfo *root,
694694
pathnode->path.pathkeys=pathkeys;
695695
pathnode->subpaths=subpaths;
696696

697+
/*
698+
* Apply query-wide LIMIT if known and path is for sole base relation.
699+
* Finding out the latter at this low level is a bit klugy.
700+
*/
701+
pathnode->limit_tuples=root->limit_tuples;
702+
if (pathnode->limit_tuples >=0)
703+
{
704+
Indexrti;
705+
706+
for (rti=1;rti<root->simple_rel_array_size;rti++)
707+
{
708+
RelOptInfo*brel=root->simple_rel_array[rti];
709+
710+
if (brel==NULL)
711+
continue;
712+
713+
/* ignore RTEs that are "other rels" */
714+
if (brel->reloptkind!=RELOPT_BASEREL)
715+
continue;
716+
717+
if (brel!=rel)
718+
{
719+
/* Oops, it's a join query */
720+
pathnode->limit_tuples=-1.0;
721+
break;
722+
}
723+
}
724+
}
725+
697726
/* Add up all the costs of the input paths */
698727
input_startup_cost=0;
699728
input_total_cost=0;
@@ -720,7 +749,7 @@ create_merge_append_path(PlannerInfo *root,
720749
subpath->parent->width,
721750
0.0,
722751
work_mem,
723-
-1.0);
752+
pathnode->limit_tuples);
724753
input_startup_cost+=sort_path.startup_cost;
725754
input_total_cost+=sort_path.total_cost;
726755
}

‎src/include/nodes/relation.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ typedef struct PlannerInfo
198198
doubletotal_table_pages;/* # of pages in all tables of query */
199199

200200
doubletuple_fraction;/* tuple_fraction passed to query_planner */
201+
doublelimit_tuples;/* limit_tuples passed to query_planner */
201202

202203
boolhasInheritedTarget;/* true if parse->resultRelation is an
203204
* inheritance child rel */
@@ -766,6 +767,7 @@ typedef struct MergeAppendPath
766767
{
767768
Pathpath;
768769
List*subpaths;/* list of component Paths */
770+
doublelimit_tuples;/* hard limit on output tuples, or -1 */
769771
}MergeAppendPath;
770772

771773
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp