1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-21 00:42:43 +03:00

Use parameterized paths to generate inner indexscans more flexibly.

This patch fixes the planner so that it can generate nestloop-with-
inner-indexscan plans even with one or more levels of joining between
the indexscan and the nestloop join that is supplying the parameter.
The executor was fixed to handle such cases some time ago, but the
planner was not ready.  This should improve our plans in many situations
where join ordering restrictions formerly forced complete table scans.

There is probably a fair amount of tuning work yet to be done, because
of various heuristics that have been added to limit the number of
parameterized paths considered.  However, we are not going to find out
what needs to be adjusted until the code gets some real-world use, so
it's time to get it in there where it can be tested easily.

Note API change for index AM amcostestimate functions.  I'm not aware of
any non-core index AMs, but if there are any, they will need minor
adjustments.
This commit is contained in:
Tom Lane
2012-01-27 19:26:38 -05:00
parent b376ec6fa5
commit e2fa76d80b
26 changed files with 3884 additions and 2292 deletions

View File

@@ -33,8 +33,6 @@ static Expr *make_sub_restrictinfos(Expr *clause,
bool pseudoconstant,
Relids required_relids,
Relids nullable_relids);
static List *select_nonredundant_join_list(List *restrictinfo_list,
List *reference_list);
static bool join_clause_is_redundant(RestrictInfo *rinfo,
List *reference_list);
@@ -623,11 +621,14 @@ extract_actual_join_clauses(List *restrictinfo_list,
/*
* select_nonredundant_join_clauses
* Select the members of restrictinfo_list that are not redundant with
* any member of reference_list.
*
* Given a list of RestrictInfo clauses that are to be applied in a join,
* select the ones that are not redundant with any clause that's enforced
* by the inner_path. This is used for nestloop joins, wherein any clause
* being used in an inner indexscan need not be checked again at the join.
* select the ones that are not redundant with any clause that's listed in
* reference_list. This is used, for example, to avoid checking joinclauses
* again at a nestloop join when they've already been enforced by a
* parameterized inner path.
*
* "Redundant" means either equal() or derived from the same EquivalenceClass.
* We have to check the latter because indxpath.c may select different derived
@@ -637,78 +638,16 @@ extract_actual_join_clauses(List *restrictinfo_list,
* restrictinfo_list; that should have been handled elsewhere.
*/
List *
select_nonredundant_join_clauses(PlannerInfo *root,
List *restrictinfo_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)
select_nonredundant_join_clauses(List *restrictinfo_list,
List *reference_list)
{
List *result = NIL;
ListCell *item;
/* Quick out if nothing could be removed */
if (reference_list == NIL)
return restrictinfo_list;
foreach(item, restrictinfo_list)
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);