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 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -232,7 +232,7 @@ set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte)
create_index_paths(root, rel); create_index_paths(root, rel);
/* create_index_paths must be done before create_or_index_paths */ /* 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 */ /* Now find the cheapest of the paths for this rel */
set_cheapest(rel); set_cheapest(rel);
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -397,7 +397,7 @@ match_or_subclause_to_indexkey(RelOptInfo *rel,
clause, false); clause, false);
} }
/* /*----------
* Given an OR subclause that has previously been determined to match * Given an OR subclause that has previously been determined to match
* the specified index, extract a list of specific opclauses that can be * the specified index, extract a list of specific opclauses that can be
* used as indexquals. * used as indexquals.
...@@ -406,10 +406,25 @@ match_or_subclause_to_indexkey(RelOptInfo *rel, ...@@ -406,10 +406,25 @@ match_or_subclause_to_indexkey(RelOptInfo *rel,
* given opclause. However, if the OR subclause is an AND, we have to * 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 * 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 * be at least one, if match_or_subclause_to_indexkey succeeded, but there
* could be more.) Also, we apply expand_indexqual_conditions() to convert * could be more.)
* any special matching opclauses to indexable operators. *
* 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. * The passed-in clause is not changed.
*----------
*/ */
List * List *
extract_or_indexqual_conditions(RelOptInfo *rel, extract_or_indexqual_conditions(RelOptInfo *rel,
...@@ -417,54 +432,72 @@ extract_or_indexqual_conditions(RelOptInfo *rel, ...@@ -417,54 +432,72 @@ extract_or_indexqual_conditions(RelOptInfo *rel,
Expr *orsubclause) Expr *orsubclause)
{ {
List *quals = NIL; 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;
/* if (and_clause((Node *) orsubclause))
* Extract relevant sub-subclauses in indexkey order. This is {
* just like group_clauses_by_indexkey() except that the input and foreach(item, orsubclause->args)
* output are lists of bare clauses, not of RestrictInfo nodes. {
*/ Expr *subsubclause = (Expr *) lfirst(item);
int *indexkeys = index->indexkeys;
Oid *classes = index->classlist;
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]; clausegroup = makeList1(orsubclause);
Oid curClass = classes[0]; }
List *clausegroup = NIL;
List *item;
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, if (match_clause_to_indexkey(rel, index,
curIndxKey, curClass, curIndxKey, curClass,
lfirst(item), false)) rinfo->clause, false))
clausegroup = lappend(clausegroup, lfirst(item)); clausegroup = lappend(clausegroup, rinfo->clause);
} }
}
/* /*
* If no clauses match this key, we're done; we don't want to * If still no clauses match this key, we're done; we don't want to
* look at keys to its right. * look at keys to its right.
*/ */
if (clausegroup == NIL) if (clausegroup == NIL)
break; break;
quals = nconc(quals, clausegroup); quals = nconc(quals, clausegroup);
indexkeys++; indexkeys++;
classes++; classes++;
} while (!DoneMatchingIndexKeys(indexkeys, index)); } while (!DoneMatchingIndexKeys(indexkeys, index));
if (quals == NIL) if (quals == NIL)
elog(ERROR, "extract_or_indexqual_conditions: no matching clause"); elog(ERROR, "extract_or_indexqual_conditions: no matching clause");
}
else
{
/* we assume the caller passed a valid indexable qual */
quals = makeList1(orsubclause);
}
return expand_indexqual_conditions(quals); return expand_indexqual_conditions(quals);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -38,20 +38,17 @@ static void best_or_subclause_index(Query *root, RelOptInfo *rel,
* create_index_paths() must already have been called. * create_index_paths() must already have been called.
* *
* 'rel' is the relation entry for which the paths are to be created * '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(). * Returns nothing, but adds paths to rel->pathlist via add_path().
*/ */
void void
create_or_index_paths(Query *root, create_or_index_paths(Query *root, RelOptInfo *rel)
RelOptInfo *rel,
List *clauses)
{ {
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, * Check to see if this clause is an 'or' clause, and, if so,
...@@ -59,13 +56,13 @@ create_or_index_paths(Query *root, ...@@ -59,13 +56,13 @@ create_or_index_paths(Query *root,
* has been matched by an index. The information used was saved * has been matched by an index. The information used was saved
* by create_index_paths(). * by create_index_paths().
*/ */
if (restriction_is_or_clause(clausenode) && if (restriction_is_or_clause(restrictinfo) &&
clausenode->subclauseindices) restrictinfo->subclauseindices)
{ {
bool all_indexable = true; bool all_indexable = true;
List *temp; List *temp;
foreach(temp, clausenode->subclauseindices) foreach(temp, restrictinfo->subclauseindices)
{ {
if (lfirst(temp) == NIL) if (lfirst(temp) == NIL)
{ {
...@@ -75,7 +72,6 @@ create_or_index_paths(Query *root, ...@@ -75,7 +72,6 @@ create_or_index_paths(Query *root,
} }
if (all_indexable) if (all_indexable)
{ {
/* /*
* OK, build an IndexPath for this OR clause, using the * OK, build an IndexPath for this OR clause, using the
* best available index for each subclause. * best available index for each subclause.
...@@ -93,10 +89,7 @@ create_or_index_paths(Query *root, ...@@ -93,10 +89,7 @@ create_or_index_paths(Query *root,
*/ */
pathnode->path.pathkeys = NIL; 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; pathnode->indexscandir = NoMovementScanDirection;
/* This isn't a nestloop innerjoin, so: */ /* This isn't a nestloop innerjoin, so: */
...@@ -106,8 +99,8 @@ create_or_index_paths(Query *root, ...@@ -106,8 +99,8 @@ create_or_index_paths(Query *root,
best_or_subclause_indices(root, best_or_subclause_indices(root,
rel, rel,
clausenode->clause->args, restrictinfo->clause->args,
clausenode->subclauseindices, restrictinfo->subclauseindices,
pathnode); pathnode);
add_path(rel, (Path *) pathnode); add_path(rel, (Path *) pathnode);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -47,8 +47,7 @@ extern List *expand_indexqual_conditions(List *indexquals);
* orindxpath.c * orindxpath.c
* additional routines for indexable OR clauses * additional routines for indexable OR clauses
*/ */
extern void create_or_index_paths(Query *root, RelOptInfo *rel, extern void create_or_index_paths(Query *root, RelOptInfo *rel);
List *clauses);
/* /*
* tidpath.h * 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