1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-11 20:28:21 +03:00

Further fallout from the MergeAppend patch.

Fix things so that top-N sorting can be used in child Sort nodes of a
MergeAppend node, when there is a LIMIT and no intervening joins or
grouping.  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 an
explicit sort cheaper when there will be grouping or aggregation in
between.  Possibly this should be back-patched, but I'm not sure the
mistake is serious enough to be a real problem in practice.
This commit is contained in:
Tom Lane
2010-11-18 00:30:10 -05:00
parent 45768d10e3
commit 6fbc323c80
7 changed files with 103 additions and 21 deletions

View File

@ -25,6 +25,7 @@
#include "executor/nodeLimit.h"
static void recompute_limits(LimitState *node);
static void pass_down_bound(LimitState *node, PlanState *child_node);
/* ----------------------------------------------------------------
@ -293,26 +294,35 @@ recompute_limits(LimitState *node)
/* Set state-machine state */
node->lstate = LIMIT_RESCAN;
/*
* If we have a COUNT, and our input is a Sort node, notify it that it can
* use bounded sort.
*
* This is a bit of a kluge, but we don't have any more-abstract way of
* communicating between the two nodes; and it doesn't seem worth trying
* to invent one without some more examples of special communication
* needs.
*
* Note: it is the responsibility of nodeSort.c to react properly to
* changes of these parameters. If we ever do redesign this, it'd be a
* good idea to integrate this signaling with the parameter-change
* mechanism.
*/
if (IsA(outerPlanState(node), SortState))
/* Notify child node about limit, if useful */
pass_down_bound(node, outerPlanState(node));
}
/*
* If we have a COUNT, and our input is a Sort node, notify it that it can
* use bounded sort. Also, if our input is a MergeAppend, we can apply the
* same bound to any Sorts that are direct children of the MergeAppend,
* since the MergeAppend surely need read no more than that many tuples from
* any one input. We also have to be prepared to look through a Result,
* since the planner might stick one atop MergeAppend for projection purposes.
*
* This is a bit of a kluge, but we don't have any more-abstract way of
* communicating between the two nodes; and it doesn't seem worth trying
* to invent one without some more examples of special communication needs.
*
* Note: it is the responsibility of nodeSort.c to react properly to
* changes of these parameters. If we ever do redesign this, it'd be a
* good idea to integrate this signaling with the parameter-change mechanism.
*/
static void
pass_down_bound(LimitState *node, PlanState *child_node)
{
if (IsA(child_node, SortState))
{
SortState *sortState = (SortState *) outerPlanState(node);
SortState *sortState = (SortState *) child_node;
int64 tuples_needed = node->count + node->offset;
/* negative test checks for overflow */
/* negative test checks for overflow in sum */
if (node->noCount || tuples_needed < 0)
{
/* make sure flag gets reset if needed upon rescan */
@ -324,6 +334,19 @@ recompute_limits(LimitState *node)
sortState->bound = tuples_needed;
}
}
else if (IsA(child_node, MergeAppendState))
{
MergeAppendState *maState = (MergeAppendState *) child_node;
int i;
for (i = 0; i < maState->ms_nplans; i++)
pass_down_bound(node, maState->mergeplans[i]);
}
else if (IsA(child_node, ResultState))
{
if (outerPlanState(child_node))
pass_down_bound(node, outerPlanState(child_node));
}
}
/* ----------------------------------------------------------------