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

Lines changed: 82 additions & 16 deletions
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

Lines changed: 17 additions & 11 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy