mirror of
https://github.com/postgres/postgres.git
synced 2025-04-24 10:47:04 +03:00
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
@ -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)
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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,
|
|||||||
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,
|
|||||||
* 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,
|
|||||||
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
|
|
||||||
* output are lists of bare clauses, not of RestrictInfo nodes.
|
|
||||||
*/
|
|
||||||
int *indexkeys = index->indexkeys;
|
|
||||||
Oid *classes = index->classlist;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
int curIndxKey = indexkeys[0];
|
|
||||||
Oid curClass = classes[0];
|
|
||||||
List *clausegroup = NIL;
|
|
||||||
List *item;
|
|
||||||
|
|
||||||
foreach(item, orsubclause->args)
|
foreach(item, orsubclause->args)
|
||||||
{
|
{
|
||||||
|
Expr *subsubclause = (Expr *) lfirst(item);
|
||||||
|
|
||||||
if (match_clause_to_indexkey(rel, index,
|
if (match_clause_to_indexkey(rel, index,
|
||||||
curIndxKey, curClass,
|
curIndxKey, curClass,
|
||||||
lfirst(item), false))
|
subsubclause, false))
|
||||||
clausegroup = lappend(clausegroup, lfirst(item));
|
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
|
* If we found no clauses for this indexkey in the OR subclause
|
||||||
* look at keys to its right.
|
* itself, try looking in the rel's top-level restriction list.
|
||||||
*/
|
*/
|
||||||
if (clausegroup == NIL)
|
if (clausegroup == NIL)
|
||||||
break;
|
{
|
||||||
|
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++;
|
* If still no clauses match this key, we're done; we don't want to
|
||||||
} while (!DoneMatchingIndexKeys(indexkeys, index));
|
* look at keys to its right.
|
||||||
|
*/
|
||||||
|
if (clausegroup == NIL)
|
||||||
|
break;
|
||||||
|
|
||||||
if (quals == NIL)
|
quals = nconc(quals, clausegroup);
|
||||||
elog(ERROR, "extract_or_indexqual_conditions: no matching clause");
|
|
||||||
}
|
indexkeys++;
|
||||||
else
|
classes++;
|
||||||
{
|
} while (!DoneMatchingIndexKeys(indexkeys, index));
|
||||||
/* 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);
|
return expand_indexqual_conditions(quals);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
|||||||
* 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,
|
|||||||
* 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,
|
|||||||
}
|
}
|
||||||
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,
|
|||||||
*/
|
*/
|
||||||
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,
|
|||||||
|
|
||||||
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 @@
|
|||||||
* 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);
|
|||||||
* 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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user