Commit f5983923 authored by Tom Lane's avatar Tom Lane

Allow create_index_paths() to consider multiple join bitmapscan paths.

In the initial cut at the "parameterized paths" feature, I'd simplified
create_index_paths() to the point where it would only generate a single
parameterized bitmap path per relation.  Experimentation with an example
supplied by Josh Berkus convinces me that that's not good enough: we really
need to consider a bitmap path for each possible outer relation.  Otherwise
we have regressions relative to pre-9.2 versions, in which the planner
picks a plain indexscan where it should have used a bitmap scan in queries
involving three or more tables.  Indeed, after fixing this, several queries
in the regression tests show improved plans as a result of using bitmap not
plain indexscans.
parent 56ba337e
...@@ -309,27 +309,93 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel) ...@@ -309,27 +309,93 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
} }
/* /*
* Likewise, if we found anything usable, generate a BitmapHeapPath for * Likewise, if we found anything usable, generate BitmapHeapPaths for the
* the most promising combination of join bitmap index paths. Note there * most promising combinations of join bitmap index paths. Our strategy
* will be only one such path no matter how many join clauses are * is to generate one such path for each distinct parameterization seen
* available. (XXX is that good enough, or do we need to consider even * among the available bitmap index paths. This may look pretty
* more paths for different subsets of possible join partners? Also, * expensive, but usually there won't be very many distinct
* should we add in restriction bitmap paths as well?) * parameterizations.
*/ */
if (bitjoinpaths != NIL) if (bitjoinpaths != NIL)
{ {
List *path_outer;
List *all_path_outers;
ListCell *lc;
/*
* path_outer holds the parameterization of each path in bitjoinpaths
* (to save recalculating that several times), while all_path_outers
* holds all distinct parameterization sets.
*/
path_outer = all_path_outers = NIL;
foreach(lc, bitjoinpaths)
{
Path *path = (Path *) lfirst(lc);
Relids required_outer;
bool found = false;
ListCell *lco;
required_outer = get_bitmap_tree_required_outer(path);
path_outer = lappend(path_outer, required_outer);
/* Have we already seen this param set? */
foreach(lco, all_path_outers)
{
Relids existing_outers = (Relids) lfirst(lco);
if (bms_equal(existing_outers, required_outer))
{
found = true;
break;
}
}
if (!found)
{
/* No, so add it to all_path_outers */
all_path_outers = lappend(all_path_outers, required_outer);
}
}
/* Now, for each distinct parameterization set ... */
foreach(lc, all_path_outers)
{
Relids max_outers = (Relids) lfirst(lc);
List *this_path_set;
Path *bitmapqual; Path *bitmapqual;
Relids required_outer; Relids required_outer;
double loop_count; double loop_count;
BitmapHeapPath *bpath; BitmapHeapPath *bpath;
ListCell *lcp;
ListCell *lco;
/* Identify all the bitmap join paths needing no more than that */
this_path_set = NIL;
forboth(lcp, bitjoinpaths, lco, path_outer)
{
Path *path = (Path *) lfirst(lcp);
Relids p_outers = (Relids) lfirst(lco);
bitmapqual = choose_bitmap_and(root, rel, bitjoinpaths); if (bms_is_subset(p_outers, max_outers))
this_path_set = lappend(this_path_set, path);
}
/*
* Add in restriction bitmap paths, since they can be used
* together with any join paths.
*/
this_path_set = list_concat(this_path_set, bitindexpaths);
/* Select best AND combination for this parameterization */
bitmapqual = choose_bitmap_and(root, rel, this_path_set);
/* And push that path into the mix */
required_outer = get_bitmap_tree_required_outer(bitmapqual); required_outer = get_bitmap_tree_required_outer(bitmapqual);
loop_count = get_loop_count(root, required_outer); loop_count = get_loop_count(root, required_outer);
bpath = create_bitmap_heap_path(root, rel, bitmapqual, bpath = create_bitmap_heap_path(root, rel, bitmapqual,
required_outer, loop_count); required_outer, loop_count);
add_path(rel, (Path *) bpath); add_path(rel, (Path *) bpath);
} }
}
} }
/* /*
......
...@@ -2725,11 +2725,13 @@ where t1.unique1 = 1; ...@@ -2725,11 +2725,13 @@ where t1.unique1 = 1;
Index Cond: (unique1 = 1) Index Cond: (unique1 = 1)
-> Nested Loop -> Nested Loop
Join Filter: (t1.ten = t3.ten) Join Filter: (t1.ten = t3.ten)
-> Index Scan using tenk1_hundred on tenk1 t2 -> Bitmap Heap Scan on tenk1 t2
Recheck Cond: (t1.hundred = hundred)
-> Bitmap Index Scan on tenk1_hundred
Index Cond: (t1.hundred = hundred) Index Cond: (t1.hundred = hundred)
-> Index Scan using tenk1_unique2 on tenk1 t3 -> Index Scan using tenk1_unique2 on tenk1 t3
Index Cond: (unique2 = t2.thousand) Index Cond: (unique2 = t2.thousand)
(9 rows) (11 rows)
explain (costs off) explain (costs off)
select * from tenk1 t1 left join select * from tenk1 t1 left join
...@@ -2743,11 +2745,13 @@ where t1.unique1 = 1; ...@@ -2743,11 +2745,13 @@ where t1.unique1 = 1;
Index Cond: (unique1 = 1) Index Cond: (unique1 = 1)
-> Nested Loop -> Nested Loop
Join Filter: ((t1.ten + t2.ten) = t3.ten) Join Filter: ((t1.ten + t2.ten) = t3.ten)
-> Index Scan using tenk1_hundred on tenk1 t2 -> Bitmap Heap Scan on tenk1 t2
Recheck Cond: (t1.hundred = hundred)
-> Bitmap Index Scan on tenk1_hundred
Index Cond: (t1.hundred = hundred) Index Cond: (t1.hundred = hundred)
-> Index Scan using tenk1_unique2 on tenk1 t3 -> Index Scan using tenk1_unique2 on tenk1 t3
Index Cond: (unique2 = t2.thousand) Index Cond: (unique2 = t2.thousand)
(9 rows) (11 rows)
explain (costs off) explain (costs off)
select count(*) from select count(*) from
...@@ -2755,20 +2759,22 @@ select count(*) from ...@@ -2755,20 +2759,22 @@ select count(*) from
left join tenk1 c on a.unique2 = b.unique1 and c.thousand = a.thousand left join tenk1 c on a.unique2 = b.unique1 and c.thousand = a.thousand
join int4_tbl on b.thousand = f1; join int4_tbl on b.thousand = f1;
QUERY PLAN QUERY PLAN
-------------------------------------------------------------------------- -------------------------------------------------------------------------
Aggregate Aggregate
-> Nested Loop Left Join -> Nested Loop Left Join
Join Filter: (a.unique2 = b.unique1) Join Filter: (a.unique2 = b.unique1)
-> Nested Loop -> Nested Loop
-> Nested Loop -> Nested Loop
-> Seq Scan on int4_tbl -> Seq Scan on int4_tbl
-> Index Scan using tenk1_thous_tenthous on tenk1 b -> Bitmap Heap Scan on tenk1 b
Recheck Cond: (thousand = int4_tbl.f1)
-> Bitmap Index Scan on tenk1_thous_tenthous
Index Cond: (thousand = int4_tbl.f1) Index Cond: (thousand = int4_tbl.f1)
-> Index Scan using tenk1_unique1 on tenk1 a -> Index Scan using tenk1_unique1 on tenk1 a
Index Cond: (unique1 = b.unique2) Index Cond: (unique1 = b.unique2)
-> Index Only Scan using tenk1_thous_tenthous on tenk1 c -> Index Only Scan using tenk1_thous_tenthous on tenk1 c
Index Cond: (thousand = a.thousand) Index Cond: (thousand = a.thousand)
(12 rows) (14 rows)
select count(*) from select count(*) from
tenk1 a join tenk1 b on a.unique1 = b.unique2 tenk1 a join tenk1 b on a.unique1 = b.unique2
......
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