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 ...
This commit is contained in:
parent
7c579fa12d
commit
cdd230d628
src
@ -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;
|
||||
|
||||
do
|
||||
if (and_clause((Node *) orsubclause))
|
||||
{
|
||||
int curIndxKey = indexkeys[0];
|
||||
Oid curClass = classes[0];
|
||||
List *clausegroup = NIL;
|
||||
List *item;
|
||||
|
||||
foreach(item, orsubclause->args)
|
||||
{
|
||||
Expr *subsubclause = (Expr *) lfirst(item);
|
||||
|
||||
if (match_clause_to_indexkey(rel, index,
|
||||
curIndxKey, curClass,
|
||||
lfirst(item), false))
|
||||
clausegroup = lappend(clausegroup, lfirst(item));
|
||||
subsubclause, false))
|
||||
clausegroup = lappend(clausegroup, subsubclause);
|
||||
}
|
||||
}
|
||||
else if (match_clause_to_indexkey(rel, index,
|
||||
curIndxKey, curClass,
|
||||
orsubclause, false))
|
||||
{
|
||||
clausegroup = makeList1(orsubclause);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 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);
|
||||
|
||||
quals = nconc(quals, clausegroup);
|
||||
if (match_clause_to_indexkey(rel, index,
|
||||
curIndxKey, curClass,
|
||||
rinfo->clause, false))
|
||||
clausegroup = lappend(clausegroup, rinfo->clause);
|
||||
}
|
||||
}
|
||||
|
||||
indexkeys++;
|
||||
classes++;
|
||||
} while (!DoneMatchingIndexKeys(indexkeys, index));
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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);
|
||||
}
|
||||
quals = nconc(quals, clausegroup);
|
||||
|
||||
indexkeys++;
|
||||
classes++;
|
||||
} while (!DoneMatchingIndexKeys(indexkeys, index));
|
||||
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user