1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-07 19:06:32 +03:00

Allow index use with OR clauses.

This commit is contained in:
Bruce Momjian
1998-08-01 22:12:13 +00:00
parent 0668aa8817
commit 0a2e5cdfc9
9 changed files with 289 additions and 318 deletions

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.9 1998/07/18 04:22:30 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.10 1998/08/01 22:12:11 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -159,19 +159,8 @@ set_rest_selec(Query *root, List *clauseinfo_list)
Cost
compute_clause_selec(Query *root, Node *clause, List *or_selectivities)
{
if (!is_opclause(clause))
{
/*
* if it's not an operator clause, then it is a boolean clause
* -jolly
*/
/*
* Boolean variables get a selectivity of 1/2.
*/
return (0.1);
}
if (is_opclause (clause))
return compute_selec(root, lcons(clause,NIL), or_selectivities);
else if (not_clause(clause))
{

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.19 1998/07/31 15:10:40 vadim Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.20 1998/08/01 22:12:12 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,6 +21,7 @@
#include "access/nbtree.h"
#include "catalog/catname.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_type.h"
#include "executor/executor.h"
#include "fmgr.h"
#include "nodes/makefuncs.h"
@@ -77,10 +78,7 @@ create_index_paths(Query *root, RelOptInfo *rel, RelOptInfo *index,
List *clausegroup_list, bool join);
static List *add_index_paths(List *indexpaths, List *new_indexpaths);
static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index);
static bool SingleAttributeIndex(RelOptInfo *index);
/* If Spyros can use a constant PRS2_BOOL_TYPEID, I can use this */
#define BOOL_TYPEID ((Oid) 16)
/*
* find-index-paths--
@@ -121,91 +119,82 @@ find_index_paths(Query *root,
List *joinclausegroups = NIL;
List *joinpaths = NIL;
List *retval = NIL;
if (indices == NIL)
return (NULL);
index = (RelOptInfo *) lfirst(indices);
retval = find_index_paths(root,
rel,
lnext(indices),
clauseinfo_list,
joininfo_list);
/* If this is a partial index, return if it fails the predicate test */
if (index->indpred != NIL)
if (!pred_test(index->indpred, clauseinfo_list, joininfo_list))
return retval;
/*
* 1. If this index has only one key, try matching it against
* subclauses of an 'or' clause. The fields of the clauseinfo nodes
* are marked with lists of the matching indices no path are actually
* created.
*
* XXX NOTE: Currently btrees dos not support indices with > 1 key, so
* the following test will always be true for now but we have decided
* not to support index-scans on disjunction . -- lp
*/
if (SingleAttributeIndex(index))
List *ilist;
foreach(ilist, indices)
{
index = (RelOptInfo *) lfirst(ilist);
/* If this is a partial index, return if it fails the predicate test */
if (index->indpred != NIL)
if (!pred_test(index->indpred, clauseinfo_list, joininfo_list))
continue;
/*
* 1. Try matching the index against subclauses of an 'or' clause.
* The fields of the clauseinfo nodes are marked with lists of the
* matching indices. No path are actually created. We currently
* only look to match the first key. We don't find multi-key index
* cases where an AND matches the first key, and the OR matches the
* second key.
*/
match_index_orclauses(rel,
index,
index->indexkeys[0],
index->classlist[0],
clauseinfo_list);
index,
index->indexkeys[0],
index->classlist[0],
clauseinfo_list);
}
/*
* 2. If the keys of this index match any of the available restriction
* clauses, then create pathnodes corresponding to each group of
* usable clauses.
*/
scanclausegroups = group_clauses_by_indexkey(rel,
index,
index->indexkeys,
index->classlist,
clauseinfo_list);
scanpaths = NIL;
if (scanclausegroups != NIL)
scanpaths = create_index_paths(root,
rel,
index,
scanclausegroups,
false);
/*
* 3. If this index can be used with any join clause, then create
* pathnodes for each group of usable clauses. An index can be used
* with a join clause if its ordering is useful for a mergejoin, or if
* the index can possibly be used for scanning the inner relation of a
* nestloop join.
*/
joinclausegroups = indexable_joinclauses(rel, index, joininfo_list, clauseinfo_list);
joinpaths = NIL;
if (joinclausegroups != NIL)
{
List *new_join_paths = create_index_paths(root, rel,
index,
joinclausegroups,
true);
List *innerjoin_paths = index_innerjoin(root, rel, joinclausegroups, index);
rel->innerjoin = nconc(rel->innerjoin, innerjoin_paths);
joinpaths = new_join_paths;
}
/*
* Some sanity checks to make sure that the indexpath is valid.
*/
if (joinpaths != NULL)
retval = add_index_paths(joinpaths, retval);
if (scanpaths != NULL)
retval = add_index_paths(scanpaths, retval);
}
/*
* 2. If the keys of this index match any of the available restriction
* clauses, then create pathnodes corresponding to each group of
* usable clauses.
*/
scanclausegroups = group_clauses_by_indexkey(rel,
index,
index->indexkeys,
index->classlist,
clauseinfo_list);
scanpaths = NIL;
if (scanclausegroups != NIL)
scanpaths = create_index_paths(root,
rel,
index,
scanclausegroups,
false);
/*
* 3. If this index can be used with any join clause, then create
* pathnodes for each group of usable clauses. An index can be used
* with a join clause if its ordering is useful for a mergejoin, or if
* the index can possibly be used for scanning the inner relation of a
* nestloop join.
*/
joinclausegroups = indexable_joinclauses(rel, index, joininfo_list, clauseinfo_list);
joinpaths = NIL;
if (joinclausegroups != NIL)
{
List *new_join_paths = create_index_paths(root, rel,
index,
joinclausegroups,
true);
List *innerjoin_paths = index_innerjoin(root, rel, joinclausegroups, index);
rel->innerjoin = nconc(rel->innerjoin, innerjoin_paths);
joinpaths = new_join_paths;
}
/*
* Some sanity checks to make sure that the indexpath is valid.
*/
if (joinpaths != NULL)
retval = add_index_paths(joinpaths, retval);
if (scanpaths != NULL)
retval = add_index_paths(scanpaths, retval);
return retval;
}
@@ -297,7 +286,7 @@ match_index_to_operand(int indexkey,
* (1) the operator within the subclause can be used with one
* of the index's operator classes, and
* (2) there is a usable key that matches the variable within a
* sargable clause.
* searchable clause.
*
* 'or-clauses' are the remaining subclauses within the 'or' clause
* 'other-matching-indices' is the list of information on other indices
@@ -322,30 +311,31 @@ match_index_orclause(RelOptInfo *rel,
List *matched_indices = other_matching_indices;
List *index_list = NIL;
List *clist;
List *ind;
if (!matched_indices)
matched_indices = lcons(NIL, NIL);
for (clist = or_clauses, ind = matched_indices;
clist;
clist = lnext(clist), ind = lnext(ind))
foreach(clist, or_clauses)
{
clause = lfirst(clist);
if (is_opclause(clause) &&
op_class(((Oper *) ((Expr *) clause)->oper)->opno,
xclass, index->relam) &&
match_index_to_operand(indexkey,
((match_index_to_operand(indexkey,
(Expr *) get_leftop((Expr *) clause),
rel,
index) &&
IsA(get_rightop((Expr *) clause), Const))
IsA(get_rightop((Expr *) clause), Const)) ||
(match_index_to_operand(indexkey,
(Expr *) get_leftop((Expr *) clause),
rel,
index) &&
IsA(get_rightop((Expr *) clause), Const))))
{
matched_indices = lcons(index, matched_indices);
index_list = lappend(index_list,
matched_indices);
}
index_list = lappend(index_list, matched_indices);
/* for the first index, we are creating the indexids list */
if (matched_indices)
matched_indices = lnext(matched_indices);
}
return (index_list);
@@ -1061,7 +1051,7 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
*/
test_oper = makeOper(test_op, /* opno */
InvalidOid, /* opid */
BOOL_TYPEID, /* opresulttype */
BOOLOID, /* opresulttype */
0, /* opsize */
NULL); /* op_fcache */
replace_opid(test_oper);
@@ -1176,7 +1166,8 @@ extract_restrict_clauses(List *clausegroup)
*
*/
static List *
index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list, RelOptInfo *index)
index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
RelOptInfo *index)
{
List *clausegroup = NIL;
List *cg_list = NIL;
@@ -1366,29 +1357,3 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index)
return true;
}
static bool
SingleAttributeIndex(RelOptInfo *index)
{
/*
* return false for now as I don't know if we support index scans on
* disjunction and the code doesn't work
*/
return (false);
#if 0
/*
* Non-functional indices.
*/
if (index->indproc == InvalidOid)
return (index->indexkeys[0] != 0 &&
index->indexkeys[1] == 0);
/*
* We have a functional index which is a single attr index
*/
return true;
#endif
}

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.7 1998/07/18 04:22:33 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.8 1998/08/01 22:12:13 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -55,10 +55,11 @@ create_or_index_paths(Query *root,
RelOptInfo *rel, List *clauses)
{
List *t_list = NIL;
List *clist;
if (clauses != NIL)
foreach(clist, clauses)
{
CInfo *clausenode = (CInfo *) (lfirst(clauses));
CInfo *clausenode = (CInfo *) (lfirst(clist));
/*
* Check to see if this clause is an 'or' clause, and, if so,
@@ -77,8 +78,11 @@ create_or_index_paths(Query *root,
index_list = clausenode->indexids;
foreach(temp, index_list)
{
if (!temp)
if (!lfirst(temp))
{
index_flag = false;
break;
}
}
if (index_flag)
{ /* used to be a lisp every function */
@@ -100,8 +104,7 @@ create_or_index_paths(Query *root,
pathnode->path.pathtype = T_IndexScan;
pathnode->path.parent = rel;
pathnode->indexqual =
lcons(clausenode, NIL);
pathnode->indexqual = lcons(clausenode, NIL);
pathnode->indexid = indexids;
pathnode->path.path_cost = cost;
@@ -110,9 +113,8 @@ create_or_index_paths(Query *root,
* processing -- JMH, 7/7/92
*/
pathnode->path.locclauseinfo =
set_difference(clauses,
copyObject((Node *)
rel->clauseinfo));
set_difference(copyObject((Node *)rel->clauseinfo),
lcons(clausenode,NIL));
#if 0 /* fix xfunc */
/* add in cost for expensive functions! -- JMH, 7/7/92 */
@@ -123,12 +125,8 @@ create_or_index_paths(Query *root,
}
#endif
clausenode->selectivity = (Cost) floatVal(selecs);
t_list =
lcons(pathnode,
create_or_index_paths(root, rel, lnext(clauses)));
t_list = lappend(t_list, pathnode);
}
else
t_list = create_or_index_paths(root, rel, lnext(clauses));
}
}
@@ -167,32 +165,28 @@ best_or_subclause_indices(Query *root,
Cost *cost, /* return value */
List **selecs) /* return value */
{
if (subclauses == NIL)
{
*indexids = nreverse(examined_indexids);
*cost = subcost;
*selecs = nreverse(selectivities);
}
else
List *slist;
foreach (slist, subclauses)
{
int best_indexid;
Cost best_cost;
Cost best_selec;
best_or_subclause_index(root, rel, lfirst(subclauses), lfirst(indices),
best_or_subclause_index(root, rel, lfirst(slist), lfirst(indices),
&best_indexid, &best_cost, &best_selec);
examined_indexids = lappendi(examined_indexids, best_indexid);
subcost += best_cost;
selectivities = lappend(selectivities, makeFloat(best_selec));
best_or_subclause_indices(root,
rel,
lnext(subclauses),
lnext(indices),
lconsi(best_indexid, examined_indexids),
subcost + best_cost,
lcons(makeFloat(best_selec), selectivities),
indexids,
cost,
selecs);
indices = lnext(indices);
}
*indexids = examined_indexids;
*cost = subcost;
*selecs = selectivities;
return;
}
@@ -219,20 +213,21 @@ best_or_subclause_index(Query *root,
Cost *retCost, /* return value */
Cost *retSelec) /* return value */
{
if (indices != NIL)
List *ilist;
bool first_run = true;
foreach (ilist, indices)
{
RelOptInfo *index = (RelOptInfo *) lfirst(ilist);
Datum value;
int flag = 0;
Cost subcost;
RelOptInfo *index = (RelOptInfo *) lfirst(indices);
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;
int subclause_indexid;
Cost subclause_cost;
Cost subclause_selec;
if (constant_on_right)
value = ((Const *) get_rightop(subclause))->constvalue;
@@ -242,6 +237,7 @@ best_or_subclause_index(Query *root,
flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_);
else
flag = _SELEC_CONSTANT_RIGHT_;
index_selectivity(lfirsti(index->relids),
index->classlist,
lconsi(opno, NIL),
@@ -262,26 +258,22 @@ best_or_subclause_index(Query *root,
index->pages,
index->tuples,
false);
best_or_subclause_index(root,
rel,
subclause,
lnext(indices),
&subclause_indexid,
&subclause_cost,
&subclause_selec);
if (subclause_indexid == 0 || subcost < subclause_cost)
if (first_run || subcost < *retCost)
{
*retIndexid = lfirsti(index->relids);
*retCost = subcost;
*retSelec = selec;
first_run = false;
}
else
{
*retIndexid = 0;
*retCost = 0.0;
*retSelec = 0.0;
}
}
/* we didn't get any indexes, so zero return values */
if (first_run)
{
*retIndexid = 0;
*retCost = 0.0;
*retSelec = 0.0;
}
return;
}