Sort node for ORDER BY is suppressed if choosen index scan will
allways present tuples in the requested order. Jan
This commit is contained in:
parent
724119a979
commit
f3a6b38e32
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user