Commit 8dcf1841 authored by Tom Lane's avatar Tom Lane

Fix cost_nestloop and cost_hashjoin to model the behavior of semi and anti

joins a bit better, ie, understand the differing cost functions for matched
and unmatched outer tuples.  There is more that could be done in cost_hashjoin
but this already helps a great deal.  Per discussions with Robert Haas.
parent a41e9ec0
This diff is collapsed.
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.258 2009/04/19 19:46:33 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.259 2009/05/09 22:51:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1562,62 +1562,16 @@ create_nestloop_plan(PlannerInfo *root, ...@@ -1562,62 +1562,16 @@ create_nestloop_plan(PlannerInfo *root,
List *otherclauses; List *otherclauses;
NestLoop *join_plan; NestLoop *join_plan;
if (IsA(best_path->innerjoinpath, IndexPath)) /*
{ * If the inner path is a nestloop inner indexscan, it might be using
/* * some of the join quals as index quals, in which case we don't have
* An index is being used to reduce the number of tuples scanned in * to check them again at the join node. Remove any join quals that
* the inner relation. If there are join clauses being used with the * are redundant.
* index, we may remove those join clauses from the list of clauses */
* that have to be checked as qpquals at the join node. joinrestrictclauses =
* select_nonredundant_join_clauses(root,
* We can also remove any join clauses that are redundant with those joinrestrictclauses,
* being used in the index scan; this check is needed because best_path->innerjoinpath);
* find_eclass_clauses_for_index_join() may emit different clauses
* than generate_join_implied_equalities() did.
*
* We can skip this if the index path is an ordinary indexpath and not
* a special innerjoin path, since it then wouldn't be using any join
* clauses.
*/
IndexPath *innerpath = (IndexPath *) best_path->innerjoinpath;
if (innerpath->isjoininner)
joinrestrictclauses =
select_nonredundant_join_clauses(root,
joinrestrictclauses,
innerpath->indexclauses);
}
else if (IsA(best_path->innerjoinpath, BitmapHeapPath))
{
/*
* Same deal for bitmapped index scans.
*
* Note: both here and above, we ignore any implicit index
* restrictions associated with the use of partial indexes. This is
* OK because we're only trying to prove we can dispense with some
* join quals; failing to prove that doesn't result in an incorrect
* plan. It is the right way to proceed because adding more quals to
* the stuff we got from the original query would just make it harder
* to detect duplication. (Also, to change this we'd have to be wary
* of UPDATE/DELETE/SELECT FOR UPDATE target relations; see notes
* above about EvalPlanQual.)
*/
BitmapHeapPath *innerpath = (BitmapHeapPath *) best_path->innerjoinpath;
if (innerpath->isjoininner)
{
List *bitmapclauses;
bitmapclauses =
make_restrictinfo_from_bitmapqual(innerpath->bitmapqual,
true,
false);
joinrestrictclauses =
select_nonredundant_join_clauses(root,
joinrestrictclauses,
bitmapclauses);
}
}
/* Sort join qual clauses into best execution order */ /* Sort join qual clauses into best execution order */
joinrestrictclauses = order_qual_clauses(root, joinrestrictclauses); joinrestrictclauses = order_qual_clauses(root, joinrestrictclauses);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.58 2009/04/16 20:42:16 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.59 2009/05/09 22:51:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -35,8 +35,9 @@ static Expr *make_sub_restrictinfos(Expr *clause, ...@@ -35,8 +35,9 @@ static Expr *make_sub_restrictinfos(Expr *clause,
bool pseudoconstant, bool pseudoconstant,
Relids required_relids, Relids required_relids,
Relids nullable_relids); Relids nullable_relids);
static bool join_clause_is_redundant(PlannerInfo *root, static List *select_nonredundant_join_list(List *restrictinfo_list,
RestrictInfo *rinfo, List *reference_list);
static bool join_clause_is_redundant(RestrictInfo *rinfo,
List *reference_list); List *reference_list);
...@@ -545,26 +546,91 @@ extract_actual_join_clauses(List *restrictinfo_list, ...@@ -545,26 +546,91 @@ extract_actual_join_clauses(List *restrictinfo_list,
} }
} }
/* /*
* select_nonredundant_join_clauses * select_nonredundant_join_clauses
* *
* Given a list of RestrictInfo clauses that are to be applied in a join, * Given a list of RestrictInfo clauses that are to be applied in a join,
* select the ones that are not redundant with any clause in the * select the ones that are not redundant with any clause that's enforced
* reference_list. This is used only for nestloop-with-inner-indexscan * by the inner_path. This is used for nestloop joins, wherein any clause
* joins: any clauses being checked by the index should be removed from * being used in an inner indexscan need not be checked again at the join.
* the qpquals list.
* *
* "Redundant" means either equal() or derived from the same EquivalenceClass. * "Redundant" means either equal() or derived from the same EquivalenceClass.
* We have to check the latter because indxqual.c may select different derived * We have to check the latter because indxqual.c may select different derived
* clauses than were selected by generate_join_implied_equalities(). * clauses than were selected by generate_join_implied_equalities().
* *
* Note that we assume the given restrictinfo_list has already been checked * Note that we are *not* checking for local redundancies within the given
* for local redundancies, so we don't check again. * restrictinfo_list; that should have been handled elsewhere.
*/ */
List * List *
select_nonredundant_join_clauses(PlannerInfo *root, select_nonredundant_join_clauses(PlannerInfo *root,
List *restrictinfo_list, List *restrictinfo_list,
List *reference_list) Path *inner_path)
{
if (IsA(inner_path, IndexPath))
{
/*
* Check the index quals to see if any of them are join clauses.
*
* We can skip this if the index path is an ordinary indexpath and not
* a special innerjoin path, since it then wouldn't be using any join
* clauses.
*/
IndexPath *innerpath = (IndexPath *) inner_path;
if (innerpath->isjoininner)
restrictinfo_list =
select_nonredundant_join_list(restrictinfo_list,
innerpath->indexclauses);
}
else if (IsA(inner_path, BitmapHeapPath))
{
/*
* Same deal for bitmapped index scans.
*
* Note: both here and above, we ignore any implicit index
* restrictions associated with the use of partial indexes. This is
* OK because we're only trying to prove we can dispense with some
* join quals; failing to prove that doesn't result in an incorrect
* plan. It's quite unlikely that a join qual could be proven
* redundant by an index predicate anyway. (Also, if we did manage
* to prove it, we'd have to have a special case for update targets;
* see notes about EvalPlanQual testing in create_indexscan_plan().)
*/
BitmapHeapPath *innerpath = (BitmapHeapPath *) inner_path;
if (innerpath->isjoininner)
{
List *bitmapclauses;
bitmapclauses =
make_restrictinfo_from_bitmapqual(innerpath->bitmapqual,
true,
false);
restrictinfo_list =
select_nonredundant_join_list(restrictinfo_list,
bitmapclauses);
}
}
/*
* XXX the inner path of a nestloop could also be an append relation
* whose elements use join quals. However, they might each use different
* quals; we could only remove join quals that are enforced by all the
* appendrel members. For the moment we don't bother to try.
*/
return restrictinfo_list;
}
/*
* select_nonredundant_join_list
* Select the members of restrictinfo_list that are not redundant with
* any member of reference_list. See above for more info.
*/
static List *
select_nonredundant_join_list(List *restrictinfo_list,
List *reference_list)
{ {
List *result = NIL; List *result = NIL;
ListCell *item; ListCell *item;
...@@ -574,7 +640,7 @@ select_nonredundant_join_clauses(PlannerInfo *root, ...@@ -574,7 +640,7 @@ select_nonredundant_join_clauses(PlannerInfo *root,
RestrictInfo *rinfo = (RestrictInfo *) lfirst(item); RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
/* drop it if redundant with any reference clause */ /* drop it if redundant with any reference clause */
if (join_clause_is_redundant(root, rinfo, reference_list)) if (join_clause_is_redundant(rinfo, reference_list))
continue; continue;
/* otherwise, add it to result list */ /* otherwise, add it to result list */
...@@ -589,8 +655,7 @@ select_nonredundant_join_clauses(PlannerInfo *root, ...@@ -589,8 +655,7 @@ select_nonredundant_join_clauses(PlannerInfo *root,
* Test whether rinfo is redundant with any clause in reference_list. * Test whether rinfo is redundant with any clause in reference_list.
*/ */
static bool static bool
join_clause_is_redundant(PlannerInfo *root, join_clause_is_redundant(RestrictInfo *rinfo,
RestrictInfo *rinfo,
List *reference_list) List *reference_list)
{ {
ListCell *refitem; ListCell *refitem;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.43 2009/04/16 20:42:16 tgl Exp $ * $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.44 2009/05/09 22:51:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -39,6 +39,6 @@ extern void extract_actual_join_clauses(List *restrictinfo_list, ...@@ -39,6 +39,6 @@ extern void extract_actual_join_clauses(List *restrictinfo_list,
List **otherquals); List **otherquals);
extern List *select_nonredundant_join_clauses(PlannerInfo *root, extern List *select_nonredundant_join_clauses(PlannerInfo *root,
List *restrictinfo_list, List *restrictinfo_list,
List *reference_list); Path *inner_path);
#endif /* RESTRICTINFO_H */ #endif /* RESTRICTINFO_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