Skip to content

Commit 14c7fba

Browse files
committed
Rethink original decision to use AND/OR Expr nodes to represent bitmap
logic operations during planning. Seems cleaner to create two new Path node types, instead --- this avoids duplication of cost-estimation code. Also, create an enable_bitmapscan GUC parameter to control use of bitmap plans.
1 parent c6221db commit 14c7fba

File tree

16 files changed

+338
-193
lines changed

16 files changed

+338
-193
lines changed

doc/src/sgml/runtime.sgml

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.313 2005/04/08 00:59:57 neilc Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.314 2005/04/21 19:18:12 tgl Exp $
33
-->
44

55
<chapter Id="runtime">
@@ -1768,6 +1768,22 @@ archive_command = 'copy "%p" /mnt/server/archivedir/"%f"' # Windows
17681768
</para>
17691769

17701770
<variablelist>
1771+
<varlistentry id="guc-enable-bitmapscan" xreflabel="enable_bitmapscan">
1772+
<term><varname>enable_bitmapscan</varname> (<type>boolean</type>)</term>
1773+
<indexterm>
1774+
<primary>bitmap scan</primary>
1775+
</indexterm>
1776+
<indexterm>
1777+
<primary><varname>enable_bitmapscan</> configuration parameter</primary>
1778+
</indexterm>
1779+
<listitem>
1780+
<para>
1781+
Enables or disables the query planner's use of bitmap-scan plan
1782+
types. The default is on.
1783+
</para>
1784+
</listitem>
1785+
</varlistentry>
1786+
17711787
<varlistentry id="guc-enable-hashagg" xreflabel="enable_hashagg">
17721788
<term><varname>enable_hashagg</varname> (<type>boolean</type>)</term>
17731789
<indexterm>
@@ -4094,7 +4110,7 @@ plruby.bar = true # generates error, unknown class name
40944110

40954111
<row>
40964112
<entry>
4097-
<option>-fi</option>, <option>-fh</option>,
4113+
<option>-fb</option>, <option>-fh</option>, <option>-fi</option>,
40984114
<option>-fm</option>, <option>-fn</option>,
40994115
<option>-fs</option>, <option>-ft</option><footnote
41004116
id="fn.runtime-config-short">
@@ -4111,8 +4127,9 @@ $ <userinput>postmaster -o '-S 1024 -s'</userinput>
41114127
</footnote>
41124128
</entry>
41134129
<entry>
4114-
<literal>enable_indexscan = off</>,
4130+
<literal>enable_bitmapscan = off</>,
41154131
<literal>enable_hashjoin = off</>,
4132+
<literal>enable_indexscan = off</>,
41164133
<literal>enable_mergejoin = off</>,
41174134
<literal>enable_nestloop = off</>,
41184135
<literal>enable_seqscan = off</>,

src/backend/nodes/outfuncs.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.248 2005/04/21 02:28:01 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.249 2005/04/21 19:18:12 tgl Exp $
1212
*
1313
* NOTES
1414
* Every node type that can appear in stored rules' parsetrees *must*
@@ -1041,6 +1041,28 @@ _outBitmapHeapPath(StringInfo str, BitmapHeapPath *node)
10411041
WRITE_FLOAT_FIELD(rows, "%.0f");
10421042
}
10431043

1044+
static void
1045+
_outBitmapAndPath(StringInfo str, BitmapAndPath *node)
1046+
{
1047+
WRITE_NODE_TYPE("BITMAPANDPATH");
1048+
1049+
_outPathInfo(str, (Path *) node);
1050+
1051+
WRITE_NODE_FIELD(bitmapquals);
1052+
WRITE_FLOAT_FIELD(bitmapselectivity, "%.4f");
1053+
}
1054+
1055+
static void
1056+
_outBitmapOrPath(StringInfo str, BitmapOrPath *node)
1057+
{
1058+
WRITE_NODE_TYPE("BITMAPORPATH");
1059+
1060+
_outPathInfo(str, (Path *) node);
1061+
1062+
WRITE_NODE_FIELD(bitmapquals);
1063+
WRITE_FLOAT_FIELD(bitmapselectivity, "%.4f");
1064+
}
1065+
10441066
static void
10451067
_outTidPath(StringInfo str, TidPath *node)
10461068
{
@@ -1853,6 +1875,12 @@ _outNode(StringInfo str, void *obj)
18531875
case T_BitmapHeapPath:
18541876
_outBitmapHeapPath(str, obj);
18551877
break;
1878+
case T_BitmapAndPath:
1879+
_outBitmapAndPath(str, obj);
1880+
break;
1881+
case T_BitmapOrPath:
1882+
_outBitmapOrPath(str, obj);
1883+
break;
18561884
case T_TidPath:
18571885
_outTidPath(str, obj);
18581886
break;

src/backend/optimizer/README

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ RelOptInfo - a relation or joined relations
255255
Path - every way to generate a RelOptInfo(sequential,index,joins)
256256
SeqScan - a plain Path node with pathtype = T_SeqScan
257257
IndexPath - index scans
258+
BitmapHeapPath - top of a bitmapped index scan
258259
TidPath - scan by CTID
259260
AppendPath - append multiple subpaths together
260261
ResultPath - a Result plan node (used for variable-free tlist or qual)

src/backend/optimizer/path/allpaths.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.126 2005/04/19 22:35:15 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.127 2005/04/21 19:18:12 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -901,6 +901,12 @@ print_path(Query *root, Path *path, int indent)
901901
case T_BitmapHeapPath:
902902
ptype = "BitmapHeapScan";
903903
break;
904+
case T_BitmapAndPath:
905+
ptype = "BitmapAndPath";
906+
break;
907+
case T_BitmapOrPath:
908+
ptype = "BitmapOrPath";
909+
break;
904910
case T_TidPath:
905911
ptype = "TidScan";
906912
break;

src/backend/optimizer/path/costsize.c

Lines changed: 113 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
* Portions Copyright (c) 1994, Regents of the University of California
5050
*
5151
* IDENTIFICATION
52-
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.143 2005/04/21 02:28:01 tgl Exp $
52+
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.144 2005/04/21 19:18:12 tgl Exp $
5353
*
5454
*-------------------------------------------------------------------------
5555
*/
@@ -94,6 +94,7 @@ Cost disable_cost = 100000000.0;
9494

9595
bool enable_seqscan = true;
9696
bool enable_indexscan = true;
97+
bool enable_bitmapscan = true;
9798
bool enable_tidscan = true;
9899
bool enable_sort = true;
99100
bool enable_hashagg = true;
@@ -103,7 +104,7 @@ bool enable_hashjoin = true;
103104

104105

105106
static bool cost_qual_eval_walker(Node *node, QualCost *total);
106-
static Selectivity cost_bitmap_qual(Node *bitmapqual, Cost *totalCost);
107+
static void cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec);
107108
static Selectivity approx_selectivity(Query *root, List *quals,
108109
JoinType jointype);
109110
static Selectivity join_in_selectivity(JoinPath *path, Query *root);
@@ -292,7 +293,7 @@ cost_index(IndexPath *path, Query *root,
292293
PointerGetDatum(&indexCorrelation));
293294

294295
/*
295-
* Save amcostestimate's results for possible use by cost_bitmap_scan.
296+
* Save amcostestimate's results for possible use in bitmap scan planning.
296297
* We don't bother to save indexStartupCost or indexCorrelation, because
297298
* a bitmap scan doesn't care about either.
298299
*/
@@ -414,19 +415,19 @@ cost_index(IndexPath *path, Query *root,
414415
}
415416

416417
/*
417-
* cost_bitmap_scan
418+
* cost_bitmap_heap_scan
418419
* Determines and returns the cost of scanning a relation using a bitmap
419420
* index-then-heap plan.
420421
*
421422
* 'root' is the query root
422423
* 'baserel' is the relation to be scanned
423-
* 'bitmapqual' is an AND/OR tree of IndexPaths for the component scans
424+
* 'bitmapqual' is a tree of IndexPaths, BitmapAndPaths, and BitmapOrPaths
424425
* 'is_injoin' is T if we are considering using the scan as the inside
425426
* of a nestloop join (hence, some of the quals are join clauses)
426427
*/
427428
void
428-
cost_bitmap_scan(Path *path, Query *root, RelOptInfo *baserel,
429-
Node *bitmapqual, bool is_injoin)
429+
cost_bitmap_heap_scan(Path *path, Query *root, RelOptInfo *baserel,
430+
Path *bitmapqual, bool is_injoin)
430431
{
431432
Cost startup_cost = 0;
432433
Cost run_cost = 0;
@@ -443,15 +444,14 @@ cost_bitmap_scan(Path *path, Query *root, RelOptInfo *baserel,
443444
Assert(baserel->relid > 0);
444445
Assert(baserel->rtekind == RTE_RELATION);
445446

446-
if (!enable_indexscan) /* XXX use a separate enable flag? */
447+
if (!enable_bitmapscan)
447448
startup_cost += disable_cost;
448449

449450
/*
450-
* Estimate total cost of obtaining the bitmap, as well as its total
451+
* Fetch total cost of obtaining the bitmap, as well as its total
451452
* selectivity.
452453
*/
453-
indexTotalCost = 0;
454-
indexSelectivity = cost_bitmap_qual(bitmapqual, &indexTotalCost);
454+
cost_bitmap_tree_node(bitmapqual, &indexTotalCost, &indexSelectivity);
455455

456456
startup_cost += indexTotalCost;
457457

@@ -497,82 +497,120 @@ cost_bitmap_scan(Path *path, Query *root, RelOptInfo *baserel,
497497
}
498498

499499
/*
500-
* cost_bitmap_qual
501-
* Recursively examine the AND/OR/IndexPath tree for a bitmap scan
502-
*
503-
* Total execution costs are added to *totalCost (so caller must be sure
504-
* to initialize that to zero). Estimated total selectivity of the bitmap
505-
* is returned as the function result.
500+
* cost_bitmap_tree_node
501+
* Extract cost and selectivity from a bitmap tree node (index/and/or)
506502
*/
507-
static Selectivity
508-
cost_bitmap_qual(Node *bitmapqual, Cost *totalCost)
503+
static void
504+
cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec)
509505
{
510-
Selectivity result;
511-
Selectivity subresult;
512-
ListCell *l;
513-
514-
if (and_clause(bitmapqual))
506+
if (IsA(path, IndexPath))
515507
{
516-
/*
517-
* We estimate AND selectivity on the assumption that the inputs
518-
* are independent. This is probably often wrong, but we don't
519-
* have the info to do better.
520-
*
521-
* The runtime cost of the BitmapAnd itself is estimated at 100x
522-
* cpu_operator_cost for each tbm_intersect needed. Probably too
523-
* small, definitely too simplistic?
524-
*
525-
* This must agree with make_bitmap_and in createplan.c.
526-
*/
527-
result = 1.0;
528-
foreach(l, ((BoolExpr *) bitmapqual)->args)
529-
{
530-
subresult = cost_bitmap_qual((Node *) lfirst(l), totalCost);
531-
result *= subresult;
532-
if (l != list_head(((BoolExpr *) bitmapqual)->args))
533-
*totalCost += 100.0 * cpu_operator_cost;
534-
}
508+
*cost = ((IndexPath *) path)->indextotalcost;
509+
*selec = ((IndexPath *) path)->indexselectivity;
535510
}
536-
else if (or_clause(bitmapqual))
511+
else if (IsA(path, BitmapAndPath))
537512
{
538-
/*
539-
* We estimate OR selectivity on the assumption that the inputs
540-
* are non-overlapping, since that's often the case in "x IN (list)"
541-
* type situations. Of course, we clamp to 1.0 at the end.
542-
*
543-
* The runtime cost of the BitmapOr itself is estimated at 100x
544-
* cpu_operator_cost for each tbm_union needed. Probably too
545-
* small, definitely too simplistic? We are aware that the tbm_unions
546-
* are optimized out when the inputs are BitmapIndexScans.
547-
*
548-
* This must agree with make_bitmap_or in createplan.c.
549-
*/
550-
result = 0.0;
551-
foreach(l, ((BoolExpr *) bitmapqual)->args)
552-
{
553-
subresult = cost_bitmap_qual((Node *) lfirst(l), totalCost);
554-
result += subresult;
555-
if (l != list_head(((BoolExpr *) bitmapqual)->args) &&
556-
!IsA((Node *) lfirst(l), IndexPath))
557-
*totalCost += 100.0 * cpu_operator_cost;
558-
}
559-
result = Min(result, 1.0);
513+
*cost = path->total_cost;
514+
*selec = ((BitmapAndPath *) path)->bitmapselectivity;
560515
}
561-
else if (IsA(bitmapqual, IndexPath))
516+
else if (IsA(path, BitmapOrPath))
562517
{
563-
IndexPath *ipath = (IndexPath *) bitmapqual;
564-
565-
/* this must agree with create_bitmap_subplan in createplan.c */
566-
*totalCost += ipath->indextotalcost;
567-
result = ipath->indexselectivity;
518+
*cost = path->total_cost;
519+
*selec = ((BitmapOrPath *) path)->bitmapselectivity;
568520
}
569521
else
522+
elog(ERROR, "unrecognized node type: %d", nodeTag(path));
523+
}
524+
525+
/*
526+
* cost_bitmap_and_node
527+
* Estimate the cost of a BitmapAnd node
528+
*
529+
* Note that this considers only the costs of index scanning and bitmap
530+
* creation, not the eventual heap access. In that sense the object isn't
531+
* truly a Path, but it has enough path-like properties (costs in particular)
532+
* to warrant treating it as one.
533+
*/
534+
void
535+
cost_bitmap_and_node(BitmapAndPath *path, Query *root)
536+
{
537+
Cost totalCost;
538+
Selectivity selec;
539+
ListCell *l;
540+
541+
/*
542+
* We estimate AND selectivity on the assumption that the inputs
543+
* are independent. This is probably often wrong, but we don't
544+
* have the info to do better.
545+
*
546+
* The runtime cost of the BitmapAnd itself is estimated at 100x
547+
* cpu_operator_cost for each tbm_intersect needed. Probably too
548+
* small, definitely too simplistic?
549+
*/
550+
totalCost = 0.0;
551+
selec = 1.0;
552+
foreach(l, path->bitmapquals)
570553
{
571-
elog(ERROR, "unrecognized node type: %d", nodeTag(bitmapqual));
572-
result = 0.0; /* keep compiler quiet */
554+
Path *subpath = (Path *) lfirst(l);
555+
Cost subCost;
556+
Selectivity subselec;
557+
558+
cost_bitmap_tree_node(subpath, &subCost, &subselec);
559+
560+
selec *= subselec;
561+
562+
totalCost += subCost;
563+
if (l != list_head(path->bitmapquals))
564+
totalCost += 100.0 * cpu_operator_cost;
573565
}
566+
path->bitmapselectivity = selec;
567+
path->path.startup_cost = totalCost;
568+
path->path.total_cost = totalCost;
569+
}
570+
571+
/*
572+
* cost_bitmap_or_node
573+
* Estimate the cost of a BitmapOr node
574+
*
575+
* See comments for cost_bitmap_and_node.
576+
*/
577+
void
578+
cost_bitmap_or_node(BitmapOrPath *path, Query *root)
579+
{
580+
Cost totalCost;
581+
Selectivity selec;
582+
ListCell *l;
583+
584+
/*
585+
* We estimate OR selectivity on the assumption that the inputs
586+
* are non-overlapping, since that's often the case in "x IN (list)"
587+
* type situations. Of course, we clamp to 1.0 at the end.
588+
*
589+
* The runtime cost of the BitmapOr itself is estimated at 100x
590+
* cpu_operator_cost for each tbm_union needed. Probably too
591+
* small, definitely too simplistic? We are aware that the tbm_unions
592+
* are optimized out when the inputs are BitmapIndexScans.
593+
*/
594+
totalCost = 0.0;
595+
selec = 0.0;
596+
foreach(l, path->bitmapquals)
597+
{
598+
Path *subpath = (Path *) lfirst(l);
599+
Cost subCost;
600+
Selectivity subselec;
574601

575-
return result;
602+
cost_bitmap_tree_node(subpath, &subCost, &subselec);
603+
604+
selec += subselec;
605+
606+
totalCost += subCost;
607+
if (l != list_head(path->bitmapquals) &&
608+
!IsA(subpath, IndexPath))
609+
totalCost += 100.0 * cpu_operator_cost;
610+
}
611+
path->bitmapselectivity = Min(selec, 1.0);
612+
path->path.startup_cost = totalCost;
613+
path->path.total_cost = totalCost;
576614
}
577615

578616
/*

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