postgresql/src/backend/optimizer/path/orindxpath.c

272 lines
7.3 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* orindxpath.c
* Routines to find index paths that match a set of 'or' clauses
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
1999-07-16 07:00:38 +02:00
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.28 1999/07/16 04:59:15 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
1999-07-16 07:00:38 +02:00
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
1999-07-16 07:00:38 +02:00
#include "optimizer/internal.h"
#include "optimizer/paths.h"
#include "optimizer/plancat.h"
1999-07-16 07:00:38 +02:00
#include "optimizer/restrictinfo.h"
#include "parser/parsetree.h"
1999-05-26 00:43:53 +02:00
static void best_or_subclause_indices(Query *root, RelOptInfo *rel, List *subclauses,
1999-05-25 18:15:34 +02:00
List *indices, List **indexids, Cost *cost, Cost *selec);
1999-05-26 00:43:53 +02:00
static void best_or_subclause_index(Query *root, RelOptInfo *rel, Expr *subclause,
List *indices, int *indexid, Cost *cost, Cost *selec);
/*
* create_or_index_paths
* Creates index paths for indices that match 'or' clauses.
*
* 'rel' is the relation entry for which the paths are to be defined on
* 'clauses' is the list of available restriction clause nodes
*
* Returns a list of these index path nodes.
*
*/
List *
create_or_index_paths(Query *root,
1999-05-26 00:43:53 +02:00
RelOptInfo *rel, List *clauses)
{
List *t_list = NIL;
1998-08-02 00:12:13 +02:00
List *clist;
1998-08-02 00:12:13 +02:00
foreach(clist, clauses)
{
RestrictInfo *clausenode = (RestrictInfo *) (lfirst(clist));
/*
* Check to see if this clause is an 'or' clause, and, if so,
* whether or not each of the subclauses within the 'or' clause
* has been matched by an index (the 'Index field was set in
* (match_or) if no index matches a given subclause, one of the
* lists of index nodes returned by (get_index) will be 'nil').
*/
if (valid_or_clause(clausenode) &&
clausenode->indexids)
{
List *temp = NIL;
List *index_list = NIL;
bool index_flag = true;
index_list = clausenode->indexids;
foreach(temp, index_list)
{
1998-08-02 00:12:13 +02:00
if (!lfirst(temp))
{
index_flag = false;
1998-08-02 00:12:13 +02:00
break;
}
}
1998-08-31 09:19:56 +02:00
/* do they all have indexes? */
if (index_flag)
{ /* used to be a lisp every function */
IndexPath *pathnode = makeNode(IndexPath);
1999-03-08 15:01:57 +01:00
List *indexids = NIL;
Cost cost;
1999-05-25 18:15:34 +02:00
Cost selec;
best_or_subclause_indices(root,
rel,
clausenode->clause->args,
clausenode->indexids,
&indexids,
&cost,
1999-03-08 15:01:57 +01:00
&selec);
pathnode->path.pathtype = T_IndexScan;
pathnode->path.parent = rel;
1999-02-11 15:59:09 +01:00
pathnode->path.pathorder = makeNode(PathOrder);
1999-05-25 18:15:34 +02:00
pathnode->path.pathorder->ordtype = SORTOP_ORDER;
/*
* This is an IndexScan, but it does index lookups based
* on the order of the fields specified in the WHERE
* clause, not in any order, so the sortop is NULL.
1998-09-21 17:41:28 +02:00
*/
1999-05-25 18:15:34 +02:00
pathnode->path.pathorder->ord.sortop = NULL;
pathnode->path.pathkeys = NIL;
1998-09-21 17:41:28 +02:00
1998-08-02 00:12:13 +02:00
pathnode->indexqual = lcons(clausenode, NIL);
pathnode->indexid = indexids;
pathnode->path.path_cost = cost;
/*
* copy restrictinfo list into path for expensive function
* processing -- JMH, 7/7/92
*/
pathnode->path.loc_restrictinfo = set_difference(copyObject((Node *) rel->restrictinfo),
1999-05-25 18:15:34 +02:00
lcons(clausenode, NIL));
1999-05-25 18:15:34 +02:00
#ifdef NOT_USED /* fix xfunc */
/* add in cost for expensive functions! -- JMH, 7/7/92 */
if (XfuncMode != XFUNC_OFF)
((Path *) pathnode)->path_cost += xfunc_get_path_cost((Path) pathnode);
#endif
1999-03-08 15:01:57 +01:00
clausenode->selectivity = (Cost) selec;
1998-08-02 00:12:13 +02:00
t_list = lappend(t_list, pathnode);
}
}
}
1998-09-01 05:29:17 +02:00
return t_list;
}
/*
* best_or_subclause_indices
* Determines the best index to be used in conjunction with each subclause
* of an 'or' clause and the cost of scanning a relation using these
* indices. The cost is the sum of the individual index costs.
*
* 'rel' is the node of the relation on which the index is defined
* 'subclauses' are the subclauses of the 'or' clause
* 'indices' are those index nodes that matched subclauses of the 'or'
* clause
* 'examined_indexids' is a list of those index ids to be used with
* subclauses that have already been examined
* 'subcost' is the cost of using the indices in 'examined_indexids'
1999-03-08 15:01:57 +01:00
* 'selec' is a list of all subclauses that have already been examined
*
* Returns a list of the indexids, cost, and selectivities of each
* subclause, e.g., ((i1 i2 i3) cost (s1 s2 s3)), where 'i' is an OID,
* 'cost' is a flonum, and 's' is a flonum.
*/
static void
best_or_subclause_indices(Query *root,
1999-05-26 00:43:53 +02:00
RelOptInfo *rel,
List *subclauses,
List *indices,
List **indexids, /* return value */
1999-05-25 18:15:34 +02:00
Cost *cost, /* return value */
Cost *selec) /* return value */
{
1999-05-25 18:15:34 +02:00
List *slist;
1999-03-08 15:01:57 +01:00
*selec = (Cost) 0.0;
*cost = (Cost) 0.0;
1999-05-25 18:15:34 +02:00
foreach(slist, subclauses)
{
int best_indexid;
Cost best_cost;
Cost best_selec;
1998-08-02 00:12:13 +02:00
best_or_subclause_index(root, rel, lfirst(slist), lfirst(indices),
&best_indexid, &best_cost, &best_selec);
1999-03-08 15:01:57 +01:00
*indexids = lappendi(*indexids, best_indexid);
*cost += best_cost;
*selec += best_selec;
if (*selec > (Cost) 1.0)
*selec = (Cost) 1.0;
1998-08-02 00:12:13 +02:00
indices = lnext(indices);
}
1998-08-02 00:12:13 +02:00
return;
}
/*
* best_or_subclause_index
* Determines which is the best index to be used with a subclause of
* an 'or' clause by estimating the cost of using each index and selecting
* the least expensive.
*
* 'rel' is the node of the relation on which the index is defined
* 'subclause' is the subclause
* 'indices' is a list of index nodes that match the subclause
*
* Returns a list (index_id index_subcost index_selectivity)
* (a fixnum, a fixnum, and a flonum respectively).
*
*/
static void
best_or_subclause_index(Query *root,
1999-05-26 00:43:53 +02:00
RelOptInfo *rel,
Expr *subclause,
List *indices,
int *retIndexid, /* return value */
Cost *retCost, /* return value */
Cost *retSelec) /* return value */
{
List *ilist;
bool first_run = true;
1998-08-31 09:19:56 +02:00
/* if we don't match anything, return zeros */
*retIndexid = 0;
*retCost = 0.0;
*retSelec = 0.0;
foreach(ilist, indices)
{
RelOptInfo *index = (RelOptInfo *) lfirst(ilist);
Datum value;
int flag = 0;
Cost subcost;
AttrNumber attno = (get_leftop(subclause))->varattno;
Oid opno = ((Oper *) subclause->oper)->opno;
bool constant_on_right = non_null((Expr *) get_rightop(subclause));
float npages,
selec;
if (constant_on_right)
value = ((Const *) get_rightop(subclause))->constvalue;
else
value = NameGetDatum("");
if (constant_on_right)
flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_);
else
flag = _SELEC_CONSTANT_RIGHT_;
1998-08-02 00:12:13 +02:00
index_selectivity(lfirsti(index->relids),
index->classlist,
lconsi(opno, NIL),
getrelid(lfirsti(rel->relids),
root->rtable),
lconsi(attno, NIL),
lconsi(value, NIL),
lconsi(flag, NIL),
1,
&npages,
&selec);
subcost = cost_index((Oid) lfirsti(index->relids),
(int) npages,
(Cost) selec,
rel->pages,
rel->tuples,
index->pages,
index->tuples,
false);
1998-08-02 00:12:13 +02:00
if (first_run || subcost < *retCost)
{
*retIndexid = lfirsti(index->relids);
*retCost = subcost;
*retSelec = selec;
1998-08-02 00:12:13 +02:00
first_run = false;
}
1998-08-02 00:12:13 +02:00
}
return;
}