1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-10 17:42:29 +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

@@ -403,14 +403,17 @@ pathkeys_contained_in(List *keys1, List *keys2)
/*
* get_cheapest_path_for_pathkeys
* Find the cheapest path (according to the specified criterion) that
* satisfies the given pathkeys. Return NULL if no such path.
* satisfies the given pathkeys and parameterization.
* Return NULL if no such path.
*
* 'paths' is a list of possible paths that all generate the same relation
* 'pathkeys' represents a required ordering (already canonicalized!)
* 'required_outer' denotes allowable outer relations for parameterized paths
* 'cost_criterion' is STARTUP_COST or TOTAL_COST
*/
Path *
get_cheapest_path_for_pathkeys(List *paths, List *pathkeys,
Relids required_outer,
CostSelector cost_criterion)
{
Path *matched_path = NULL;
@@ -428,7 +431,8 @@ get_cheapest_path_for_pathkeys(List *paths, List *pathkeys,
compare_path_costs(matched_path, path, cost_criterion) <= 0)
continue;
if (pathkeys_contained_in(pathkeys, path->pathkeys))
if (pathkeys_contained_in(pathkeys, path->pathkeys) &&
bms_is_subset(path->required_outer, required_outer))
matched_path = path;
}
return matched_path;
@@ -437,7 +441,7 @@ get_cheapest_path_for_pathkeys(List *paths, List *pathkeys,
/*
* get_cheapest_fractional_path_for_pathkeys
* Find the cheapest path (for retrieving a specified fraction of all
* the tuples) that satisfies the given pathkeys.
* the tuples) that satisfies the given pathkeys and parameterization.
* Return NULL if no such path.
*
* See compare_fractional_path_costs() for the interpretation of the fraction
@@ -445,11 +449,13 @@ get_cheapest_path_for_pathkeys(List *paths, List *pathkeys,
*
* 'paths' is a list of possible paths that all generate the same relation
* 'pathkeys' represents a required ordering (already canonicalized!)
* 'required_outer' denotes allowable outer relations for parameterized paths
* 'fraction' is the fraction of the total tuples expected to be retrieved
*/
Path *
get_cheapest_fractional_path_for_pathkeys(List *paths,
List *pathkeys,
Relids required_outer,
double fraction)
{
Path *matched_path = NULL;
@@ -461,13 +467,14 @@ get_cheapest_fractional_path_for_pathkeys(List *paths,
/*
* Since cost comparison is a lot cheaper than pathkey comparison, do
* that first.
* that first. (XXX is that still true?)
*/
if (matched_path != NULL &&
compare_fractional_path_costs(matched_path, path, fraction) <= 0)
continue;
if (pathkeys_contained_in(pathkeys, path->pathkeys))
if (pathkeys_contained_in(pathkeys, path->pathkeys) &&
bms_is_subset(path->required_outer, required_outer))
matched_path = path;
}
return matched_path;