Teach choose_bitmap_and() to actually be choosy --- that is, try to

make some estimate of which available indexes to AND together, rather
than blindly taking 'em all.  This could probably stand further
improvement, but it seems to do OK in simple tests.
This commit is contained in:
Tom Lane 2005-04-23 01:57:34 +00:00
parent 4b89126ccc
commit e092828241
1 changed files with 132 additions and 5 deletions

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.176 2005/04/22 21:58:31 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.177 2005/04/23 01:57:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -63,6 +63,8 @@ static List *generate_bitmap_or_paths(Query *root, RelOptInfo *rel,
bool isjoininner,
Relids outer_relids);
static Path *choose_bitmap_and(Query *root, RelOptInfo *rel, List *paths);
static int bitmap_path_comparator(const void *a, const void *b);
static Cost bitmap_and_cost_est(Query *root, RelOptInfo *rel, List *paths);
static bool match_clause_to_indexcol(IndexOptInfo *index,
int indexcol, Oid opclass,
RestrictInfo *rinfo,
@ -476,15 +478,140 @@ generate_bitmap_or_paths(Query *root, RelOptInfo *rel,
static Path *
choose_bitmap_and(Query *root, RelOptInfo *rel, List *paths)
{
Assert(paths != NIL); /* else caller error */
if (list_length(paths) == 1)
return (Path *) linitial(paths); /* easy case */
int npaths = list_length(paths);
Path **patharray;
Cost costsofar;
List *qualsofar;
ListCell *lastcell;
int i;
ListCell *l;
Assert(npaths > 0); /* else caller error */
if (npaths == 1)
return (Path *) linitial(paths); /* easy case */
/*
* XXX temporary stopgap: always use all available paths
* In theory we should consider every nonempty subset of the given paths.
* In practice that seems like overkill, given the crude nature of the
* estimates, not to mention the possible effects of higher-level AND and
* OR clauses. As a compromise, we sort the paths by selectivity.
* We always take the first, and sequentially add on paths that result
* in a lower estimated cost.
*
* We also make some effort to detect directly redundant input paths,
* as can happen if there are multiple possibly usable indexes. For
* this we look only at plain IndexPath inputs, not at sub-OR clauses.
* And we consider an index redundant if all its index conditions were
* already used by earlier indexes. (We could use pred_test() to have
* a more intelligent, but much more expensive, check --- but in most
* cases simple equality should suffice, since after all the index
* conditions are all coming from the same query clauses.)
*/
/* Convert list to array so we can apply qsort */
patharray = (Path **) palloc(npaths * sizeof(Path *));
i = 0;
foreach(l, paths)
{
patharray[i++] = (Path *) lfirst(l);
}
qsort(patharray, npaths, sizeof(Path *), bitmap_path_comparator);
paths = list_make1(patharray[0]);
costsofar = bitmap_and_cost_est(root, rel, paths);
if (IsA(patharray[0], IndexPath))
{
Assert(list_length(((IndexPath *) patharray[0])->indexclauses) == 1);
qualsofar = (List *) linitial(((IndexPath *) patharray[0])->indexclauses);
qualsofar = list_copy(qualsofar);
}
else
qualsofar = NIL;
lastcell = list_head(paths); /* for quick deletions */
for (i = 1; i < npaths; i++)
{
Path *newpath = patharray[i];
List *newqual = NIL;
Cost newcost;
if (IsA(newpath, IndexPath))
{
Assert(list_length(((IndexPath *) newpath)->indexclauses) == 1);
newqual = (List *) linitial(((IndexPath *) newpath)->indexclauses);
if (list_difference(newqual, qualsofar) == NIL)
continue; /* redundant */
}
paths = lappend(paths, newpath);
newcost = bitmap_and_cost_est(root, rel, paths);
if (newcost < costsofar)
{
costsofar = newcost;
if (newqual)
qualsofar = list_concat(qualsofar, list_copy(newqual));
lastcell = lnext(lastcell);
}
else
{
paths = list_delete_cell(paths, lnext(lastcell), lastcell);
}
Assert(lnext(lastcell) == NULL);
}
if (list_length(paths) == 1)
return (Path *) linitial(paths); /* no need for AND */
return (Path *) create_bitmap_and_path(root, rel, paths);
}
/* qsort comparator to sort in increasing selectivity order */
static int
bitmap_path_comparator(const void *a, const void *b)
{
Path *pa = *(Path * const *) a;
Path *pb = *(Path * const *) b;
Cost acost;
Cost bcost;
Selectivity aselec;
Selectivity bselec;
cost_bitmap_tree_node(pa, &acost, &aselec);
cost_bitmap_tree_node(pb, &bcost, &bselec);
if (aselec < bselec)
return -1;
if (aselec > bselec)
return 1;
/* if identical selectivity, sort by cost */
if (acost < bcost)
return -1;
if (acost > bcost)
return 1;
return 0;
}
/*
* Estimate the cost of actually executing a BitmapAnd with the given
* inputs.
*/
static Cost
bitmap_and_cost_est(Query *root, RelOptInfo *rel, List *paths)
{
BitmapAndPath apath;
Path bpath;
/* Set up a dummy BitmapAndPath */
apath.path.type = T_BitmapAndPath;
apath.path.parent = rel;
apath.bitmapquals = paths;
cost_bitmap_and_node(&apath, root);
/* Now we can do cost_bitmap_heap_scan */
cost_bitmap_heap_scan(&bpath, root, rel, (Path *) &apath, false);
return bpath.total_cost;
}
/****************************************************************************
* ---- ROUTINES TO CHECK RESTRICTIONS ----