Commit 14c7fba3 authored by Tom Lane's avatar Tom Lane

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.
parent c6221db3
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.313 2005/04/08 00:59:57 neilc Exp $ $PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.314 2005/04/21 19:18:12 tgl Exp $
--> -->
<chapter Id="runtime"> <chapter Id="runtime">
...@@ -1768,6 +1768,22 @@ archive_command = 'copy "%p" /mnt/server/archivedir/"%f"' # Windows ...@@ -1768,6 +1768,22 @@ archive_command = 'copy "%p" /mnt/server/archivedir/"%f"' # Windows
</para> </para>
<variablelist> <variablelist>
<varlistentry id="guc-enable-bitmapscan" xreflabel="enable_bitmapscan">
<term><varname>enable_bitmapscan</varname> (<type>boolean</type>)</term>
<indexterm>
<primary>bitmap scan</primary>
</indexterm>
<indexterm>
<primary><varname>enable_bitmapscan</> configuration parameter</primary>
</indexterm>
<listitem>
<para>
Enables or disables the query planner's use of bitmap-scan plan
types. The default is on.
</para>
</listitem>
</varlistentry>
<varlistentry id="guc-enable-hashagg" xreflabel="enable_hashagg"> <varlistentry id="guc-enable-hashagg" xreflabel="enable_hashagg">
<term><varname>enable_hashagg</varname> (<type>boolean</type>)</term> <term><varname>enable_hashagg</varname> (<type>boolean</type>)</term>
<indexterm> <indexterm>
...@@ -4094,7 +4110,7 @@ plruby.bar = true # generates error, unknown class name ...@@ -4094,7 +4110,7 @@ plruby.bar = true # generates error, unknown class name
<row> <row>
<entry> <entry>
<option>-fi</option>, <option>-fh</option>, <option>-fb</option>, <option>-fh</option>, <option>-fi</option>,
<option>-fm</option>, <option>-fn</option>, <option>-fm</option>, <option>-fn</option>,
<option>-fs</option>, <option>-ft</option><footnote <option>-fs</option>, <option>-ft</option><footnote
id="fn.runtime-config-short"> id="fn.runtime-config-short">
...@@ -4111,8 +4127,9 @@ $ <userinput>postmaster -o '-S 1024 -s'</userinput> ...@@ -4111,8 +4127,9 @@ $ <userinput>postmaster -o '-S 1024 -s'</userinput>
</footnote> </footnote>
</entry> </entry>
<entry> <entry>
<literal>enable_indexscan = off</>, <literal>enable_bitmapscan = off</>,
<literal>enable_hashjoin = off</>, <literal>enable_hashjoin = off</>,
<literal>enable_indexscan = off</>,
<literal>enable_mergejoin = off</>, <literal>enable_mergejoin = off</>,
<literal>enable_nestloop = off</>, <literal>enable_nestloop = off</>,
<literal>enable_seqscan = off</>, <literal>enable_seqscan = off</>,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.248 2005/04/21 02:28:01 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.249 2005/04/21 19:18:12 tgl Exp $
* *
* NOTES * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
...@@ -1041,6 +1041,28 @@ _outBitmapHeapPath(StringInfo str, BitmapHeapPath *node) ...@@ -1041,6 +1041,28 @@ _outBitmapHeapPath(StringInfo str, BitmapHeapPath *node)
WRITE_FLOAT_FIELD(rows, "%.0f"); WRITE_FLOAT_FIELD(rows, "%.0f");
} }
static void
_outBitmapAndPath(StringInfo str, BitmapAndPath *node)
{
WRITE_NODE_TYPE("BITMAPANDPATH");
_outPathInfo(str, (Path *) node);
WRITE_NODE_FIELD(bitmapquals);
WRITE_FLOAT_FIELD(bitmapselectivity, "%.4f");
}
static void
_outBitmapOrPath(StringInfo str, BitmapOrPath *node)
{
WRITE_NODE_TYPE("BITMAPORPATH");
_outPathInfo(str, (Path *) node);
WRITE_NODE_FIELD(bitmapquals);
WRITE_FLOAT_FIELD(bitmapselectivity, "%.4f");
}
static void static void
_outTidPath(StringInfo str, TidPath *node) _outTidPath(StringInfo str, TidPath *node)
{ {
...@@ -1853,6 +1875,12 @@ _outNode(StringInfo str, void *obj) ...@@ -1853,6 +1875,12 @@ _outNode(StringInfo str, void *obj)
case T_BitmapHeapPath: case T_BitmapHeapPath:
_outBitmapHeapPath(str, obj); _outBitmapHeapPath(str, obj);
break; break;
case T_BitmapAndPath:
_outBitmapAndPath(str, obj);
break;
case T_BitmapOrPath:
_outBitmapOrPath(str, obj);
break;
case T_TidPath: case T_TidPath:
_outTidPath(str, obj); _outTidPath(str, obj);
break; break;
......
...@@ -255,6 +255,7 @@ RelOptInfo - a relation or joined relations ...@@ -255,6 +255,7 @@ RelOptInfo - a relation or joined relations
Path - every way to generate a RelOptInfo(sequential,index,joins) Path - every way to generate a RelOptInfo(sequential,index,joins)
SeqScan - a plain Path node with pathtype = T_SeqScan SeqScan - a plain Path node with pathtype = T_SeqScan
IndexPath - index scans IndexPath - index scans
BitmapHeapPath - top of a bitmapped index scan
TidPath - scan by CTID TidPath - scan by CTID
AppendPath - append multiple subpaths together AppendPath - append multiple subpaths together
ResultPath - a Result plan node (used for variable-free tlist or qual) ResultPath - a Result plan node (used for variable-free tlist or qual)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.126 2005/04/19 22:35:15 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.127 2005/04/21 19:18:12 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -901,6 +901,12 @@ print_path(Query *root, Path *path, int indent) ...@@ -901,6 +901,12 @@ print_path(Query *root, Path *path, int indent)
case T_BitmapHeapPath: case T_BitmapHeapPath:
ptype = "BitmapHeapScan"; ptype = "BitmapHeapScan";
break; break;
case T_BitmapAndPath:
ptype = "BitmapAndPath";
break;
case T_BitmapOrPath:
ptype = "BitmapOrPath";
break;
case T_TidPath: case T_TidPath:
ptype = "TidScan"; ptype = "TidScan";
break; break;
......
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.143 2005/04/21 02:28:01 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.144 2005/04/21 19:18:12 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -94,6 +94,7 @@ Cost disable_cost = 100000000.0; ...@@ -94,6 +94,7 @@ Cost disable_cost = 100000000.0;
bool enable_seqscan = true; bool enable_seqscan = true;
bool enable_indexscan = true; bool enable_indexscan = true;
bool enable_bitmapscan = true;
bool enable_tidscan = true; bool enable_tidscan = true;
bool enable_sort = true; bool enable_sort = true;
bool enable_hashagg = true; bool enable_hashagg = true;
...@@ -103,7 +104,7 @@ bool enable_hashjoin = true; ...@@ -103,7 +104,7 @@ bool enable_hashjoin = true;
static bool cost_qual_eval_walker(Node *node, QualCost *total); static bool cost_qual_eval_walker(Node *node, QualCost *total);
static Selectivity cost_bitmap_qual(Node *bitmapqual, Cost *totalCost); static void cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec);
static Selectivity approx_selectivity(Query *root, List *quals, static Selectivity approx_selectivity(Query *root, List *quals,
JoinType jointype); JoinType jointype);
static Selectivity join_in_selectivity(JoinPath *path, Query *root); static Selectivity join_in_selectivity(JoinPath *path, Query *root);
...@@ -292,7 +293,7 @@ cost_index(IndexPath *path, Query *root, ...@@ -292,7 +293,7 @@ cost_index(IndexPath *path, Query *root,
PointerGetDatum(&indexCorrelation)); PointerGetDatum(&indexCorrelation));
/* /*
* Save amcostestimate's results for possible use by cost_bitmap_scan. * Save amcostestimate's results for possible use in bitmap scan planning.
* We don't bother to save indexStartupCost or indexCorrelation, because * We don't bother to save indexStartupCost or indexCorrelation, because
* a bitmap scan doesn't care about either. * a bitmap scan doesn't care about either.
*/ */
...@@ -414,19 +415,19 @@ cost_index(IndexPath *path, Query *root, ...@@ -414,19 +415,19 @@ cost_index(IndexPath *path, Query *root,
} }
/* /*
* cost_bitmap_scan * cost_bitmap_heap_scan
* Determines and returns the cost of scanning a relation using a bitmap * Determines and returns the cost of scanning a relation using a bitmap
* index-then-heap plan. * index-then-heap plan.
* *
* 'root' is the query root * 'root' is the query root
* 'baserel' is the relation to be scanned * 'baserel' is the relation to be scanned
* 'bitmapqual' is an AND/OR tree of IndexPaths for the component scans * 'bitmapqual' is a tree of IndexPaths, BitmapAndPaths, and BitmapOrPaths
* 'is_injoin' is T if we are considering using the scan as the inside * 'is_injoin' is T if we are considering using the scan as the inside
* of a nestloop join (hence, some of the quals are join clauses) * of a nestloop join (hence, some of the quals are join clauses)
*/ */
void void
cost_bitmap_scan(Path *path, Query *root, RelOptInfo *baserel, cost_bitmap_heap_scan(Path *path, Query *root, RelOptInfo *baserel,
Node *bitmapqual, bool is_injoin) Path *bitmapqual, bool is_injoin)
{ {
Cost startup_cost = 0; Cost startup_cost = 0;
Cost run_cost = 0; Cost run_cost = 0;
...@@ -443,15 +444,14 @@ cost_bitmap_scan(Path *path, Query *root, RelOptInfo *baserel, ...@@ -443,15 +444,14 @@ cost_bitmap_scan(Path *path, Query *root, RelOptInfo *baserel,
Assert(baserel->relid > 0); Assert(baserel->relid > 0);
Assert(baserel->rtekind == RTE_RELATION); Assert(baserel->rtekind == RTE_RELATION);
if (!enable_indexscan) /* XXX use a separate enable flag? */ if (!enable_bitmapscan)
startup_cost += disable_cost; startup_cost += disable_cost;
/* /*
* Estimate total cost of obtaining the bitmap, as well as its total * Fetch total cost of obtaining the bitmap, as well as its total
* selectivity. * selectivity.
*/ */
indexTotalCost = 0; cost_bitmap_tree_node(bitmapqual, &indexTotalCost, &indexSelectivity);
indexSelectivity = cost_bitmap_qual(bitmapqual, &indexTotalCost);
startup_cost += indexTotalCost; startup_cost += indexTotalCost;
...@@ -497,22 +497,47 @@ cost_bitmap_scan(Path *path, Query *root, RelOptInfo *baserel, ...@@ -497,22 +497,47 @@ cost_bitmap_scan(Path *path, Query *root, RelOptInfo *baserel,
} }
/* /*
* cost_bitmap_qual * cost_bitmap_tree_node
* Recursively examine the AND/OR/IndexPath tree for a bitmap scan * Extract cost and selectivity from a bitmap tree node (index/and/or)
*/
static void
cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec)
{
if (IsA(path, IndexPath))
{
*cost = ((IndexPath *) path)->indextotalcost;
*selec = ((IndexPath *) path)->indexselectivity;
}
else if (IsA(path, BitmapAndPath))
{
*cost = path->total_cost;
*selec = ((BitmapAndPath *) path)->bitmapselectivity;
}
else if (IsA(path, BitmapOrPath))
{
*cost = path->total_cost;
*selec = ((BitmapOrPath *) path)->bitmapselectivity;
}
else
elog(ERROR, "unrecognized node type: %d", nodeTag(path));
}
/*
* cost_bitmap_and_node
* Estimate the cost of a BitmapAnd node
* *
* Total execution costs are added to *totalCost (so caller must be sure * Note that this considers only the costs of index scanning and bitmap
* to initialize that to zero). Estimated total selectivity of the bitmap * creation, not the eventual heap access. In that sense the object isn't
* is returned as the function result. * truly a Path, but it has enough path-like properties (costs in particular)
* to warrant treating it as one.
*/ */
static Selectivity void
cost_bitmap_qual(Node *bitmapqual, Cost *totalCost) cost_bitmap_and_node(BitmapAndPath *path, Query *root)
{ {
Selectivity result; Cost totalCost;
Selectivity subresult; Selectivity selec;
ListCell *l; ListCell *l;
if (and_clause(bitmapqual))
{
/* /*
* We estimate AND selectivity on the assumption that the inputs * We estimate AND selectivity on the assumption that the inputs
* are independent. This is probably often wrong, but we don't * are independent. This is probably often wrong, but we don't
...@@ -521,20 +546,41 @@ cost_bitmap_qual(Node *bitmapqual, Cost *totalCost) ...@@ -521,20 +546,41 @@ cost_bitmap_qual(Node *bitmapqual, Cost *totalCost)
* The runtime cost of the BitmapAnd itself is estimated at 100x * The runtime cost of the BitmapAnd itself is estimated at 100x
* cpu_operator_cost for each tbm_intersect needed. Probably too * cpu_operator_cost for each tbm_intersect needed. Probably too
* small, definitely too simplistic? * small, definitely too simplistic?
*
* This must agree with make_bitmap_and in createplan.c.
*/ */
result = 1.0; totalCost = 0.0;
foreach(l, ((BoolExpr *) bitmapqual)->args) selec = 1.0;
foreach(l, path->bitmapquals)
{ {
subresult = cost_bitmap_qual((Node *) lfirst(l), totalCost); Path *subpath = (Path *) lfirst(l);
result *= subresult; Cost subCost;
if (l != list_head(((BoolExpr *) bitmapqual)->args)) Selectivity subselec;
*totalCost += 100.0 * cpu_operator_cost;
} cost_bitmap_tree_node(subpath, &subCost, &subselec);
selec *= subselec;
totalCost += subCost;
if (l != list_head(path->bitmapquals))
totalCost += 100.0 * cpu_operator_cost;
} }
else if (or_clause(bitmapqual)) path->bitmapselectivity = selec;
{ path->path.startup_cost = totalCost;
path->path.total_cost = totalCost;
}
/*
* cost_bitmap_or_node
* Estimate the cost of a BitmapOr node
*
* See comments for cost_bitmap_and_node.
*/
void
cost_bitmap_or_node(BitmapOrPath *path, Query *root)
{
Cost totalCost;
Selectivity selec;
ListCell *l;
/* /*
* We estimate OR selectivity on the assumption that the inputs * We estimate OR selectivity on the assumption that the inputs
* are non-overlapping, since that's often the case in "x IN (list)" * are non-overlapping, since that's often the case in "x IN (list)"
...@@ -544,35 +590,27 @@ cost_bitmap_qual(Node *bitmapqual, Cost *totalCost) ...@@ -544,35 +590,27 @@ cost_bitmap_qual(Node *bitmapqual, Cost *totalCost)
* cpu_operator_cost for each tbm_union needed. Probably too * cpu_operator_cost for each tbm_union needed. Probably too
* small, definitely too simplistic? We are aware that the tbm_unions * small, definitely too simplistic? We are aware that the tbm_unions
* are optimized out when the inputs are BitmapIndexScans. * are optimized out when the inputs are BitmapIndexScans.
*
* This must agree with make_bitmap_or in createplan.c.
*/ */
result = 0.0; totalCost = 0.0;
foreach(l, ((BoolExpr *) bitmapqual)->args) selec = 0.0;
foreach(l, path->bitmapquals)
{ {
subresult = cost_bitmap_qual((Node *) lfirst(l), totalCost); Path *subpath = (Path *) lfirst(l);
result += subresult; Cost subCost;
if (l != list_head(((BoolExpr *) bitmapqual)->args) && Selectivity subselec;
!IsA((Node *) lfirst(l), IndexPath))
*totalCost += 100.0 * cpu_operator_cost;
}
result = Min(result, 1.0);
}
else if (IsA(bitmapqual, IndexPath))
{
IndexPath *ipath = (IndexPath *) bitmapqual;
/* this must agree with create_bitmap_subplan in createplan.c */ cost_bitmap_tree_node(subpath, &subCost, &subselec);
*totalCost += ipath->indextotalcost;
result = ipath->indexselectivity;
}
else
{
elog(ERROR, "unrecognized node type: %d", nodeTag(bitmapqual));
result = 0.0; /* keep compiler quiet */
}
return result; selec += subselec;
totalCost += subCost;
if (l != list_head(path->bitmapquals) &&
!IsA(subpath, IndexPath))
totalCost += 100.0 * cpu_operator_cost;
}
path->bitmapselectivity = Min(selec, 1.0);
path->path.startup_cost = totalCost;
path->path.total_cost = totalCost;
} }
/* /*
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.181 2005/04/21 02:28:01 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.182 2005/04/21 19:18:12 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -51,9 +51,9 @@ static IndexScan *create_indexscan_plan(Query *root, IndexPath *best_path, ...@@ -51,9 +51,9 @@ static IndexScan *create_indexscan_plan(Query *root, IndexPath *best_path,
static BitmapHeapScan *create_bitmap_scan_plan(Query *root, static BitmapHeapScan *create_bitmap_scan_plan(Query *root,
BitmapHeapPath *best_path, BitmapHeapPath *best_path,
List *tlist, List *scan_clauses); List *tlist, List *scan_clauses);
static Plan *create_bitmap_subplan(Query *root, Node *bitmapqual); static Plan *create_bitmap_subplan(Query *root, Path *bitmapqual);
static List *create_bitmap_qual(Node *bitmapqual); static List *create_bitmap_qual(Path *bitmapqual);
static List *create_bitmap_indxqual(Node *bitmapqual); static List *create_bitmap_indxqual(Path *bitmapqual);
static TidScan *create_tidscan_plan(Query *root, TidPath *best_path, static TidScan *create_tidscan_plan(Query *root, TidPath *best_path,
List *tlist, List *scan_clauses); List *tlist, List *scan_clauses);
static SubqueryScan *create_subqueryscan_plan(Query *root, Path *best_path, static SubqueryScan *create_subqueryscan_plan(Query *root, Path *best_path,
...@@ -928,37 +928,41 @@ create_bitmap_scan_plan(Query *root, ...@@ -928,37 +928,41 @@ create_bitmap_scan_plan(Query *root,
* Given a bitmapqual tree, generate the Plan tree that implements it * Given a bitmapqual tree, generate the Plan tree that implements it
*/ */
static Plan * static Plan *
create_bitmap_subplan(Query *root, Node *bitmapqual) create_bitmap_subplan(Query *root, Path *bitmapqual)
{ {
Plan *plan; Plan *plan;
Plan *subplan;
if (bitmapqual == NULL) if (IsA(bitmapqual, BitmapAndPath))
return NULL; /* probably can't happen */
if (IsA(bitmapqual, List))
{ {
/* this case is to handle the List arguments of AND/OR */ BitmapAndPath *apath = (BitmapAndPath *) bitmapqual;
List *newlist = NIL; List *newlist = NIL;
ListCell *l; ListCell *l;
foreach(l, (List *) bitmapqual) foreach(l, apath->bitmapquals)
{ {
subplan = create_bitmap_subplan(root, lfirst(l)); Plan *subplan = create_bitmap_subplan(root, lfirst(l));
newlist = lappend(newlist, subplan); newlist = lappend(newlist, subplan);
} }
plan = (Plan *) newlist; plan = (Plan *) make_bitmap_and(newlist);
copy_path_costsize(plan, bitmapqual);
plan->plan_width = 0; /* meaningless */
} }
else if (and_clause(bitmapqual)) else if (IsA(bitmapqual, BitmapOrPath))
{ {
subplan = create_bitmap_subplan(root, BitmapOrPath *opath = (BitmapOrPath *) bitmapqual;
(Node *) ((BoolExpr *) bitmapqual)->args); List *newlist = NIL;
plan = (Plan *) make_bitmap_and((List *) subplan); ListCell *l;
}
else if (or_clause(bitmapqual)) foreach(l, opath->bitmapquals)
{ {
subplan = create_bitmap_subplan(root, Plan *subplan = create_bitmap_subplan(root, lfirst(l));
(Node *) ((BoolExpr *) bitmapqual)->args);
plan = (Plan *) make_bitmap_or((List *) subplan); newlist = lappend(newlist, subplan);
}
plan = (Plan *) make_bitmap_or(newlist);
copy_path_costsize(plan, bitmapqual);
plan->plan_width = 0; /* meaningless */
} }
else if (IsA(bitmapqual, IndexPath)) else if (IsA(bitmapqual, IndexPath))
{ {
...@@ -976,7 +980,6 @@ create_bitmap_subplan(Query *root, Node *bitmapqual) ...@@ -976,7 +980,6 @@ create_bitmap_subplan(Query *root, Node *bitmapqual)
linitial(iscan->indxqualorig), linitial(iscan->indxqualorig),
linitial(iscan->indxstrategy), linitial(iscan->indxstrategy),
linitial(iscan->indxsubtype)); linitial(iscan->indxsubtype));
/* this must agree with cost_bitmap_qual in costsize.c */
bscan->scan.plan.startup_cost = 0.0; bscan->scan.plan.startup_cost = 0.0;
bscan->scan.plan.total_cost = ipath->indextotalcost; bscan->scan.plan.total_cost = ipath->indextotalcost;
bscan->scan.plan.plan_rows = bscan->scan.plan.plan_rows =
...@@ -999,28 +1002,30 @@ create_bitmap_subplan(Query *root, Node *bitmapqual) ...@@ -999,28 +1002,30 @@ create_bitmap_subplan(Query *root, Node *bitmapqual)
* The result is expressed as an implicit-AND list. * The result is expressed as an implicit-AND list.
*/ */
static List * static List *
create_bitmap_qual(Node *bitmapqual) create_bitmap_qual(Path *bitmapqual)
{ {
List *result; List *result;
List *sublist; List *sublist;
if (and_clause(bitmapqual)) if (IsA(bitmapqual, BitmapAndPath))
{ {
BitmapAndPath *apath = (BitmapAndPath *) bitmapqual;
ListCell *l; ListCell *l;
result = NIL; result = NIL;
foreach(l, ((BoolExpr *) bitmapqual)->args) foreach(l, apath->bitmapquals)
{ {
sublist = create_bitmap_qual(lfirst(l)); sublist = create_bitmap_qual(lfirst(l));
result = list_concat(result, sublist); result = list_concat(result, sublist);
} }
} }
else if (or_clause(bitmapqual)) else if (IsA(bitmapqual, BitmapOrPath))
{ {
BitmapOrPath *opath = (BitmapOrPath *) bitmapqual;
List *newlist = NIL; List *newlist = NIL;
ListCell *l; ListCell *l;
foreach(l, ((BoolExpr *) bitmapqual)->args) foreach(l, opath->bitmapquals)
{ {
sublist = create_bitmap_qual(lfirst(l)); sublist = create_bitmap_qual(lfirst(l));
if (sublist == NIL) if (sublist == NIL)
...@@ -1056,26 +1061,29 @@ create_bitmap_qual(Node *bitmapqual) ...@@ -1056,26 +1061,29 @@ create_bitmap_qual(Node *bitmapqual)
* to enforce, which may be weaker than the original qual expressions. * to enforce, which may be weaker than the original qual expressions.
*/ */
static List * static List *
create_bitmap_indxqual(Node *bitmapqual) create_bitmap_indxqual(Path *bitmapqual)
{ {
List *result; List *result;
List *sublist; List *sublist;
ListCell *l; ListCell *l;
if (and_clause(bitmapqual)) if (IsA(bitmapqual, BitmapAndPath))
{ {
BitmapAndPath *apath = (BitmapAndPath *) bitmapqual;
result = NIL; result = NIL;
foreach(l, ((BoolExpr *) bitmapqual)->args) foreach(l, apath->bitmapquals)
{ {
sublist = create_bitmap_indxqual(lfirst(l)); sublist = create_bitmap_indxqual(lfirst(l));
result = list_concat(result, sublist); result = list_concat(result, sublist);
} }
} }
else if (or_clause(bitmapqual)) else if (IsA(bitmapqual, BitmapOrPath))
{ {
BitmapOrPath *opath = (BitmapOrPath *) bitmapqual;
List *newlist = NIL; List *newlist = NIL;
foreach(l, ((BoolExpr *) bitmapqual)->args) foreach(l, opath->bitmapquals)
{ {
sublist = create_bitmap_indxqual(lfirst(l)); sublist = create_bitmap_indxqual(lfirst(l));
if (sublist == NIL) if (sublist == NIL)
...@@ -2067,34 +2075,8 @@ make_bitmap_and(List *bitmapplans) ...@@ -2067,34 +2075,8 @@ make_bitmap_and(List *bitmapplans)
{ {
BitmapAnd *node = makeNode(BitmapAnd); BitmapAnd *node = makeNode(BitmapAnd);
Plan *plan = &node->plan; Plan *plan = &node->plan;
ListCell *subnode;
/*
* Compute cost as sum of subplan costs, plus 100x cpu_operator_cost
* (a pretty arbitrary amount, agreed) for each tbm_intersect needed.
* This must agree with cost_bitmap_qual in costsize.c.
*/
plan->startup_cost = 0;
plan->total_cost = 0;
plan->plan_rows = 0;
plan->plan_width = 0; /* meaningless */
foreach(subnode, bitmapplans)
{
Plan *subplan = (Plan *) lfirst(subnode);
if (subnode == list_head(bitmapplans)) /* first node? */
{
plan->startup_cost = subplan->startup_cost;
plan->plan_rows = subplan->plan_rows;
}
else
{
plan->total_cost += cpu_operator_cost * 100.0;
plan->plan_rows = Min(plan->plan_rows, subplan->plan_rows);
}
plan->total_cost += subplan->total_cost;
}
/* cost should be inserted by caller */
plan->targetlist = NIL; plan->targetlist = NIL;
plan->qual = NIL; plan->qual = NIL;
plan->lefttree = NULL; plan->lefttree = NULL;
...@@ -2109,32 +2091,8 @@ make_bitmap_or(List *bitmapplans) ...@@ -2109,32 +2091,8 @@ make_bitmap_or(List *bitmapplans)
{ {
BitmapOr *node = makeNode(BitmapOr); BitmapOr *node = makeNode(BitmapOr);
Plan *plan = &node->plan; Plan *plan = &node->plan;
ListCell *subnode;
/*
* Compute cost as sum of subplan costs, plus 100x cpu_operator_cost
* (a pretty arbitrary amount, agreed) for each tbm_union needed.
* We assume that tbm_union can be optimized away for BitmapIndexScan
* subplans.
*
* This must agree with cost_bitmap_qual in costsize.c.
*/
plan->startup_cost = 0;
plan->total_cost = 0;
plan->plan_rows = 0;
plan->plan_width = 0; /* meaningless */
foreach(subnode, bitmapplans)
{
Plan *subplan = (Plan *) lfirst(subnode);
if (subnode == list_head(bitmapplans)) /* first node? */
plan->startup_cost = subplan->startup_cost;
else if (!IsA(subplan, BitmapIndexScan))
plan->total_cost += cpu_operator_cost * 100.0;
plan->total_cost += subplan->total_cost;
plan->plan_rows += subplan->plan_rows; /* ignore overlap */
}
/* cost should be inserted by caller */
plan->targetlist = NIL; plan->targetlist = NIL;
plan->qual = NIL; plan->qual = NIL;
plan->lefttree = NULL; plan->lefttree = NULL;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.117 2005/04/21 02:28:01 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.118 2005/04/21 19:18:12 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -475,12 +475,12 @@ create_index_path(Query *root, ...@@ -475,12 +475,12 @@ create_index_path(Query *root,
* create_bitmap_heap_path * create_bitmap_heap_path
* Creates a path node for a bitmap scan. * Creates a path node for a bitmap scan.
* *
* 'bitmapqual' is an AND/OR tree of IndexPath nodes. * 'bitmapqual' is a tree of IndexPath, BitmapAndPath, and BitmapOrPath nodes.
*/ */
BitmapHeapPath * BitmapHeapPath *
create_bitmap_heap_path(Query *root, create_bitmap_heap_path(Query *root,
RelOptInfo *rel, RelOptInfo *rel,
Node *bitmapqual) Path *bitmapqual)
{ {
BitmapHeapPath *pathnode = makeNode(BitmapHeapPath); BitmapHeapPath *pathnode = makeNode(BitmapHeapPath);
...@@ -499,7 +499,53 @@ create_bitmap_heap_path(Query *root, ...@@ -499,7 +499,53 @@ create_bitmap_heap_path(Query *root,
*/ */
pathnode->rows = rel->rows; pathnode->rows = rel->rows;
cost_bitmap_scan(&pathnode->path, root, rel, bitmapqual, false); cost_bitmap_heap_scan(&pathnode->path, root, rel, bitmapqual, false);
return pathnode;
}
/*
* create_bitmap_and_path
* Creates a path node representing a BitmapAnd.
*/
BitmapAndPath *
create_bitmap_and_path(Query *root,
RelOptInfo *rel,
List *bitmapquals)
{
BitmapAndPath *pathnode = makeNode(BitmapAndPath);
pathnode->path.pathtype = T_BitmapAnd;
pathnode->path.parent = rel;
pathnode->path.pathkeys = NIL; /* always unordered */
pathnode->bitmapquals = bitmapquals;
/* this sets bitmapselectivity as well as the regular cost fields: */
cost_bitmap_and_node(pathnode, root);
return pathnode;
}
/*
* create_bitmap_or_path
* Creates a path node representing a BitmapOr.
*/
BitmapOrPath *
create_bitmap_or_path(Query *root,
RelOptInfo *rel,
List *bitmapquals)
{
BitmapOrPath *pathnode = makeNode(BitmapOrPath);
pathnode->path.pathtype = T_BitmapOr;
pathnode->path.parent = rel;
pathnode->path.pathkeys = NIL; /* always unordered */
pathnode->bitmapquals = bitmapquals;
/* this sets bitmapselectivity as well as the regular cost fields: */
cost_bitmap_or_node(pathnode, root);
return pathnode; return pathnode;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.442 2005/02/22 04:37:17 momjian Exp $ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.443 2005/04/21 19:18:13 tgl Exp $
* *
* NOTES * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -2371,6 +2371,9 @@ PostgresMain(int argc, char *argv[], const char *username) ...@@ -2371,6 +2371,9 @@ PostgresMain(int argc, char *argv[], const char *username)
case 'i': /* indexscan */ case 'i': /* indexscan */
tmp = "enable_indexscan"; tmp = "enable_indexscan";
break; break;
case 'b': /* bitmapscan */
tmp = "enable_bitmapscan";
break;
case 't': /* tidscan */ case 't': /* tidscan */
tmp = "enable_tidscan"; tmp = "enable_tidscan";
break; break;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>. * Written by Peter Eisentraut <peter_e@gmx.net>.
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.259 2005/04/13 18:54:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.260 2005/04/21 19:18:13 tgl Exp $
* *
*-------------------------------------------------------------------- *--------------------------------------------------------------------
*/ */
...@@ -369,6 +369,14 @@ static struct config_bool ConfigureNamesBool[] = ...@@ -369,6 +369,14 @@ static struct config_bool ConfigureNamesBool[] =
&enable_indexscan, &enable_indexscan,
true, NULL, NULL true, NULL, NULL
}, },
{
{"enable_bitmapscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of bitmap-scan plans."),
NULL
},
&enable_bitmapscan,
true, NULL, NULL
},
{ {
{"enable_tidscan", PGC_USERSET, QUERY_TUNING_METHOD, {"enable_tidscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of TID scan plans."), gettext_noop("Enables the planner's use of TID scan plans."),
......
...@@ -137,6 +137,7 @@ ...@@ -137,6 +137,7 @@
# - Planner Method Configuration - # - Planner Method Configuration -
#enable_bitmapscan = true
#enable_hashagg = true #enable_hashagg = true
#enable_hashjoin = true #enable_hashjoin = true
#enable_indexscan = true #enable_indexscan = true
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright (c) 2000-2005, PostgreSQL Global Development Group * Copyright (c) 2000-2005, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.124 2005/04/07 01:51:39 neilc Exp $ * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.125 2005/04/21 19:18:13 tgl Exp $
*/ */
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
...@@ -533,6 +533,7 @@ psql_completion(char *text, int start, int end) ...@@ -533,6 +533,7 @@ psql_completion(char *text, int start, int end)
"default_with_oids", "default_with_oids",
"dynamic_library_path", "dynamic_library_path",
"effective_cache_size", "effective_cache_size",
"enable_bitmapscan",
"enable_hashagg", "enable_hashagg",
"enable_hashjoin", "enable_hashjoin",
"enable_indexscan", "enable_indexscan",
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.167 2005/04/19 22:35:17 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.168 2005/04/21 19:18:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -170,6 +170,8 @@ typedef enum NodeTag ...@@ -170,6 +170,8 @@ typedef enum NodeTag
T_Path, T_Path,
T_IndexPath, T_IndexPath,
T_BitmapHeapPath, T_BitmapHeapPath,
T_BitmapAndPath,
T_BitmapOrPath,
T_NestPath, T_NestPath,
T_MergePath, T_MergePath,
T_HashPath, T_HashPath,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.106 2005/04/21 02:28:02 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.107 2005/04/21 19:18:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -406,7 +406,7 @@ typedef struct IndexPath ...@@ -406,7 +406,7 @@ typedef struct IndexPath
* out in physical heap order no matter what the underlying indexes did. * out in physical heap order no matter what the underlying indexes did.
* *
* The individual indexscans are represented by IndexPath nodes, and any * The individual indexscans are represented by IndexPath nodes, and any
* logic on top of them is represented by regular AND and OR expressions. * logic on top of them is represented by BitmapAndPath and BitmapOrPath.
* Notice that we can use the same IndexPath node both to represent a regular * Notice that we can use the same IndexPath node both to represent a regular
* IndexScan plan, and as the child of a BitmapHeapPath that represents * IndexScan plan, and as the child of a BitmapHeapPath that represents
* scanning the same index using a BitmapIndexScan. The startup_cost and * scanning the same index using a BitmapIndexScan. The startup_cost and
...@@ -420,11 +420,37 @@ typedef struct IndexPath ...@@ -420,11 +420,37 @@ typedef struct IndexPath
typedef struct BitmapHeapPath typedef struct BitmapHeapPath
{ {
Path path; Path path;
Node *bitmapqual; /* the IndexPath/AND/OR tree */ Path *bitmapqual; /* IndexPath, BitmapAndPath, BitmapOrPath */
bool isjoininner; /* T if it's a nestloop inner scan */ bool isjoininner; /* T if it's a nestloop inner scan */
double rows; /* estimated number of result tuples */ double rows; /* estimated number of result tuples */
} BitmapHeapPath; } BitmapHeapPath;
/*
* BitmapAndPath represents a BitmapAnd plan node; it can only appear as
* part of the substructure of a BitmapHeapPath. The Path structure is
* a bit more heavyweight than we really need for this, but for simplicity
* we make it a derivative of Path anyway.
*/
typedef struct BitmapAndPath
{
Path path;
List *bitmapquals; /* IndexPaths and BitmapOrPaths */
Selectivity bitmapselectivity;
} BitmapAndPath;
/*
* BitmapOrPath represents a BitmapOr plan node; it can only appear as
* part of the substructure of a BitmapHeapPath. The Path structure is
* a bit more heavyweight than we really need for this, but for simplicity
* we make it a derivative of Path anyway.
*/
typedef struct BitmapOrPath
{
Path path;
List *bitmapquals; /* IndexPaths and BitmapAndPaths */
Selectivity bitmapselectivity;
} BitmapOrPath;
/* /*
* TidPath represents a scan by TID * TidPath represents a scan by TID
* *
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/optimizer/cost.h,v 1.65 2005/04/21 02:28:02 tgl Exp $ * $PostgreSQL: pgsql/src/include/optimizer/cost.h,v 1.66 2005/04/21 19:18:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -42,6 +42,7 @@ extern double cpu_operator_cost; ...@@ -42,6 +42,7 @@ extern double cpu_operator_cost;
extern Cost disable_cost; extern Cost disable_cost;
extern bool enable_seqscan; extern bool enable_seqscan;
extern bool enable_indexscan; extern bool enable_indexscan;
extern bool enable_bitmapscan;
extern bool enable_tidscan; extern bool enable_tidscan;
extern bool enable_sort; extern bool enable_sort;
extern bool enable_hashagg; extern bool enable_hashagg;
...@@ -53,8 +54,10 @@ extern double clamp_row_est(double nrows); ...@@ -53,8 +54,10 @@ extern double clamp_row_est(double nrows);
extern void cost_seqscan(Path *path, Query *root, RelOptInfo *baserel); extern void cost_seqscan(Path *path, Query *root, RelOptInfo *baserel);
extern void cost_index(IndexPath *path, Query *root, IndexOptInfo *index, extern void cost_index(IndexPath *path, Query *root, IndexOptInfo *index,
List *indexQuals, bool is_injoin); List *indexQuals, bool is_injoin);
extern void cost_bitmap_scan(Path *path, Query *root, RelOptInfo *baserel, extern void cost_bitmap_heap_scan(Path *path, Query *root, RelOptInfo *baserel,
Node *bitmapqual, bool is_injoin); Path *bitmapqual, bool is_injoin);
extern void cost_bitmap_and_node(BitmapAndPath *path, Query *root);
extern void cost_bitmap_or_node(BitmapOrPath *path, Query *root);
extern void cost_tidscan(Path *path, Query *root, extern void cost_tidscan(Path *path, Query *root,
RelOptInfo *baserel, List *tideval); RelOptInfo *baserel, List *tideval);
extern void cost_subqueryscan(Path *path, RelOptInfo *baserel); extern void cost_subqueryscan(Path *path, RelOptInfo *baserel);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/optimizer/pathnode.h,v 1.58 2005/04/19 22:35:18 tgl Exp $ * $PostgreSQL: pgsql/src/include/optimizer/pathnode.h,v 1.59 2005/04/21 19:18:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -35,7 +35,13 @@ extern IndexPath *create_index_path(Query *root, ...@@ -35,7 +35,13 @@ extern IndexPath *create_index_path(Query *root,
ScanDirection indexscandir); ScanDirection indexscandir);
extern BitmapHeapPath *create_bitmap_heap_path(Query *root, extern BitmapHeapPath *create_bitmap_heap_path(Query *root,
RelOptInfo *rel, RelOptInfo *rel,
Node *bitmapqual); Path *bitmapqual);
extern BitmapAndPath *create_bitmap_and_path(Query *root,
RelOptInfo *rel,
List *bitmapquals);
extern BitmapOrPath *create_bitmap_or_path(Query *root,
RelOptInfo *rel,
List *bitmapquals);
extern TidPath *create_tidscan_path(Query *root, RelOptInfo *rel, extern TidPath *create_tidscan_path(Query *root, RelOptInfo *rel,
List *tideval); List *tideval);
extern AppendPath *create_append_path(RelOptInfo *rel, List *subpaths); extern AppendPath *create_append_path(RelOptInfo *rel, List *subpaths);
......
SELECT name, setting FROM pg_settings WHERE name LIKE 'enable%'; SELECT name, setting FROM pg_settings WHERE name LIKE 'enable%';
name | setting name | setting
------------------+--------- -------------------+---------
enable_bitmapscan | on
enable_hashagg | on enable_hashagg | on
enable_hashjoin | on enable_hashjoin | on
enable_indexscan | on enable_indexscan | on
...@@ -9,7 +10,7 @@ SELECT name, setting FROM pg_settings WHERE name LIKE 'enable%'; ...@@ -9,7 +10,7 @@ SELECT name, setting FROM pg_settings WHERE name LIKE 'enable%';
enable_seqscan | on enable_seqscan | on
enable_sort | on enable_sort | on
enable_tidscan | on enable_tidscan | on
(8 rows) (9 rows)
CREATE TABLE foo2(fooid int, f2 int); CREATE TABLE foo2(fooid int, f2 int);
INSERT INTO foo2 VALUES(1, 11); INSERT INTO foo2 VALUES(1, 11);
......
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