From f3a6b38e321a30a447c31404d127eee9d01582df Mon Sep 17 00:00:00 2001 From: Jan Wieck Date: Wed, 3 Feb 1999 19:31:24 +0000 Subject: [PATCH] Sort node for ORDER BY is suppressed if choosen index scan will allways present tuples in the requested order. Jan --- src/backend/optimizer/plan/planner.c | 177 ++++++++++++++++++++++++++- 1 file changed, 175 insertions(+), 2 deletions(-) diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 8edcfcd4f0..0008caddee 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.39 1999/02/02 17:46:14 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.40 1999/02/03 19:31:24 wieck Exp $ * *------------------------------------------------------------------------- */ @@ -50,6 +50,12 @@ #include "executor/executor.h" +#include "utils/builtins.h" +#include "utils/syscache.h" +#include "access/genam.h" +#include "parser/parse_oper.h" + +static bool need_sortplan(List *sortcls, Plan *plan); static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode); extern Plan *make_groupPlan(List **tlist, bool tuplePerGroup, List *groupClause, Plan *subplan); @@ -344,7 +350,7 @@ union_planner(Query *parse) } else { - if (parse->sortClause) + if (parse->sortClause && need_sortplan(parse->sortClause, result_plan)) return (make_sortplan(tlist, parse->sortClause, result_plan)); else return ((Plan *) result_plan); @@ -572,3 +578,170 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList) /* success */ return; } + + +/* ---------- + * Support function for need_sortplan + * ---------- + */ +static TargetEntry * +get_matching_tle(Plan *plan, Resdom *resdom) +{ + List *i; + TargetEntry *tle; + + foreach (i, plan->targetlist) { + tle = (TargetEntry *)lfirst(i); + if (tle->resdom->resno == resdom->resno) + return tle; + } + return NULL; +} + + +/* ---------- + * Check if a user requested ORDER BY is already satisfied by + * the choosen index scan. + * + * Returns TRUE if sort is required, FALSE if can be omitted. + * ---------- + */ +static bool +need_sortplan(List *sortcls, Plan *plan) +{ + Relation indexRel; + IndexScan *indexScan; + Oid indexId; + List *i; + HeapTuple htup; + Form_pg_index index_tup; + int key_no = 0; + + /* ---------- + * Must be an IndexScan + * ---------- + */ + if (nodeTag(plan) != T_IndexScan) { + return TRUE; + } + + indexScan = (IndexScan *)plan; + + /* ---------- + * Should not have left- or righttree + * ---------- + */ + if (plan->lefttree != NULL) { + return TRUE; + } + if (plan->righttree != NULL) { + return TRUE; + } + + /* ---------- + * Must be a single index scan + * ---------- + */ + if (length(indexScan->indxid) != 1) { + return TRUE; + } + + /* ---------- + * Indices can only have up to 8 attributes. So an ORDER BY using + * more that 8 attributes could never be satisfied by an index. + * ---------- + */ + if (length(sortcls) > 8) { + return TRUE; + } + + /* ---------- + * The choosen Index must be a btree + * ---------- + */ + indexId = lfirsti(indexScan->indxid); + + indexRel = index_open(indexId); + if (strcmp(nameout(&(indexRel->rd_am->amname)), "btree") != 0) { + heap_close(indexRel); + return TRUE; + } + heap_close(indexRel); + + /* ---------- + * Fetch the index tuple + * ---------- + */ + htup = SearchSysCacheTuple(INDEXRELID, + ObjectIdGetDatum(indexId), 0, 0, 0); + if (!HeapTupleIsValid(htup)) { + elog(ERROR, "cache lookup for index %d failed", indexId); + } + index_tup = (Form_pg_index) GETSTRUCT(htup); + + /* ---------- + * Check if all the sort clauses match the attributes in the index + * ---------- + */ + foreach (i, sortcls) { + SortClause *sortcl; + Resdom *resdom; + TargetEntry *tle; + Var *var; + + sortcl = (SortClause *) lfirst(i); + + resdom = sortcl->resdom; + tle = get_matching_tle(plan, resdom); + if (tle == NULL) { + /* ---------- + * Could this happen? + * ---------- + */ + return TRUE; + } + if (nodeTag(tle->expr) != T_Var) { + /* ---------- + * The target list expression isn't a var, so it + * cannot be the indexed attribute + * ---------- + */ + return TRUE; + } + var = (Var *)(tle->expr); + + if (var->varno != indexScan->scan.scanrelid) { + /* ---------- + * This Var isn't from the scan relation. So it isn't + * that of the index + * ---------- + */ + return TRUE; + } + + if (var->varattno != index_tup->indkey[key_no]) { + /* ---------- + * It isn't the indexed attribute. + * ---------- + */ + return TRUE; + } + + if (oprid(oper("<", resdom->restype, resdom->restype, FALSE)) != sortcl->opoid) { + /* ---------- + * Sort order isn't in ascending order. + * ---------- + */ + return TRUE; + } + + key_no++; + } + + /* ---------- + * Index matches ORDER BY - sort not required + * ---------- + */ + return FALSE; +} + -- GitLab