Commit cdd230d6 authored by Tom Lane's avatar Tom Lane

Improve planning of OR indexscan plans: for quals like

	WHERE (a = 1 or a = 2) and b = 42
and an index on (a,b), include the clause b = 42 in the indexquals
generated for each arm of the OR clause.  Essentially this is an index-
driven conversion from CNF to DNF.  Implementation is a bit klugy, but
better than not exploiting the extra quals at all ...
parent 7c579fa1
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.75 2001/06/05 05:26:04 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.76 2001/06/05 17:13:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -232,7 +232,7 @@ set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte)
create_index_paths(root, rel);
/* create_index_paths must be done before create_or_index_paths */
create_or_index_paths(root, rel, rel->baserestrictinfo);
create_or_index_paths(root, rel);
/* Now find the cheapest of the paths for this rel */
set_cheapest(rel);
......
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.105 2001/05/20 20:28:18 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.106 2001/06/05 17:13:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -397,7 +397,7 @@ match_or_subclause_to_indexkey(RelOptInfo *rel,
clause, false);
}
/*
/*----------
* Given an OR subclause that has previously been determined to match
* the specified index, extract a list of specific opclauses that can be
* used as indexquals.
......@@ -406,10 +406,25 @@ match_or_subclause_to_indexkey(RelOptInfo *rel,
* given opclause. However, if the OR subclause is an AND, we have to
* scan it to find the opclause(s) that match the index. (There should
* be at least one, if match_or_subclause_to_indexkey succeeded, but there
* could be more.) Also, we apply expand_indexqual_conditions() to convert
* any special matching opclauses to indexable operators.
* could be more.)
*
* Also, we can look at other restriction clauses of the rel to discover
* additional candidate indexquals: for example, consider
* ... where (a = 11 or a = 12) and b = 42;
* If we are dealing with an index on (a,b) then we can include the clause
* b = 42 in the indexqual list generated for each of the OR subclauses.
* Essentially, we are making an index-specific transformation from CNF to
* DNF. (NOTE: when we do this, we end up with a slightly inefficient plan
* because create_indexscan_plan is not very bright about figuring out which
* restriction clauses are implied by the generated indexqual condition.
* Currently we'll end up rechecking both the OR clause and the transferred
* restriction clause as qpquals. FIXME someday.)
*
* Also, we apply expand_indexqual_conditions() to convert any special
* matching opclauses to indexable operators.
*
* The passed-in clause is not changed.
*----------
*/
List *
extract_or_indexqual_conditions(RelOptInfo *rel,
......@@ -417,54 +432,72 @@ extract_or_indexqual_conditions(RelOptInfo *rel,
Expr *orsubclause)
{
List *quals = NIL;
int *indexkeys = index->indexkeys;
Oid *classes = index->classlist;
if (and_clause((Node *) orsubclause))
/*
* Extract relevant indexclauses in indexkey order. This is essentially
* just like group_clauses_by_indexkey() except that the input and
* output are lists of bare clauses, not of RestrictInfo nodes.
*/
do
{
int curIndxKey = indexkeys[0];
Oid curClass = classes[0];
List *clausegroup = NIL;
List *item;
/*
* Extract relevant sub-subclauses in indexkey order. This is
* just like group_clauses_by_indexkey() except that the input and
* output are lists of bare clauses, not of RestrictInfo nodes.
*/
int *indexkeys = index->indexkeys;
Oid *classes = index->classlist;
if (and_clause((Node *) orsubclause))
{
foreach(item, orsubclause->args)
{
Expr *subsubclause = (Expr *) lfirst(item);
do
if (match_clause_to_indexkey(rel, index,
curIndxKey, curClass,
subsubclause, false))
clausegroup = lappend(clausegroup, subsubclause);
}
}
else if (match_clause_to_indexkey(rel, index,
curIndxKey, curClass,
orsubclause, false))
{
int curIndxKey = indexkeys[0];
Oid curClass = classes[0];
List *clausegroup = NIL;
List *item;
clausegroup = makeList1(orsubclause);
}
foreach(item, orsubclause->args)
/*
* If we found no clauses for this indexkey in the OR subclause
* itself, try looking in the rel's top-level restriction list.
*/
if (clausegroup == NIL)
{
foreach(item, rel->baserestrictinfo)
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
if (match_clause_to_indexkey(rel, index,
curIndxKey, curClass,
lfirst(item), false))
clausegroup = lappend(clausegroup, lfirst(item));
rinfo->clause, false))
clausegroup = lappend(clausegroup, rinfo->clause);
}
}
/*
* If no clauses match this key, we're done; we don't want to
* look at keys to its right.
*/
if (clausegroup == NIL)
break;
/*
* If still no clauses match this key, we're done; we don't want to
* look at keys to its right.
*/
if (clausegroup == NIL)
break;
quals = nconc(quals, clausegroup);
quals = nconc(quals, clausegroup);
indexkeys++;
classes++;
} while (!DoneMatchingIndexKeys(indexkeys, index));
indexkeys++;
classes++;
} while (!DoneMatchingIndexKeys(indexkeys, index));
if (quals == NIL)
elog(ERROR, "extract_or_indexqual_conditions: no matching clause");
}
else
{
/* we assume the caller passed a valid indexable qual */
quals = makeList1(orsubclause);
}
if (quals == NIL)
elog(ERROR, "extract_or_indexqual_conditions: no matching clause");
return expand_indexqual_conditions(quals);
}
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.43 2001/05/20 20:28:18 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.44 2001/06/05 17:13:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -38,20 +38,17 @@ static void best_or_subclause_index(Query *root, RelOptInfo *rel,
* create_index_paths() must already have been called.
*
* 'rel' is the relation entry for which the paths are to be created
* 'clauses' is the list of available restriction clause nodes
*
* Returns nothing, but adds paths to rel->pathlist via add_path().
*/
void
create_or_index_paths(Query *root,
RelOptInfo *rel,
List *clauses)
create_or_index_paths(Query *root, RelOptInfo *rel)
{
List *clist;
List *rlist;
foreach(clist, clauses)
foreach(rlist, rel->baserestrictinfo)
{
RestrictInfo *clausenode = (RestrictInfo *) lfirst(clist);
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(rlist);
/*
* Check to see if this clause is an 'or' clause, and, if so,
......@@ -59,13 +56,13 @@ create_or_index_paths(Query *root,
* has been matched by an index. The information used was saved
* by create_index_paths().
*/
if (restriction_is_or_clause(clausenode) &&
clausenode->subclauseindices)
if (restriction_is_or_clause(restrictinfo) &&
restrictinfo->subclauseindices)
{
bool all_indexable = true;
List *temp;
foreach(temp, clausenode->subclauseindices)
foreach(temp, restrictinfo->subclauseindices)
{
if (lfirst(temp) == NIL)
{
......@@ -75,7 +72,6 @@ create_or_index_paths(Query *root,
}
if (all_indexable)
{
/*
* OK, build an IndexPath for this OR clause, using the
* best available index for each subclause.
......@@ -93,10 +89,7 @@ create_or_index_paths(Query *root,
*/
pathnode->path.pathkeys = NIL;
/*
* We don't actually care what order the index scans in
* ...
*/
/* We don't actually care what order the index scans in. */
pathnode->indexscandir = NoMovementScanDirection;
/* This isn't a nestloop innerjoin, so: */
......@@ -106,8 +99,8 @@ create_or_index_paths(Query *root,
best_or_subclause_indices(root,
rel,
clausenode->clause->args,
clausenode->subclauseindices,
restrictinfo->clause->args,
restrictinfo->subclauseindices,
pathnode);
add_path(rel, (Path *) pathnode);
......
......@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: paths.h,v 1.53 2001/05/20 20:28:20 tgl Exp $
* $Id: paths.h,v 1.54 2001/06/05 17:13:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -47,8 +47,7 @@ extern List *expand_indexqual_conditions(List *indexquals);
* orindxpath.c
* additional routines for indexable OR clauses
*/
extern void create_or_index_paths(Query *root, RelOptInfo *rel,
List *clauses);
extern void create_or_index_paths(Query *root, RelOptInfo *rel);
/*
* tidpath.h
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment