diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2010-11-04 12:01:17 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2010-11-04 12:01:17 -0400 |
commit | 034967bdcbb0c7be61d0500955226e1234ec5f04 (patch) | |
tree | 501a2819d7895cca156d08025cd5de49418c8d69 /src/backend/optimizer/plan/planmain.c | |
parent | 0abc8fdd4df3dd0524cd9fd8e2d761cf932dd80f (diff) | |
download | postgresql-034967bdcbb0c7be61d0500955226e1234ec5f04.tar.gz postgresql-034967bdcbb0c7be61d0500955226e1234ec5f04.zip |
Reimplement planner's handling of MIN/MAX aggregate optimization.
Per my recent proposal, get rid of all the direct inspection of indexes
and manual generation of paths in planagg.c. Instead, set up
EquivalenceClasses for the aggregate argument expressions, and let the
regular path generation logic deal with creating paths that can satisfy
those sort orders. This makes planagg.c a bit more visible to the rest
of the planner than it was originally, but the approach is basically a lot
cleaner than before. A major advantage of doing it this way is that we get
MIN/MAX optimization on inheritance trees (using MergeAppend of indexscans)
practically for free, whereas in the old way we'd have had to add a whole
lot more duplicative logic.
One small disadvantage of this approach is that MIN/MAX aggregates can no
longer exploit partial indexes having an "x IS NOT NULL" predicate, unless
that restriction or something that implies it is specified in the query.
The previous implementation was able to use the added "x IS NOT NULL"
condition as an extra predicate proof condition, but in this version we
rely entirely on indexes that are considered usable by the main planning
process. That seems a fair tradeoff for the simplicity and functionality
gained.
Diffstat (limited to 'src/backend/optimizer/plan/planmain.c')
-rw-r--r-- | src/backend/optimizer/plan/planmain.c | 59 |
1 files changed, 37 insertions, 22 deletions
diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index fd4c6f54d0f..cab6e9e25ad 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -30,6 +30,10 @@ #include "utils/selfuncs.h" +/* Local functions */ +static void canonicalize_all_pathkeys(PlannerInfo *root); + + /* * query_planner * Generate a path (that is, a simplified plan) for a basic query, @@ -68,9 +72,9 @@ * PlannerInfo field and not a passed parameter is that the low-level routines * in indxpath.c need to see it.) * - * Note: the PlannerInfo node also includes group_pathkeys, window_pathkeys, - * distinct_pathkeys, and sort_pathkeys, which like query_pathkeys need to be - * canonicalized once the info is available. + * Note: the PlannerInfo node includes other pathkeys fields besides + * query_pathkeys, all of which need to be canonicalized once the info is + * available. See canonicalize_all_pathkeys. * * tuple_fraction is interpreted as follows: * 0: expect all tuples to be retrieved (normal case) @@ -118,16 +122,7 @@ query_planner(PlannerInfo *root, List *tlist, * something like "SELECT 2+2 ORDER BY 1". */ root->canon_pathkeys = NIL; - root->query_pathkeys = canonicalize_pathkeys(root, - root->query_pathkeys); - root->group_pathkeys = canonicalize_pathkeys(root, - root->group_pathkeys); - root->window_pathkeys = canonicalize_pathkeys(root, - root->window_pathkeys); - root->distinct_pathkeys = canonicalize_pathkeys(root, - root->distinct_pathkeys); - root->sort_pathkeys = canonicalize_pathkeys(root, - root->sort_pathkeys); + canonicalize_all_pathkeys(root); return; } @@ -136,7 +131,7 @@ query_planner(PlannerInfo *root, List *tlist, * for "simple" rels. * * NOTE: append_rel_list was set up by subquery_planner, so do not touch - * here; eq_classes may contain data already, too. + * here; eq_classes and minmax_aggs may contain data already, too. */ root->simple_rel_array_size = list_length(parse->rtable) + 1; root->simple_rel_array = (RelOptInfo **) @@ -212,15 +207,10 @@ query_planner(PlannerInfo *root, List *tlist, /* * We have completed merging equivalence sets, so it's now possible to - * convert the requested query_pathkeys to canonical form. Also - * canonicalize the groupClause, windowClause, distinctClause and - * sortClause pathkeys for use later. + * convert previously generated pathkeys (in particular, the requested + * query_pathkeys) to canonical form. */ - root->query_pathkeys = canonicalize_pathkeys(root, root->query_pathkeys); - root->group_pathkeys = canonicalize_pathkeys(root, root->group_pathkeys); - root->window_pathkeys = canonicalize_pathkeys(root, root->window_pathkeys); - root->distinct_pathkeys = canonicalize_pathkeys(root, root->distinct_pathkeys); - root->sort_pathkeys = canonicalize_pathkeys(root, root->sort_pathkeys); + canonicalize_all_pathkeys(root); /* * Examine any "placeholder" expressions generated during subquery pullup. @@ -430,3 +420,28 @@ query_planner(PlannerInfo *root, List *tlist, *cheapest_path = cheapestpath; *sorted_path = sortedpath; } + + +/* + * canonicalize_all_pathkeys + * Canonicalize all pathkeys that were generated before entering + * query_planner and then stashed in PlannerInfo. + */ +static void +canonicalize_all_pathkeys(PlannerInfo *root) +{ + ListCell *lc; + + root->query_pathkeys = canonicalize_pathkeys(root, root->query_pathkeys); + root->group_pathkeys = canonicalize_pathkeys(root, root->group_pathkeys); + root->window_pathkeys = canonicalize_pathkeys(root, root->window_pathkeys); + root->distinct_pathkeys = canonicalize_pathkeys(root, root->distinct_pathkeys); + root->sort_pathkeys = canonicalize_pathkeys(root, root->sort_pathkeys); + + foreach(lc, root->minmax_aggs) + { + MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc); + + mminfo->pathkeys = canonicalize_pathkeys(root, mminfo->pathkeys); + } +} |