Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit f3a6b38

Browse files
Jan WieckJan Wieck
Jan Wieck
authored and
Jan Wieck
committed
Sort node for ORDER BY is suppressed if choosen index scan will
allways present tuples in the requested order. Jan
1 parent 724119a commit f3a6b38

File tree

1 file changed

+175
-2
lines changed

1 file changed

+175
-2
lines changed

src/backend/optimizer/plan/planner.c

Lines changed: 175 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.39 1999/02/02 17:46:14 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.40 1999/02/03 19:31:24 wieck Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -50,6 +50,12 @@
5050

5151
#include "executor/executor.h"
5252

53+
#include "utils/builtins.h"
54+
#include "utils/syscache.h"
55+
#include "access/genam.h"
56+
#include "parser/parse_oper.h"
57+
58+
static bool need_sortplan(List *sortcls, Plan *plan);
5359
static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode);
5460
extern Plan *make_groupPlan(List **tlist, bool tuplePerGroup,
5561
List *groupClause, Plan *subplan);
@@ -344,7 +350,7 @@ union_planner(Query *parse)
344350
}
345351
else
346352
{
347-
if (parse->sortClause)
353+
if (parse->sortClause && need_sortplan(parse->sortClause, result_plan))
348354
return (make_sortplan(tlist, parse->sortClause, result_plan));
349355
else
350356
return ((Plan *) result_plan);
@@ -572,3 +578,170 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
572578
/* success */
573579
return;
574580
}
581+
582+
583+
/* ----------
584+
* Support function for need_sortplan
585+
* ----------
586+
*/
587+
static TargetEntry *
588+
get_matching_tle(Plan *plan, Resdom *resdom)
589+
{
590+
List *i;
591+
TargetEntry *tle;
592+
593+
foreach (i, plan->targetlist) {
594+
tle = (TargetEntry *)lfirst(i);
595+
if (tle->resdom->resno == resdom->resno)
596+
return tle;
597+
}
598+
return NULL;
599+
}
600+
601+
602+
/* ----------
603+
* Check if a user requested ORDER BY is already satisfied by
604+
* the choosen index scan.
605+
*
606+
* Returns TRUE if sort is required, FALSE if can be omitted.
607+
* ----------
608+
*/
609+
static bool
610+
need_sortplan(List *sortcls, Plan *plan)
611+
{
612+
Relation indexRel;
613+
IndexScan *indexScan;
614+
Oid indexId;
615+
List *i;
616+
HeapTuple htup;
617+
Form_pg_index index_tup;
618+
int key_no = 0;
619+
620+
/* ----------
621+
* Must be an IndexScan
622+
* ----------
623+
*/
624+
if (nodeTag(plan) != T_IndexScan) {
625+
return TRUE;
626+
}
627+
628+
indexScan = (IndexScan *)plan;
629+
630+
/* ----------
631+
* Should not have left- or righttree
632+
* ----------
633+
*/
634+
if (plan->lefttree != NULL) {
635+
return TRUE;
636+
}
637+
if (plan->righttree != NULL) {
638+
return TRUE;
639+
}
640+
641+
/* ----------
642+
* Must be a single index scan
643+
* ----------
644+
*/
645+
if (length(indexScan->indxid) != 1) {
646+
return TRUE;
647+
}
648+
649+
/* ----------
650+
* Indices can only have up to 8 attributes. So an ORDER BY using
651+
* more that 8 attributes could never be satisfied by an index.
652+
* ----------
653+
*/
654+
if (length(sortcls) > 8) {
655+
return TRUE;
656+
}
657+
658+
/* ----------
659+
* The choosen Index must be a btree
660+
* ----------
661+
*/
662+
indexId = lfirsti(indexScan->indxid);
663+
664+
indexRel = index_open(indexId);
665+
if (strcmp(nameout(&(indexRel->rd_am->amname)), "btree") != 0) {
666+
heap_close(indexRel);
667+
return TRUE;
668+
}
669+
heap_close(indexRel);
670+
671+
/* ----------
672+
* Fetch the index tuple
673+
* ----------
674+
*/
675+
htup = SearchSysCacheTuple(INDEXRELID,
676+
ObjectIdGetDatum(indexId), 0, 0, 0);
677+
if (!HeapTupleIsValid(htup)) {
678+
elog(ERROR, "cache lookup for index %d failed", indexId);
679+
}
680+
index_tup = (Form_pg_index) GETSTRUCT(htup);
681+
682+
/* ----------
683+
* Check if all the sort clauses match the attributes in the index
684+
* ----------
685+
*/
686+
foreach (i, sortcls) {
687+
SortClause *sortcl;
688+
Resdom *resdom;
689+
TargetEntry *tle;
690+
Var *var;
691+
692+
sortcl = (SortClause *) lfirst(i);
693+
694+
resdom = sortcl->resdom;
695+
tle = get_matching_tle(plan, resdom);
696+
if (tle == NULL) {
697+
/* ----------
698+
* Could this happen?
699+
* ----------
700+
*/
701+
return TRUE;
702+
}
703+
if (nodeTag(tle->expr) != T_Var) {
704+
/* ----------
705+
* The target list expression isn't a var, so it
706+
* cannot be the indexed attribute
707+
* ----------
708+
*/
709+
return TRUE;
710+
}
711+
var = (Var *)(tle->expr);
712+
713+
if (var->varno != indexScan->scan.scanrelid) {
714+
/* ----------
715+
* This Var isn't from the scan relation. So it isn't
716+
* that of the index
717+
* ----------
718+
*/
719+
return TRUE;
720+
}
721+
722+
if (var->varattno != index_tup->indkey[key_no]) {
723+
/* ----------
724+
* It isn't the indexed attribute.
725+
* ----------
726+
*/
727+
return TRUE;
728+
}
729+
730+
if (oprid(oper("<", resdom->restype, resdom->restype, FALSE)) != sortcl->opoid) {
731+
/* ----------
732+
* Sort order isn't in ascending order.
733+
* ----------
734+
*/
735+
return TRUE;
736+
}
737+
738+
key_no++;
739+
}
740+
741+
/* ----------
742+
* Index matches ORDER BY - sort not required
743+
* ----------
744+
*/
745+
return FALSE;
746+
}
747+

0 commit comments

Comments
 (0)