First cut at planner support for bitmap index scans. Lots to do yet,

but the code is basically working.  Along the way, rewrite the entire
approach to processing OR index conditions, and make it work in join
cases for the first time ever.  orindxpath.c is now basically obsolete,
but I left it in for the time being to allow easy comparison testing
against the old implementation.
This commit is contained in:
Tom Lane 2005-04-22 21:58:32 +00:00
parent ccbb07d922
commit bc843d3960
22 changed files with 1044 additions and 615 deletions

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.133 2005/04/19 22:35:10 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.134 2005/04/22 21:58:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -847,9 +847,14 @@ explain_outNode(StringInfo str,
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
/*
* Ordinarily we don't pass down our own outer_plan value to our
* child nodes, but in bitmap scan trees we must, since the bottom
* BitmapIndexScan nodes may have outer references.
*/
explain_outNode(str, outerPlan(plan),
outerPlanState(planstate),
NULL,
IsA(plan, BitmapHeapScan) ? outer_plan : NULL,
indent + 3, es);
}
@ -907,7 +912,7 @@ explain_outNode(StringInfo str,
explain_outNode(str, subnode,
bitmapandstate->bitmapplans[j],
NULL,
outer_plan, /* pass down same outer plan */
indent + 3, es);
j++;
}
@ -931,7 +936,7 @@ explain_outNode(StringInfo str,
explain_outNode(str, subnode,
bitmaporstate->bitmapplans[j],
NULL,
outer_plan, /* pass down same outer plan */
indent + 3, es);
j++;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.2 2005/04/20 15:48:36 tgl Exp $
* $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.3 2005/04/22 21:58:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -492,7 +492,8 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
indexstate->biss_RuntimeKeyInfo = NULL;
indexstate->biss_RuntimeContext = NULL;
/* Get rid of the speculatively-allocated flag array, too */
pfree(runtimeKeyInfo);
if (runtimeKeyInfo)
pfree(runtimeKeyInfo);
}
/*

View File

@ -49,7 +49,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.144 2005/04/21 19:18:12 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.145 2005/04/22 21:58:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -104,7 +104,6 @@ bool enable_hashjoin = true;
static bool cost_qual_eval_walker(Node *node, QualCost *total);
static void cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec);
static Selectivity approx_selectivity(Query *root, List *quals,
JoinType jointype);
static Selectivity join_in_selectivity(JoinPath *path, Query *root);
@ -474,8 +473,11 @@ cost_bitmap_heap_scan(Path *path, Query *root, RelOptInfo *baserel,
* For lack of a better idea, interpolate like this to determine the
* cost per page.
*/
cost_per_page = random_page_cost -
(random_page_cost - 1.0) * sqrt(pages_fetched / T);
if (pages_fetched >= 2.0)
cost_per_page = random_page_cost -
(random_page_cost - 1.0) * sqrt(pages_fetched / T);
else
cost_per_page = random_page_cost;
run_cost += pages_fetched * cost_per_page;
@ -500,7 +502,7 @@ cost_bitmap_heap_scan(Path *path, Query *root, RelOptInfo *baserel,
* cost_bitmap_tree_node
* Extract cost and selectivity from a bitmap tree node (index/and/or)
*/
static void
void
cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec)
{
if (IsA(path, IndexPath))

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.182 2005/04/21 19:18:12 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.183 2005/04/22 21:58:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -870,6 +870,9 @@ create_bitmap_scan_plan(Query *root,
/* Also extract the true index conditions */
indexquals = create_bitmap_indxqual(best_path->bitmapqual);
/* Reduce RestrictInfo list to bare expressions */
scan_clauses = get_actual_clauses(scan_clauses);
/*
* If this is a innerjoin scan, the indexclauses will contain join
* clauses that are not present in scan_clauses (since the passed-in
@ -881,16 +884,9 @@ create_bitmap_scan_plan(Query *root,
*/
if (best_path->isjoininner)
{
/*
* Pointer comparison should be enough to determine RestrictInfo
* matches.
*/
scan_clauses = list_union_ptr(scan_clauses, bitmapqualorig);
scan_clauses = list_union(scan_clauses, bitmapqualorig);
}
/* Reduce RestrictInfo list to bare expressions */
scan_clauses = get_actual_clauses(scan_clauses);
/*
* The qpqual list must contain all restrictions not automatically
* handled by the index. All the predicates in the indexquals will be
@ -1322,7 +1318,38 @@ create_nestloop_plan(Query *root,
select_nonredundant_join_clauses(root,
joinrestrictclauses,
linitial(indexclauses),
best_path->jointype);
IS_OUTER_JOIN(best_path->jointype));
}
}
else if (IsA(best_path->innerjoinpath, BitmapHeapPath))
{
/*
* Same deal for bitmapped index scans.
*/
BitmapHeapPath *innerpath = (BitmapHeapPath *) best_path->innerjoinpath;
if (innerpath->isjoininner)
{
List *bitmapquals;
List *bitmapclauses;
ListCell *l;
bitmapquals = create_bitmap_qual(innerpath->bitmapqual);
/* must convert qual list to restrictinfos ... painful ... */
bitmapclauses = NIL;
foreach(l, bitmapquals)
{
bitmapclauses = lappend(bitmapclauses,
make_restrictinfo((Expr *) lfirst(l),
true, true));
}
joinrestrictclauses =
select_nonredundant_join_clauses(root,
joinrestrictclauses,
bitmapclauses,
IS_OUTER_JOIN(best_path->jointype));
}
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.3 2005/04/12 05:11:28 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.4 2005/04/22 21:58:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -343,7 +343,10 @@ build_minmax_path(Query *root, RelOptInfo *rel, MinMaxAggInfo *info)
* to build the path, it's convenient to extract that first and then
* look through it for the equality restrictions.
*/
restrictclauses = group_clauses_by_indexkey(index);
restrictclauses = group_clauses_by_indexkey(index,
index->rel->baserestrictinfo,
NIL,
NULL);
if (list_length(restrictclauses) < indexcol)
continue; /* definitely haven't got enough */
@ -376,7 +379,8 @@ build_minmax_path(Query *root, RelOptInfo *rel, MinMaxAggInfo *info)
new_path = create_index_path(root, index,
restrictclauses,
NIL,
indexscandir);
indexscandir,
false);
/*
* Estimate actual cost of fetching just one row.

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.107 2005/04/19 22:35:16 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.108 2005/04/22 21:58:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -44,6 +44,10 @@ typedef struct
static void fix_expr_references(Plan *plan, Node *node);
static bool fix_expr_references_walker(Node *node, void *context);
static void set_join_references(Join *join, List *rtable);
static void set_inner_join_references(Plan *inner_plan,
List *rtable,
List *outer_tlist,
bool tlists_have_non_vars);
static void set_uppernode_references(Plan *plan, Index subvarno);
static bool targetlist_has_non_vars(List *tlist);
static List *join_references(List *clauses,
@ -325,7 +329,7 @@ fix_expr_references_walker(Node *node, void *context)
*
* In the case of a nestloop with inner indexscan, we will also need to
* apply the same transformation to any outer vars appearing in the
* quals of the child indexscan.
* quals of the child indexscan. set_inner_join_references does that.
*
* 'join' is a join plan node
* 'rtable' is the associated range table
@ -365,62 +369,11 @@ set_join_references(Join *join, List *rtable)
/* Now do join-type-specific stuff */
if (IsA(join, NestLoop))
{
if (IsA(inner_plan, IndexScan))
{
/*
* An index is being used to reduce the number of tuples
* scanned in the inner relation. If there are join clauses
* being used with the index, we must update their outer-rel
* var nodes to refer to the outer side of the join.
*/
IndexScan *innerscan = (IndexScan *) inner_plan;
List *indxqualorig = innerscan->indxqualorig;
/* No work needed if indxqual refers only to its own rel... */
if (NumRelids((Node *) indxqualorig) > 1)
{
Index innerrel = innerscan->scan.scanrelid;
/* only refs to outer vars get changed in the inner qual */
innerscan->indxqualorig = join_references(indxqualorig,
rtable,
outer_tlist,
NIL,
innerrel,
tlists_have_non_vars);
innerscan->indxqual = join_references(innerscan->indxqual,
rtable,
outer_tlist,
NIL,
innerrel,
tlists_have_non_vars);
/*
* We must fix the inner qpqual too, if it has join
* clauses (this could happen if special operators are
* involved: some indxquals may get rechecked as qpquals).
*/
if (NumRelids((Node *) inner_plan->qual) > 1)
inner_plan->qual = join_references(inner_plan->qual,
rtable,
outer_tlist,
NIL,
innerrel,
tlists_have_non_vars);
}
}
else if (IsA(inner_plan, TidScan))
{
TidScan *innerscan = (TidScan *) inner_plan;
Index innerrel = innerscan->scan.scanrelid;
innerscan->tideval = join_references(innerscan->tideval,
rtable,
outer_tlist,
NIL,
innerrel,
tlists_have_non_vars);
}
/* This processing is split out to handle possible recursion */
set_inner_join_references(inner_plan,
rtable,
outer_tlist,
tlists_have_non_vars);
}
else if (IsA(join, MergeJoin))
{
@ -446,6 +399,178 @@ set_join_references(Join *join, List *rtable)
}
}
/*
* set_inner_join_references
* Handle join references appearing in an inner indexscan's quals
*
* To handle bitmap-scan plan trees, we have to be able to recurse down
* to the bottom BitmapIndexScan nodes, so this is split out as a separate
* function.
*/
static void
set_inner_join_references(Plan *inner_plan,
List *rtable,
List *outer_tlist,
bool tlists_have_non_vars)
{
if (IsA(inner_plan, IndexScan))
{
/*
* An index is being used to reduce the number of tuples
* scanned in the inner relation. If there are join clauses
* being used with the index, we must update their outer-rel
* var nodes to refer to the outer side of the join.
*/
IndexScan *innerscan = (IndexScan *) inner_plan;
List *indxqualorig = innerscan->indxqualorig;
/* No work needed if indxqual refers only to its own rel... */
if (NumRelids((Node *) indxqualorig) > 1)
{
Index innerrel = innerscan->scan.scanrelid;
/* only refs to outer vars get changed in the inner qual */
innerscan->indxqualorig = join_references(indxqualorig,
rtable,
outer_tlist,
NIL,
innerrel,
tlists_have_non_vars);
innerscan->indxqual = join_references(innerscan->indxqual,
rtable,
outer_tlist,
NIL,
innerrel,
tlists_have_non_vars);
/*
* We must fix the inner qpqual too, if it has join
* clauses (this could happen if special operators are
* involved: some indxquals may get rechecked as qpquals).
*/
if (NumRelids((Node *) inner_plan->qual) > 1)
inner_plan->qual = join_references(inner_plan->qual,
rtable,
outer_tlist,
NIL,
innerrel,
tlists_have_non_vars);
}
}
else if (IsA(inner_plan, BitmapIndexScan))
{
/*
* Same, but index is being used within a bitmap plan.
*/
BitmapIndexScan *innerscan = (BitmapIndexScan *) inner_plan;
List *indxqualorig = innerscan->indxqualorig;
/* No work needed if indxqual refers only to its own rel... */
if (NumRelids((Node *) indxqualorig) > 1)
{
Index innerrel = innerscan->scan.scanrelid;
/* only refs to outer vars get changed in the inner qual */
innerscan->indxqualorig = join_references(indxqualorig,
rtable,
outer_tlist,
NIL,
innerrel,
tlists_have_non_vars);
innerscan->indxqual = join_references(innerscan->indxqual,
rtable,
outer_tlist,
NIL,
innerrel,
tlists_have_non_vars);
/* no need to fix inner qpqual */
Assert(inner_plan->qual == NIL);
}
}
else if (IsA(inner_plan, BitmapHeapScan))
{
/*
* The inner side is a bitmap scan plan. Fix the top node,
* and recurse to get the lower nodes.
*/
BitmapHeapScan *innerscan = (BitmapHeapScan *) inner_plan;
List *bitmapqualorig = innerscan->bitmapqualorig;
/* No work needed if bitmapqual refers only to its own rel... */
if (NumRelids((Node *) bitmapqualorig) > 1)
{
Index innerrel = innerscan->scan.scanrelid;
/* only refs to outer vars get changed in the inner qual */
innerscan->bitmapqualorig = join_references(bitmapqualorig,
rtable,
outer_tlist,
NIL,
innerrel,
tlists_have_non_vars);
/*
* We must fix the inner qpqual too, if it has join
* clauses (this could happen if special operators are
* involved: some indxquals may get rechecked as qpquals).
*/
if (NumRelids((Node *) inner_plan->qual) > 1)
inner_plan->qual = join_references(inner_plan->qual,
rtable,
outer_tlist,
NIL,
innerrel,
tlists_have_non_vars);
/* Now recurse */
set_inner_join_references(inner_plan->lefttree,
rtable,
outer_tlist,
tlists_have_non_vars);
}
}
else if (IsA(inner_plan, BitmapAnd))
{
/* All we need do here is recurse */
BitmapAnd *innerscan = (BitmapAnd *) inner_plan;
ListCell *l;
foreach(l, innerscan->bitmapplans)
{
set_inner_join_references((Plan *) lfirst(l),
rtable,
outer_tlist,
tlists_have_non_vars);
}
}
else if (IsA(inner_plan, BitmapOr))
{
/* All we need do here is recurse */
BitmapOr *innerscan = (BitmapOr *) inner_plan;
ListCell *l;
foreach(l, innerscan->bitmapplans)
{
set_inner_join_references((Plan *) lfirst(l),
rtable,
outer_tlist,
tlists_have_non_vars);
}
}
else if (IsA(inner_plan, TidScan))
{
TidScan *innerscan = (TidScan *) inner_plan;
Index innerrel = innerscan->scan.scanrelid;
innerscan->tideval = join_references(innerscan->tideval,
rtable,
outer_tlist,
NIL,
innerrel,
tlists_have_non_vars);
}
}
/*
* set_uppernode_references
* Update the targetlist and quals of an upper-level plan node

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.118 2005/04/21 19:18:12 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.119 2005/04/22 21:58:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -260,6 +260,9 @@ set_cheapest(RelOptInfo *parent_rel)
* but just recycling discarded Path nodes is a very useful savings in
* a large join tree. We can recycle the List nodes of pathlist, too.
*
* BUT: we do not pfree IndexPath objects, since they may be referenced as
* children of BitmapHeapPaths as well as being paths in their own right.
*
* 'parent_rel' is the relation entry to which the path corresponds.
* 'new_path' is a potential path for parent_rel.
*
@ -349,8 +352,12 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
{
parent_rel->pathlist = list_delete_cell(parent_rel->pathlist,
p1, p1_prev);
/* Delete the data pointed-to by the deleted cell */
pfree(old_path);
/*
* Delete the data pointed-to by the deleted cell, if possible
*/
if (!IsA(old_path, IndexPath))
pfree(old_path);
/* Advance list pointer */
if (p1_prev)
p1 = lnext(p1_prev);
else
@ -361,6 +368,7 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
/* new belongs after this old path if it has cost >= old's */
if (costcmp >= 0)
insert_after = p1;
/* Advance list pointers */
p1_prev = p1;
p1 = lnext(p1);
}
@ -385,7 +393,8 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
else
{
/* Reject and recycle the new path */
pfree(new_path);
if (!IsA(new_path, IndexPath))
pfree(new_path);
}
}
@ -418,55 +427,102 @@ create_seqscan_path(Query *root, RelOptInfo *rel)
* Creates a path node for an index scan.
*
* 'index' is a usable index.
* 'restriction_clauses' is a list of lists of RestrictInfo nodes
* 'clause_groups' is a list of lists of RestrictInfo nodes
* to be used as index qual conditions in the scan.
* 'pathkeys' describes the ordering of the path.
* 'indexscandir' is ForwardScanDirection or BackwardScanDirection
* for an ordered index, or NoMovementScanDirection for
* an unordered index.
* 'isjoininner' is TRUE if this is a join inner indexscan path.
* (pathkeys and indexscandir are ignored if so.)
*
* Returns the new path node.
*/
IndexPath *
create_index_path(Query *root,
IndexOptInfo *index,
List *restriction_clauses,
List *clause_groups,
List *pathkeys,
ScanDirection indexscandir)
ScanDirection indexscandir,
bool isjoininner)
{
IndexPath *pathnode = makeNode(IndexPath);
List *indexquals;
RelOptInfo *rel = index->rel;
List *indexquals,
*allclauses;
/*
* For a join inner scan, there's no point in marking the path with any
* pathkeys, since it will only ever be used as the inner path of a
* nestloop, and so its ordering does not matter. For the same reason
* we don't really care what order it's scanned in. (We could expect
* the caller to supply the correct values, but it's easier to force
* it here.)
*/
if (isjoininner)
{
pathkeys = NIL;
indexscandir = NoMovementScanDirection;
}
pathnode->path.pathtype = T_IndexScan;
pathnode->path.parent = index->rel;
pathnode->path.parent = rel;
pathnode->path.pathkeys = pathkeys;
/* Convert clauses to indexquals the executor can handle */
indexquals = expand_indexqual_conditions(index, restriction_clauses);
indexquals = expand_indexqual_conditions(index, clause_groups);
/* Flatten the clause-groups list to produce indexclauses list */
restriction_clauses = flatten_clausegroups_list(restriction_clauses);
allclauses = flatten_clausegroups_list(clause_groups);
/*
* We are making a pathnode for a single-scan indexscan; therefore,
* indexinfo etc should be single-element lists.
*/
pathnode->indexinfo = list_make1(index);
pathnode->indexclauses = list_make1(restriction_clauses);
pathnode->indexclauses = list_make1(allclauses);
pathnode->indexquals = list_make1(indexquals);
/* It's not an innerjoin path. */
pathnode->isjoininner = false;
pathnode->isjoininner = isjoininner;
pathnode->indexscandir = indexscandir;
/*
* The number of rows is the same as the parent rel's estimate, since
* this isn't a join inner indexscan.
*/
pathnode->rows = index->rel->rows;
if (isjoininner)
{
/*
* We must compute the estimated number of output rows for the
* indexscan. This is less than rel->rows because of the additional
* selectivity of the join clauses. Since clause_groups may
* contain both restriction and join clauses, we have to do a set
* union to get the full set of clauses that must be considered to
* compute the correct selectivity. (Without the union operation,
* we might have some restriction clauses appearing twice, which'd
* mislead clauselist_selectivity into double-counting their
* selectivity. However, since RestrictInfo nodes aren't copied when
* linking them into different lists, it should be sufficient to use
* pointer comparison to remove duplicates.)
*
* Always assume the join type is JOIN_INNER; even if some of the join
* clauses come from other contexts, that's not our problem.
*/
allclauses = list_union_ptr(rel->baserestrictinfo, allclauses);
pathnode->rows = rel->tuples *
clauselist_selectivity(root,
allclauses,
rel->relid, /* do not use 0! */
JOIN_INNER);
/* Like costsize.c, force estimate to be at least one row */
pathnode->rows = clamp_row_est(pathnode->rows);
}
else
{
/*
* The number of rows is the same as the parent rel's estimate,
* since this isn't a join inner indexscan.
*/
pathnode->rows = rel->rows;
}
cost_index(pathnode, root, index, indexquals, false);
cost_index(pathnode, root, index, indexquals, isjoininner);
return pathnode;
}
@ -480,7 +536,8 @@ create_index_path(Query *root,
BitmapHeapPath *
create_bitmap_heap_path(Query *root,
RelOptInfo *rel,
Path *bitmapqual)
Path *bitmapqual,
bool isjoininner)
{
BitmapHeapPath *pathnode = makeNode(BitmapHeapPath);
@ -489,15 +546,36 @@ create_bitmap_heap_path(Query *root,
pathnode->path.pathkeys = NIL; /* always unordered */
pathnode->bitmapqual = bitmapqual;
pathnode->isjoininner = isjoininner;
/* It's not an innerjoin path. */
pathnode->isjoininner = false;
if (isjoininner)
{
/*
* We must compute the estimated number of output rows for the
* indexscan. This is less than rel->rows because of the additional
* selectivity of the join clauses. We make use of the selectivity
* estimated for the bitmap to do this; this isn't really quite
* right since there may be restriction conditions not included
* in the bitmap ...
*/
Cost indexTotalCost;
Selectivity indexSelectivity;
/*
* The number of rows is the same as the parent rel's estimate, since
* this isn't a join inner indexscan.
*/
pathnode->rows = rel->rows;
cost_bitmap_tree_node(bitmapqual, &indexTotalCost, &indexSelectivity);
pathnode->rows = rel->tuples * indexSelectivity;
if (pathnode->rows > rel->rows)
pathnode->rows = rel->rows;
/* Like costsize.c, force estimate to be at least one row */
pathnode->rows = clamp_row_est(pathnode->rows);
}
else
{
/*
* The number of rows is the same as the parent rel's estimate,
* since this isn't a join inner indexscan.
*/
pathnode->rows = rel->rows;
}
cost_bitmap_heap_scan(&pathnode->path, root, rel, bitmapqual, false);

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.105 2005/04/14 20:03:24 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.106 2005/04/22 21:58:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -194,10 +194,6 @@ get_relation_info(Oid relationObjectId, RelOptInfo *rel)
info->tuples = rel->tuples;
}
/* initialize cached join info to empty */
info->outer_relids = NULL;
info->inner_paths = NIL;
index_close(indexRelation);
indexinfos = lcons(info, indexinfos);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.64 2004/12/31 22:00:23 pgsql Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.65 2005/04/22 21:58:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -461,7 +461,8 @@ build_joinrel_restrictlist(Query *root,
* previous clauses (see optimizer/README for discussion). We detect
* that case and omit the redundant clause from the result list.
*/
result = remove_redundant_join_clauses(root, rlist, jointype);
result = remove_redundant_join_clauses(root, rlist,
IS_OUTER_JOIN(jointype));
list_free(rlist);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.32 2005/03/28 00:58:24 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.33 2005/04/22 21:58:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -31,7 +31,7 @@ static Expr *make_sub_restrictinfos(Expr *clause,
static RestrictInfo *join_clause_is_redundant(Query *root,
RestrictInfo *rinfo,
List *reference_list,
JoinType jointype);
bool isouterjoin);
/*
@ -49,27 +49,19 @@ static RestrictInfo *join_clause_is_redundant(Query *root,
RestrictInfo *
make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere)
{
Expr *orclause;
/*
* If it's an OR clause, build a modified copy with RestrictInfos
* inserted above each subclause of the top-level AND/OR structure.
*/
if (or_clause((Node *) clause))
{
orclause = make_sub_restrictinfos(clause,
is_pushed_down,
valid_everywhere);
}
else
{
/* Shouldn't be an AND clause, else AND/OR flattening messed up */
Assert(!and_clause((Node *) clause));
return (RestrictInfo *) make_sub_restrictinfos(clause,
is_pushed_down,
valid_everywhere);
orclause = NULL;
}
/* Shouldn't be an AND clause, else AND/OR flattening messed up */
Assert(!and_clause((Node *) clause));
return make_restrictinfo_internal(clause, orclause,
return make_restrictinfo_internal(clause, NULL,
is_pushed_down, valid_everywhere);
}
@ -198,6 +190,12 @@ make_restrictinfo_internal(Expr *clause, Expr *orclause,
/*
* Recursively insert sub-RestrictInfo nodes into a boolean expression.
*
* We put RestrictInfos above simple (non-AND/OR) clauses and above
* sub-OR clauses, but not above sub-AND clauses, because there's no need.
* This may seem odd but it is closely related to the fact that we use
* implicit-AND lists at top level of RestrictInfo lists. Only ORs and
* simple clauses are valid RestrictInfos.
*/
static Expr *
make_sub_restrictinfos(Expr *clause, bool is_pushed_down,
@ -213,7 +211,10 @@ make_sub_restrictinfos(Expr *clause, bool is_pushed_down,
make_sub_restrictinfos(lfirst(temp),
is_pushed_down,
valid_everywhere));
return make_orclause(orlist);
return (Expr *) make_restrictinfo_internal(clause,
make_orclause(orlist),
is_pushed_down,
valid_everywhere);
}
else if (and_clause((Node *) clause))
{
@ -314,7 +315,7 @@ get_actual_join_clauses(List *restrictinfo_list,
*/
List *
remove_redundant_join_clauses(Query *root, List *restrictinfo_list,
JoinType jointype)
bool isouterjoin)
{
List *result = NIL;
ListCell *item;
@ -341,7 +342,7 @@ remove_redundant_join_clauses(Query *root, List *restrictinfo_list,
RestrictInfo *prevrinfo;
/* is it redundant with any prior clause? */
prevrinfo = join_clause_is_redundant(root, rinfo, result, jointype);
prevrinfo = join_clause_is_redundant(root, rinfo, result, isouterjoin);
if (prevrinfo == NULL)
{
/* no, so add it to result list */
@ -377,7 +378,7 @@ List *
select_nonredundant_join_clauses(Query *root,
List *restrictinfo_list,
List *reference_list,
JoinType jointype)
bool isouterjoin)
{
List *result = NIL;
ListCell *item;
@ -387,7 +388,7 @@ select_nonredundant_join_clauses(Query *root,
RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
/* drop it if redundant with any reference clause */
if (join_clause_is_redundant(root, rinfo, reference_list, jointype) != NULL)
if (join_clause_is_redundant(root, rinfo, reference_list, isouterjoin) != NULL)
continue;
/* otherwise, add it to result list */
@ -429,7 +430,7 @@ static RestrictInfo *
join_clause_is_redundant(Query *root,
RestrictInfo *rinfo,
List *reference_list,
JoinType jointype)
bool isouterjoin)
{
ListCell *refitem;
@ -463,7 +464,7 @@ join_clause_is_redundant(Query *root,
if (rinfo->left_pathkey == refrinfo->left_pathkey &&
rinfo->right_pathkey == refrinfo->right_pathkey &&
(rinfo->is_pushed_down == refrinfo->is_pushed_down ||
!IS_OUTER_JOIN(jointype)))
!isouterjoin))
{
/* Yup, it's redundant */
return refrinfo;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.107 2005/04/21 19:18:13 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.108 2005/04/22 21:58:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -274,10 +274,6 @@ typedef struct IndexOptInfo
bool predOK; /* true if predicate matches query */
bool unique; /* true if a unique index */
/* cached info about inner indexscan paths for index */
Relids outer_relids; /* other relids in usable join clauses */
List *inner_paths; /* List of InnerIndexscanInfo nodes */
} IndexOptInfo;
@ -764,16 +760,13 @@ typedef struct JoinInfo
* thus varies depending on which outer relation we consider; so we have
* to recompute the best such path for every join. To avoid lots of
* redundant computation, we cache the results of such searches. For
* each index we compute the set of possible otherrelids (all relids
* appearing in joinquals that could become indexquals for this index).
* each relation we compute the set of possible otherrelids (all relids
* appearing in joinquals that could become indexquals for this table).
* Two outer relations whose relids have the same intersection with this
* set will have the same set of available joinclauses and thus the same
* best inner indexscan for that index. Similarly, for each base relation,
* we form the union of the per-index otherrelids sets. Two outer relations
* with the same intersection with that set will have the same best overall
* inner indexscan for the base relation. We use lists of InnerIndexscanInfo
* nodes to cache the results of these searches at both the index and
* relation level.
* best inner indexscan for the inner relation. By taking the intersection
* before scanning the cache, we avoid recomputing when considering
* join rels that differ only by the inclusion of irrelevant other rels.
*
* The search key also includes a bool showing whether the join being
* considered is an outer join. Since we constrain the join order for

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/optimizer/cost.h,v 1.66 2005/04/21 19:18:13 tgl Exp $
* $PostgreSQL: pgsql/src/include/optimizer/cost.h,v 1.67 2005/04/22 21:58:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -58,6 +58,7 @@ extern void cost_bitmap_heap_scan(Path *path, Query *root, RelOptInfo *baserel,
Path *bitmapqual, bool is_injoin);
extern void cost_bitmap_and_node(BitmapAndPath *path, Query *root);
extern void cost_bitmap_or_node(BitmapOrPath *path, Query *root);
extern void cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec);
extern void cost_tidscan(Path *path, Query *root,
RelOptInfo *baserel, List *tideval);
extern void cost_subqueryscan(Path *path, RelOptInfo *baserel);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/optimizer/pathnode.h,v 1.59 2005/04/21 19:18:13 tgl Exp $
* $PostgreSQL: pgsql/src/include/optimizer/pathnode.h,v 1.60 2005/04/22 21:58:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -30,12 +30,14 @@ extern void add_path(RelOptInfo *parent_rel, Path *new_path);
extern Path *create_seqscan_path(Query *root, RelOptInfo *rel);
extern IndexPath *create_index_path(Query *root,
IndexOptInfo *index,
List *restriction_clauses,
List *clause_groups,
List *pathkeys,
ScanDirection indexscandir);
ScanDirection indexscandir,
bool isjoininner);
extern BitmapHeapPath *create_bitmap_heap_path(Query *root,
RelOptInfo *rel,
Path *bitmapqual);
Path *bitmapqual,
bool isjoininner);
extern BitmapAndPath *create_bitmap_and_path(Query *root,
RelOptInfo *rel,
List *bitmapquals);

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.81 2005/04/11 23:06:56 tgl Exp $
* $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.82 2005/04/22 21:58:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -38,7 +38,9 @@ extern void debug_print_rel(Query *root, RelOptInfo *rel);
extern void create_index_paths(Query *root, RelOptInfo *rel);
extern Path *best_inner_indexscan(Query *root, RelOptInfo *rel,
Relids outer_relids, JoinType jointype);
extern List *group_clauses_by_indexkey(IndexOptInfo *index);
extern List *group_clauses_by_indexkey(IndexOptInfo *index,
List *clauses, List *outer_clauses,
Relids outer_relids);
extern List *group_clauses_by_indexkey_for_or(IndexOptInfo *index,
Expr *orsubclause);
extern bool match_index_to_operand(Node *operand, int indexcol,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.26 2004/12/31 22:03:36 pgsql Exp $
* $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.27 2005/04/22 21:58:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -27,10 +27,10 @@ extern void get_actual_join_clauses(List *restrictinfo_list,
List **joinquals, List **otherquals);
extern List *remove_redundant_join_clauses(Query *root,
List *restrictinfo_list,
JoinType jointype);
bool isouterjoin);
extern List *select_nonredundant_join_clauses(Query *root,
List *restrictinfo_list,
List *reference_list,
JoinType jointype);
bool isouterjoin);
#endif /* RESTRICTINFO_H */

View File

@ -131,8 +131,10 @@ ALTER INDEX tmp_onek_unique1 RENAME TO onek_unique1;
-- renaming views
CREATE VIEW tmp_view (unique1) AS SELECT unique1 FROM tenk1;
ALTER TABLE tmp_view RENAME TO tmp_view_new;
-- analyze to ensure we get an indexscan here
-- hack to ensure we get an indexscan here
ANALYZE tenk1;
set enable_seqscan to off;
set enable_bitmapscan to off;
-- 5 values, sorted
SELECT unique1 FROM tenk1 WHERE unique1 < 5;
unique1
@ -144,6 +146,8 @@ SELECT unique1 FROM tenk1 WHERE unique1 < 5;
4
(5 rows)
reset enable_seqscan;
reset enable_bitmapscan;
DROP VIEW tmp_view_new;
-- toast-like relation name
alter table stud_emp rename to pg_toast_stud_emp;

View File

@ -367,6 +367,7 @@ insert into arr_tbl values ('{2,3,4}');
insert into arr_tbl values ('{1,5,3}');
insert into arr_tbl values ('{1,2,10}');
set enable_seqscan to off;
set enable_bitmapscan to off;
select * from arr_tbl where f1 > '{1,2,3}' and f1 <= '{1,5,3}';
f1
----------
@ -376,6 +377,8 @@ select * from arr_tbl where f1 > '{1,2,3}' and f1 <= '{1,5,3}';
-- note: if above select doesn't produce the expected tuple order,
-- then you didn't get an indexscan plan, and something is busted.
reset enable_seqscan;
reset enable_bitmapscan;
-- test [not] (like|ilike) (any|all) (...)
select 'foo' like any (array['%a', '%o']); -- t
?column?

View File

@ -11,6 +11,8 @@ SHOW stats_start_collector; -- must be on
on
(1 row)
-- XXX stopgap until we figure out how bitmap scans should be counted
SET enable_bitmapscan = off;
-- save counters
CREATE TEMP TABLE prevstats AS
SELECT t.seq_scan, t.seq_tup_read, t.idx_scan, t.idx_tup_fetch,

View File

@ -171,10 +171,16 @@ ALTER INDEX tmp_onek_unique1 RENAME TO onek_unique1;
-- renaming views
CREATE VIEW tmp_view (unique1) AS SELECT unique1 FROM tenk1;
ALTER TABLE tmp_view RENAME TO tmp_view_new;
-- analyze to ensure we get an indexscan here
-- hack to ensure we get an indexscan here
ANALYZE tenk1;
set enable_seqscan to off;
set enable_bitmapscan to off;
-- 5 values, sorted
SELECT unique1 FROM tenk1 WHERE unique1 < 5;
reset enable_seqscan;
reset enable_bitmapscan;
DROP VIEW tmp_view_new;
-- toast-like relation name
alter table stud_emp rename to pg_toast_stud_emp;

View File

@ -178,10 +178,14 @@ insert into arr_tbl values ('{1,2,3}');
insert into arr_tbl values ('{2,3,4}');
insert into arr_tbl values ('{1,5,3}');
insert into arr_tbl values ('{1,2,10}');
set enable_seqscan to off;
set enable_bitmapscan to off;
select * from arr_tbl where f1 > '{1,2,3}' and f1 <= '{1,5,3}';
-- note: if above select doesn't produce the expected tuple order,
-- then you didn't get an indexscan plan, and something is busted.
reset enable_seqscan;
reset enable_bitmapscan;
-- test [not] (like|ilike) (any|all) (...)
select 'foo' like any (array['%a', '%o']); -- t

View File

@ -8,6 +8,9 @@
-- conditio sine qua non
SHOW stats_start_collector; -- must be on
-- XXX stopgap until we figure out how bitmap scans should be counted
SET enable_bitmapscan = off;
-- save counters
CREATE TEMP TABLE prevstats AS
SELECT t.seq_scan, t.seq_tup_read, t.idx_scan, t.idx_tup_fetch,