diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2010-11-18 00:30:10 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2010-11-18 00:30:10 -0500 |
commit | 6fbc323c8042303a737028f9da7616896bccc517 (patch) | |
tree | 8335501afc6e883ea14d0f88b3ca4f48f8a759ec /src/backend/executor/nodeLimit.c | |
parent | 45768d10e3abd513b4c959efeb5907798f2fac3f (diff) | |
download | postgresql-6fbc323c8042303a737028f9da7616896bccc517.tar.gz postgresql-6fbc323c8042303a737028f9da7616896bccc517.zip |
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.
Diffstat (limited to 'src/backend/executor/nodeLimit.c')
-rw-r--r-- | src/backend/executor/nodeLimit.c | 57 |
1 files changed, 40 insertions, 17 deletions
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c index ce24f1b00af..5ed8664f66f 100644 --- a/src/backend/executor/nodeLimit.c +++ b/src/backend/executor/nodeLimit.c @@ -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)); + } } /* ---------------------------------------------------------------- |