Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit f598392

Browse files
committed
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.
1 parent 56ba337 commit f598392

File tree

2 files changed

+99
-27
lines changed

2 files changed

+99
-27
lines changed

src/backend/optimizer/path/indxpath.c

+82-16
Original file line numberDiff line numberDiff line change
@@ -309,26 +309,92 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
309309
}
310310

311311
/*
312-
* Likewise, if we found anything usable, generate a BitmapHeapPath for
313-
* the most promising combination of join bitmap index paths. Note there
314-
* will be only one such path no matter how many join clauses are
315-
* available. (XXX is that good enough, or do we need to consider even
316-
* more paths for different subsets of possible join partners? Also,
317-
* should we add in restriction bitmap paths as well?)
312+
* Likewise, if we found anything usable, generate BitmapHeapPaths for the
313+
* most promising combinations of join bitmap index paths. Our strategy
314+
* is to generate one such path for each distinct parameterization seen
315+
* among the available bitmap index paths. This may look pretty
316+
* expensive, but usually there won't be very many distinct
317+
* parameterizations.
318318
*/
319319
if (bitjoinpaths != NIL)
320320
{
321-
Path *bitmapqual;
322-
Relids required_outer;
323-
double loop_count;
324-
BitmapHeapPath *bpath;
321+
List *path_outer;
322+
List *all_path_outers;
323+
ListCell *lc;
325324

326-
bitmapqual = choose_bitmap_and(root, rel, bitjoinpaths);
327-
required_outer = get_bitmap_tree_required_outer(bitmapqual);
328-
loop_count = get_loop_count(root, required_outer);
329-
bpath = create_bitmap_heap_path(root, rel, bitmapqual,
330-
required_outer, loop_count);
331-
add_path(rel, (Path *) bpath);
325+
/*
326+
* path_outer holds the parameterization of each path in bitjoinpaths
327+
* (to save recalculating that several times), while all_path_outers
328+
* holds all distinct parameterization sets.
329+
*/
330+
path_outer = all_path_outers = NIL;
331+
foreach(lc, bitjoinpaths)
332+
{
333+
Path *path = (Path *) lfirst(lc);
334+
Relids required_outer;
335+
bool found = false;
336+
ListCell *lco;
337+
338+
required_outer = get_bitmap_tree_required_outer(path);
339+
path_outer = lappend(path_outer, required_outer);
340+
341+
/* Have we already seen this param set? */
342+
foreach(lco, all_path_outers)
343+
{
344+
Relids existing_outers = (Relids) lfirst(lco);
345+
346+
if (bms_equal(existing_outers, required_outer))
347+
{
348+
found = true;
349+
break;
350+
}
351+
}
352+
if (!found)
353+
{
354+
/* No, so add it to all_path_outers */
355+
all_path_outers = lappend(all_path_outers, required_outer);
356+
}
357+
}
358+
359+
/* Now, for each distinct parameterization set ... */
360+
foreach(lc, all_path_outers)
361+
{
362+
Relids max_outers = (Relids) lfirst(lc);
363+
List *this_path_set;
364+
Path *bitmapqual;
365+
Relids required_outer;
366+
double loop_count;
367+
BitmapHeapPath *bpath;
368+
ListCell *lcp;
369+
ListCell *lco;
370+
371+
/* Identify all the bitmap join paths needing no more than that */
372+
this_path_set = NIL;
373+
forboth(lcp, bitjoinpaths, lco, path_outer)
374+
{
375+
Path *path = (Path *) lfirst(lcp);
376+
Relids p_outers = (Relids) lfirst(lco);
377+
378+
if (bms_is_subset(p_outers, max_outers))
379+
this_path_set = lappend(this_path_set, path);
380+
}
381+
382+
/*
383+
* Add in restriction bitmap paths, since they can be used
384+
* together with any join paths.
385+
*/
386+
this_path_set = list_concat(this_path_set, bitindexpaths);
387+
388+
/* Select best AND combination for this parameterization */
389+
bitmapqual = choose_bitmap_and(root, rel, this_path_set);
390+
391+
/* And push that path into the mix */
392+
required_outer = get_bitmap_tree_required_outer(bitmapqual);
393+
loop_count = get_loop_count(root, required_outer);
394+
bpath = create_bitmap_heap_path(root, rel, bitmapqual,
395+
required_outer, loop_count);
396+
add_path(rel, (Path *) bpath);
397+
}
332398
}
333399
}
334400

src/test/regress/expected/join.out

+17-11
Original file line numberDiff line numberDiff line change
@@ -2725,11 +2725,13 @@ where t1.unique1 = 1;
27252725
Index Cond: (unique1 = 1)
27262726
-> Nested Loop
27272727
Join Filter: (t1.ten = t3.ten)
2728-
-> Index Scan using tenk1_hundred on tenk1 t2
2729-
Index Cond: (t1.hundred = hundred)
2728+
-> Bitmap Heap Scan on tenk1 t2
2729+
Recheck Cond: (t1.hundred = hundred)
2730+
-> Bitmap Index Scan on tenk1_hundred
2731+
Index Cond: (t1.hundred = hundred)
27302732
-> Index Scan using tenk1_unique2 on tenk1 t3
27312733
Index Cond: (unique2 = t2.thousand)
2732-
(9 rows)
2734+
(11 rows)
27332735

27342736
explain (costs off)
27352737
select * from tenk1 t1 left join
@@ -2743,32 +2745,36 @@ where t1.unique1 = 1;
27432745
Index Cond: (unique1 = 1)
27442746
-> Nested Loop
27452747
Join Filter: ((t1.ten + t2.ten) = t3.ten)
2746-
-> Index Scan using tenk1_hundred on tenk1 t2
2747-
Index Cond: (t1.hundred = hundred)
2748+
-> Bitmap Heap Scan on tenk1 t2
2749+
Recheck Cond: (t1.hundred = hundred)
2750+
-> Bitmap Index Scan on tenk1_hundred
2751+
Index Cond: (t1.hundred = hundred)
27482752
-> Index Scan using tenk1_unique2 on tenk1 t3
27492753
Index Cond: (unique2 = t2.thousand)
2750-
(9 rows)
2754+
(11 rows)
27512755

27522756
explain (costs off)
27532757
select count(*) from
27542758
tenk1 a join tenk1 b on a.unique1 = b.unique2
27552759
left join tenk1 c on a.unique2 = b.unique1 and c.thousand = a.thousand
27562760
join int4_tbl on b.thousand = f1;
2757-
QUERY PLAN
2758-
--------------------------------------------------------------------------
2761+
QUERY PLAN
2762+
-------------------------------------------------------------------------
27592763
Aggregate
27602764
-> Nested Loop Left Join
27612765
Join Filter: (a.unique2 = b.unique1)
27622766
-> Nested Loop
27632767
-> Nested Loop
27642768
-> Seq Scan on int4_tbl
2765-
-> Index Scan using tenk1_thous_tenthous on tenk1 b
2766-
Index Cond: (thousand = int4_tbl.f1)
2769+
-> Bitmap Heap Scan on tenk1 b
2770+
Recheck Cond: (thousand = int4_tbl.f1)
2771+
-> Bitmap Index Scan on tenk1_thous_tenthous
2772+
Index Cond: (thousand = int4_tbl.f1)
27672773
-> Index Scan using tenk1_unique1 on tenk1 a
27682774
Index Cond: (unique1 = b.unique2)
27692775
-> Index Only Scan using tenk1_thous_tenthous on tenk1 c
27702776
Index Cond: (thousand = a.thousand)
2771-
(12 rows)
2777+
(14 rows)
27722778

27732779
select count(*) from
27742780
tenk1 a join tenk1 b on a.unique1 = b.unique2

0 commit comments

Comments
 (0)