summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Haas2016-03-23 11:57:46 +0000
committerRobert Haas2016-03-23 11:57:46 +0000
commit0336843939401dab8d8fbfe75e0631fea5d4c060 (patch)
treef6dae5de5651a4a231044f56f7c860bc816dcf0a
parentb283096534b9c514a92a70c98c033015b6792ba7 (diff)
not all jointypes done - rest in theory isserial_cost
-rw-r--r--src/backend/commands/explain.c7
-rw-r--r--src/backend/nodes/copyfuncs.c1
-rw-r--r--src/backend/nodes/outfuncs.c3
-rw-r--r--src/backend/nodes/readfuncs.c1
-rw-r--r--src/backend/optimizer/path/costsize.c151
-rw-r--r--src/backend/optimizer/path/indxpath.c13
-rw-r--r--src/backend/optimizer/plan/createplan.c3
-rw-r--r--src/backend/optimizer/prep/prepunion.c4
-rw-r--r--src/backend/optimizer/util/pathnode.c15
-rw-r--r--src/backend/utils/adt/selfuncs.c31
-rw-r--r--src/include/access/amapi.h1
-rw-r--r--src/include/nodes/plannodes.h1
-rw-r--r--src/include/nodes/relation.h11
-rw-r--r--src/include/optimizer/cost.h13
-rw-r--r--src/include/utils/index_selfuncs.h6
15 files changed, 211 insertions, 50 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 787b0b93cc..d9ba63f8c9 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -1187,14 +1187,17 @@ ExplainNode(PlanState *planstate, List *ancestors,
{
if (es->format == EXPLAIN_FORMAT_TEXT)
{
- appendStringInfo(es->str, " (cost=%.2f..%.2f rows=%.0f width=%d)",
+ appendStringInfo(es->str,
+ " (cost=%.2f..%.2f/%.2f rows=%.0f width=%d)",
plan->startup_cost, plan->total_cost,
- plan->plan_rows, plan->plan_width);
+ plan->serial_cost, plan->plan_rows,
+ plan->plan_width);
}
else
{
ExplainPropertyFloat("Startup Cost", plan->startup_cost, 2, es);
ExplainPropertyFloat("Total Cost", plan->total_cost, 2, es);
+ ExplainPropertyFloat("Serial Cost", plan->serial_cost, 2, es);
ExplainPropertyFloat("Plan Rows", plan->plan_rows, 0, es);
ExplainPropertyInteger("Plan Width", plan->plan_width, es);
}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 6b5d1d6efc..546ed3d3f6 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -112,6 +112,7 @@ CopyPlanFields(const Plan *from, Plan *newnode)
{
COPY_SCALAR_FIELD(startup_cost);
COPY_SCALAR_FIELD(total_cost);
+ COPY_SCALAR_FIELD(serial_cost);
COPY_SCALAR_FIELD(plan_rows);
COPY_SCALAR_FIELD(plan_width);
COPY_SCALAR_FIELD(parallel_aware);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 32d03f7f25..2306877208 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -285,6 +285,7 @@ _outPlanInfo(StringInfo str, const Plan *node)
{
WRITE_FLOAT_FIELD(startup_cost, "%.2f");
WRITE_FLOAT_FIELD(total_cost, "%.2f");
+ WRITE_FLOAT_FIELD(serial_cost, "%.2f");
WRITE_FLOAT_FIELD(plan_rows, "%.0f");
WRITE_INT_FIELD(plan_width);
WRITE_BOOL_FIELD(parallel_aware);
@@ -1614,6 +1615,7 @@ _outPathInfo(StringInfo str, const Path *node)
WRITE_FLOAT_FIELD(rows, "%.0f");
WRITE_FLOAT_FIELD(startup_cost, "%.2f");
WRITE_FLOAT_FIELD(total_cost, "%.2f");
+ WRITE_FLOAT_FIELD(serial_cost, "%.2f");
WRITE_NODE_FIELD(pathkeys);
}
@@ -1654,6 +1656,7 @@ _outIndexPath(StringInfo str, const IndexPath *node)
WRITE_NODE_FIELD(indexorderbycols);
WRITE_ENUM_FIELD(indexscandir, ScanDirection);
WRITE_FLOAT_FIELD(indextotalcost, "%.2f");
+ WRITE_FLOAT_FIELD(indexserialcost, "%.2f");
WRITE_FLOAT_FIELD(indexselectivity, "%.4f");
}
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 6db0492e15..59ebab49ca 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1422,6 +1422,7 @@ ReadCommonPlan(Plan *local_node)
READ_FLOAT_FIELD(startup_cost);
READ_FLOAT_FIELD(total_cost);
+ READ_FLOAT_FIELD(serial_cost);
READ_FLOAT_FIELD(plan_rows);
READ_INT_FIELD(plan_width);
READ_BOOL_FIELD(parallel_aware);
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 9f572d759b..ed3f4c6608 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -270,6 +270,7 @@ cost_seqscan(Path *path, PlannerInfo *root,
path->startup_cost = startup_cost;
path->total_cost = startup_cost + cpu_run_cost + disk_run_cost;
+ path->serial_cost = disk_run_cost;
}
/*
@@ -285,6 +286,7 @@ cost_samplescan(Path *path, PlannerInfo *root,
{
Cost startup_cost = 0;
Cost run_cost = 0;
+ Cost disk_run_cost = 0;
RangeTblEntry *rte;
TableSampleClause *tsc;
TsmRoutine *tsm;
@@ -321,7 +323,8 @@ cost_samplescan(Path *path, PlannerInfo *root,
* disk costs (recall that baserel->pages has already been set to the
* number of pages the sampling method will visit)
*/
- run_cost += spc_page_cost * baserel->pages;
+ disk_run_cost = spc_page_cost * baserel->pages;
+ run_cost += disk_run_cost;
/*
* CPU costs (recall that baserel->tuples has already been set to the
@@ -342,6 +345,7 @@ cost_samplescan(Path *path, PlannerInfo *root,
path->startup_cost = startup_cost;
path->total_cost = startup_cost + run_cost;
+ path->serial_cost = disk_run_cost;
}
/*
@@ -361,6 +365,7 @@ cost_gather(GatherPath *path, PlannerInfo *root,
{
Cost startup_cost = 0;
Cost run_cost = 0;
+ Cost serial_tuple_cost = 0;
/* Mark the path with the correct row estimate */
if (rows)
@@ -376,10 +381,22 @@ cost_gather(GatherPath *path, PlannerInfo *root,
/* Parallel setup and communication cost. */
startup_cost += parallel_setup_cost;
- run_cost += parallel_tuple_cost * path->path.rows;
+ serial_tuple_cost = parallel_tuple_cost * path->path.rows;
+ run_cost += serial_tuple_cost;
path->path.startup_cost = startup_cost;
path->path.total_cost = (startup_cost + run_cost);
+
+ /*
+ * The cost of setting up parallel workers undoubtedly cannot be
+ * parallelized; it doesn't take less time to set up more workers than
+ * fewer. It's more arguable whether the full parallel_tuple_cost should
+ * be charged as serial_cost, since that represents both the cost the
+ * leader pays and the cost the worker pays. But for now we err on the
+ * side of caution and charge the entire amount.
+ */
+ path->path.serial_cost = path->subpath->serial_cost + parallel_setup_cost
+ + serial_tuple_cost;
}
/*
@@ -392,8 +409,8 @@ cost_gather(GatherPath *path, PlannerInfo *root,
* estimates of caching behavior
*
* In addition to rows, startup_cost and total_cost, cost_index() sets the
- * path's indextotalcost and indexselectivity fields. These values will be
- * needed if the IndexPath is used in a BitmapIndexScan.
+ * path's indextotalcost, indexserialcost, and indexselectivity fields. These
+ * values will be needed if the IndexPath is used in a BitmapIndexScan.
*
* NOTE: path->indexquals must contain only clauses usable as index
* restrictions. Any additional quals evaluated as qpquals may reduce the
@@ -412,13 +429,15 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count)
Cost run_cost = 0;
Cost indexStartupCost;
Cost indexTotalCost;
+ Cost indexSerialCost;
Selectivity indexSelectivity;
double indexCorrelation,
csquared;
double spc_seq_page_cost,
spc_random_page_cost;
Cost min_IO_cost,
- max_IO_cost;
+ max_IO_cost,
+ disk_run_cost;
QualCost qpqual_cost;
Cost cpu_per_tuple;
double tuples_fetched;
@@ -465,7 +484,7 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count)
*/
amcostestimate = (amcostestimate_function) index->amcostestimate;
amcostestimate(root, path, loop_count,
- &indexStartupCost, &indexTotalCost,
+ &indexStartupCost, &indexTotalCost, &indexSerialCost,
&indexSelectivity, &indexCorrelation);
/*
@@ -474,6 +493,7 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count)
* bitmap scan doesn't care about either.
*/
path->indextotalcost = indexTotalCost;
+ path->indexserialcost = indexSerialCost;
path->indexselectivity = indexSelectivity;
/* all costs for touching index itself included here */
@@ -596,7 +616,8 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count)
*/
csquared = indexCorrelation * indexCorrelation;
- run_cost += max_IO_cost + csquared * (min_IO_cost - max_IO_cost);
+ disk_run_cost = max_IO_cost + csquared * (min_IO_cost - max_IO_cost);
+ run_cost += disk_run_cost;
/*
* Estimate CPU costs per tuple.
@@ -617,6 +638,7 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count)
path->path.startup_cost = startup_cost;
path->path.total_cost = startup_cost + run_cost;
+ path->path.serial_cost = indexSerialCost + disk_run_cost;
}
/*
@@ -820,12 +842,14 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
Cost startup_cost = 0;
Cost run_cost = 0;
Cost indexTotalCost;
+ Cost indexSerialCost;
Selectivity indexSelectivity;
QualCost qpqual_cost;
Cost cpu_per_tuple;
Cost cost_per_page;
double tuples_fetched;
double pages_fetched;
+ double disk_run_cost;
double spc_seq_page_cost,
spc_random_page_cost;
double T;
@@ -848,7 +872,8 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
* Fetch total cost of obtaining the bitmap, as well as its total
* selectivity.
*/
- cost_bitmap_tree_node(bitmapqual, &indexTotalCost, &indexSelectivity);
+ cost_bitmap_tree_node(bitmapqual, &indexTotalCost, &indexSerialCost,
+ &indexSelectivity);
startup_cost += indexTotalCost;
@@ -906,7 +931,8 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
else
cost_per_page = spc_random_page_cost;
- run_cost += pages_fetched * cost_per_page;
+ disk_run_cost = pages_fetched * cost_per_page;
+ run_cost += disk_run_cost;
/*
* Estimate CPU costs per tuple.
@@ -930,6 +956,7 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
path->startup_cost = startup_cost;
path->total_cost = startup_cost + run_cost;
+ path->serial_cost = indexSerialCost + disk_run_cost;
}
/*
@@ -937,11 +964,13 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
* Extract cost and selectivity from a bitmap tree node (index/and/or)
*/
void
-cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec)
+cost_bitmap_tree_node(Path *path, Cost *total_cost, Cost *serial_cost,
+ Selectivity *selec)
{
if (IsA(path, IndexPath))
{
- *cost = ((IndexPath *) path)->indextotalcost;
+ *total_cost = ((IndexPath *) path)->indextotalcost;
+ *serial_cost = ((IndexPath *) path)->indexserialcost;
*selec = ((IndexPath *) path)->indexselectivity;
/*
@@ -950,22 +979,24 @@ cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec)
* scan doesn't look to be the same cost as an indexscan to retrieve a
* single tuple.
*/
- *cost += 0.1 * cpu_operator_cost * path->rows;
+ *total_cost += 0.1 * cpu_operator_cost * path->rows;
}
else if (IsA(path, BitmapAndPath))
{
- *cost = path->total_cost;
+ *total_cost = path->total_cost;
+ *serial_cost = path->serial_cost;
*selec = ((BitmapAndPath *) path)->bitmapselectivity;
}
else if (IsA(path, BitmapOrPath))
{
- *cost = path->total_cost;
+ *total_cost = path->total_cost;
+ *serial_cost = path->serial_cost;
*selec = ((BitmapOrPath *) path)->bitmapselectivity;
}
else
{
elog(ERROR, "unrecognized node type: %d", nodeTag(path));
- *cost = *selec = 0; /* keep compiler quiet */
+ *total_cost = *serial_cost = *selec = 0; /* keep compiler quiet */
}
}
@@ -983,6 +1014,7 @@ void
cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root)
{
Cost totalCost;
+ Cost serialCost;
Selectivity selec;
ListCell *l;
@@ -996,18 +1028,22 @@ cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root)
* definitely too simplistic?
*/
totalCost = 0.0;
+ serialCost = 0.0;
selec = 1.0;
foreach(l, path->bitmapquals)
{
Path *subpath = (Path *) lfirst(l);
- Cost subCost;
+ Cost subTotalCost;
+ Cost subSerialCost;
Selectivity subselec;
- cost_bitmap_tree_node(subpath, &subCost, &subselec);
+ cost_bitmap_tree_node(subpath, &subTotalCost, &subSerialCost,
+ &subselec);
selec *= subselec;
- totalCost += subCost;
+ totalCost += subTotalCost;
+ serialCost += subSerialCost;
if (l != list_head(path->bitmapquals))
totalCost += 100.0 * cpu_operator_cost;
}
@@ -1015,6 +1051,7 @@ cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root)
path->path.rows = 0; /* per above, not used */
path->path.startup_cost = totalCost;
path->path.total_cost = totalCost;
+ path->path.serial_cost = serialCost;
}
/*
@@ -1027,6 +1064,7 @@ void
cost_bitmap_or_node(BitmapOrPath *path, PlannerInfo *root)
{
Cost totalCost;
+ Cost serialCost;
Selectivity selec;
ListCell *l;
@@ -1041,18 +1079,22 @@ cost_bitmap_or_node(BitmapOrPath *path, PlannerInfo *root)
* optimized out when the inputs are BitmapIndexScans.
*/
totalCost = 0.0;
+ serialCost = 0.0;
selec = 0.0;
foreach(l, path->bitmapquals)
{
Path *subpath = (Path *) lfirst(l);
- Cost subCost;
+ Cost subTotalCost;
+ Cost subSerialCost;
Selectivity subselec;
- cost_bitmap_tree_node(subpath, &subCost, &subselec);
+ cost_bitmap_tree_node(subpath, &subTotalCost, &subSerialCost,
+ &subselec);
selec += subselec;
- totalCost += subCost;
+ totalCost += subTotalCost;
+ serialCost += subSerialCost;
if (l != list_head(path->bitmapquals) &&
!IsA(subpath, IndexPath))
totalCost += 100.0 * cpu_operator_cost;
@@ -1061,6 +1103,7 @@ cost_bitmap_or_node(BitmapOrPath *path, PlannerInfo *root)
path->path.rows = 0; /* per above, not used */
path->path.startup_cost = totalCost;
path->path.total_cost = totalCost;
+ path->path.serial_cost = serialCost;
}
/*
@@ -1077,6 +1120,7 @@ cost_tidscan(Path *path, PlannerInfo *root,
{
Cost startup_cost = 0;
Cost run_cost = 0;
+ Cost disk_run_cost;
bool isCurrentOf = false;
QualCost qpqual_cost;
Cost cpu_per_tuple;
@@ -1148,7 +1192,8 @@ cost_tidscan(Path *path, PlannerInfo *root,
NULL);
/* disk costs --- assume each tuple on a different page */
- run_cost += spc_random_page_cost * ntuples;
+ disk_run_cost = spc_random_page_cost * ntuples;
+ run_cost += disk_run_cost;
/* Add scanning CPU costs */
get_restriction_qual_cost(root, baserel, param_info, &qpqual_cost);
@@ -1165,6 +1210,7 @@ cost_tidscan(Path *path, PlannerInfo *root,
path->startup_cost = startup_cost;
path->total_cost = startup_cost + run_cost;
+ path->serial_cost = disk_run_cost;
}
/*
@@ -1214,6 +1260,7 @@ cost_subqueryscan(SubqueryScanPath *path, PlannerInfo *root,
path->path.startup_cost += startup_cost;
path->path.total_cost += startup_cost + run_cost;
+ path->path.serial_cost = path->subpath->serial_cost;
}
/*
@@ -1275,6 +1322,7 @@ cost_functionscan(Path *path, PlannerInfo *root,
path->startup_cost = startup_cost;
path->total_cost = startup_cost + run_cost;
+ path->serial_cost = 0; /* all CPU cost */
}
/*
@@ -1322,6 +1370,7 @@ cost_valuesscan(Path *path, PlannerInfo *root,
path->startup_cost = startup_cost;
path->total_cost = startup_cost + run_cost;
+ path->serial_cost = 0; /* all CPU cost */
}
/*
@@ -1369,6 +1418,7 @@ cost_ctescan(Path *path, PlannerInfo *root,
path->startup_cost = startup_cost;
path->total_cost = startup_cost + run_cost;
+ path->serial_cost = 0; /* all CPU cost? can't this spill to disk? */
}
/*
@@ -1408,6 +1458,7 @@ cost_recursive_union(Path *runion, Path *nrterm, Path *rterm)
runion->startup_cost = startup_cost;
runion->total_cost = total_cost;
+ runion->serial_cost = nrterm->serial_cost;
runion->rows = total_rows;
runion->pathtarget->width = Max(nrterm->pathtarget->width,
rterm->pathtarget->width);
@@ -1466,6 +1517,7 @@ cost_sort(Path *path, PlannerInfo *root,
{
Cost startup_cost = input_cost;
Cost run_cost = 0;
+ Cost disk_run_cost = 0;
double input_bytes = relation_byte_size(tuples, width);
double output_bytes;
double output_tuples;
@@ -1525,8 +1577,9 @@ cost_sort(Path *path, PlannerInfo *root,
log_runs = 1.0;
npageaccesses = 2.0 * npages * log_runs;
/* Assume 3/4ths of accesses are sequential, 1/4th are not */
- startup_cost += npageaccesses *
+ disk_run_cost = npageaccesses *
(seq_page_cost * 0.75 + random_page_cost * 0.25);
+ startup_cost += disk_run_cost;
}
else if (tuples > 2 * output_tuples || input_bytes > sort_mem_bytes)
{
@@ -1556,6 +1609,7 @@ cost_sort(Path *path, PlannerInfo *root,
path->startup_cost = startup_cost;
path->total_cost = startup_cost + run_cost;
+ path->serial_cost = disk_run_cost;
}
/*
@@ -1581,13 +1635,14 @@ cost_sort(Path *path, PlannerInfo *root,
* 'n_streams' is the number of input streams
* 'input_startup_cost' is the sum of the input streams' startup costs
* 'input_total_cost' is the sum of the input streams' total costs
+ * 'input_serial_cost' is the sum of the input streams' total costs
* 'tuples' is the number of tuples in all the streams
*/
void
cost_merge_append(Path *path, PlannerInfo *root,
List *pathkeys, int n_streams,
Cost input_startup_cost, Cost input_total_cost,
- double tuples)
+ Cost input_serial_cost, double tuples)
{
Cost startup_cost = 0;
Cost run_cost = 0;
@@ -1620,6 +1675,7 @@ cost_merge_append(Path *path, PlannerInfo *root,
path->startup_cost = startup_cost + input_startup_cost;
path->total_cost = startup_cost + run_cost + input_total_cost;
+ path->serial_cost = input_serial_cost;
}
/*
@@ -1637,10 +1693,11 @@ cost_merge_append(Path *path, PlannerInfo *root,
void
cost_material(Path *path,
Cost input_startup_cost, Cost input_total_cost,
- double tuples, int width)
+ Cost input_serial_cost, double tuples, int width)
{
Cost startup_cost = input_startup_cost;
Cost run_cost = input_total_cost - input_startup_cost;
+ Cost serial_cost = input_serial_cost;
double nbytes = relation_byte_size(tuples, width);
long work_mem_bytes = work_mem * 1024L;
@@ -1671,10 +1728,12 @@ cost_material(Path *path,
double npages = ceil(nbytes / BLCKSZ);
run_cost += seq_page_cost * npages;
+ serial_cost += seq_page_cost * npages;
}
path->startup_cost = startup_cost;
path->total_cost = startup_cost + run_cost;
+ path->serial_cost = serial_cost;
}
/*
@@ -1693,7 +1752,7 @@ cost_agg(Path *path, PlannerInfo *root,
AggStrategy aggstrategy, const AggClauseCosts *aggcosts,
int numGroupCols, double numGroups,
Cost input_startup_cost, Cost input_total_cost,
- double input_tuples)
+ Cost input_serial_cost, double input_tuples)
{
double output_tuples;
Cost startup_cost;
@@ -1771,6 +1830,7 @@ cost_agg(Path *path, PlannerInfo *root,
path->rows = output_tuples;
path->startup_cost = startup_cost;
path->total_cost = total_cost;
+ path->serial_cost = input_serial_cost;
}
/*
@@ -1784,7 +1844,7 @@ void
cost_windowagg(Path *path, PlannerInfo *root,
List *windowFuncs, int numPartCols, int numOrderCols,
Cost input_startup_cost, Cost input_total_cost,
- double input_tuples)
+ Cost input_serial_cost, double input_tuples)
{
Cost startup_cost;
Cost total_cost;
@@ -1842,6 +1902,7 @@ cost_windowagg(Path *path, PlannerInfo *root,
path->rows = input_tuples;
path->startup_cost = startup_cost;
path->total_cost = total_cost;
+ path->serial_cost = input_serial_cost;
}
/*
@@ -1856,7 +1917,7 @@ void
cost_group(Path *path, PlannerInfo *root,
int numGroupCols, double numGroups,
Cost input_startup_cost, Cost input_total_cost,
- double input_tuples)
+ Cost input_serial_cost, double input_tuples)
{
Cost startup_cost;
Cost total_cost;
@@ -1873,6 +1934,7 @@ cost_group(Path *path, PlannerInfo *root,
path->rows = numGroups;
path->startup_cost = startup_cost;
path->total_cost = total_cost;
+ path->serial_cost = input_serial_cost;
}
/*
@@ -1987,6 +2049,8 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path,
double inner_path_rows = inner_path->rows;
Cost startup_cost = workspace->startup_cost;
Cost run_cost = workspace->run_cost;
+ Cost serial_cost = outer_path->serial_cost;
+ Cost inner_rescan_serial_cost;
Cost cpu_per_tuple;
QualCost restrict_qual_cost;
double ntuples;
@@ -2005,6 +2069,16 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path,
if (!enable_nestloop)
startup_cost += disable_cost;
+ /*
+ * We don't have a mechanism for accurately estimating the serial
+ * cost of rescanning the inner path. So assume it's the same as the
+ * serial cost of the first scan -- unless that'd be more than the
+ * total cost of a rescan, which would be an obviously unreasonable
+ * result.
+ */
+ inner_rescan_serial_cost = Min(inner_path->serial_cost,
+ workspace->inner_rescan_run_cost);
+
/* cost of inner-relation source data (we already dealt with outer rel) */
if (path->jointype == JOIN_SEMI || path->jointype == JOIN_ANTI)
@@ -2061,8 +2135,12 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path,
* inner_rescan_run_cost for additional ones.
*/
run_cost += inner_run_cost * inner_scan_frac;
+ serial_cost += inner_path->serial_cost * inner_scan_frac;
if (outer_matched_rows > 1)
+ {
run_cost += (outer_matched_rows - 1) * inner_rescan_run_cost * inner_scan_frac;
+ serial_cost += (outer_matched_rows - 1) * inner_rescan_serial_cost * inner_scan_frac;
+ }
/*
* Add the cost of inner-scan executions for unmatched outer rows.
@@ -2072,6 +2150,8 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path,
*/
run_cost += (outer_path_rows - outer_matched_rows) *
inner_rescan_run_cost / inner_path_rows;
+ serial_cost += (outer_path_rows - outer_matched_rows) *
+ inner_rescan_serial_cost / inner_path_rows;
/*
* We won't be evaluating any quals at all for unmatched rows, so
@@ -2090,14 +2170,20 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path,
* conservative and always charge the whole first-scan cost once.
*/
run_cost += inner_run_cost;
+ serial_cost += inner_path->serial_cost;
/* Add inner run cost for additional outer tuples having matches */
if (outer_matched_rows > 1)
+ {
run_cost += (outer_matched_rows - 1) * inner_rescan_run_cost * inner_scan_frac;
+ serial_cost += (outer_matched_rows - 1) * inner_rescan_serial_cost * inner_scan_frac;
+ }
/* Add inner run cost for unmatched outer tuples */
run_cost += (outer_path_rows - outer_matched_rows) *
inner_rescan_run_cost;
+ serial_cost += (outer_path_rows - outer_matched_rows) *
+ inner_rescan_serial_cost;
/* And count the unmatched join tuples as being processed */
ntuples += (outer_path_rows - outer_matched_rows) *
@@ -2106,7 +2192,13 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path,
}
else
{
- /* Normal-case source costs were included in preliminary estimate */
+ /*
+ * Normal-case source costs were included in preliminary estimate, but
+ * we still need to work out the serial cost.
+ */
+ serial_cost += inner_path->serial_cost;
+ if (outer_path_rows > 1)
+ serial_cost += (outer_path_rows - 1) * inner_rescan_serial_cost;
/* Compute number of tuples processed (not number emitted!) */
ntuples = outer_path_rows * inner_path_rows;
@@ -2124,6 +2216,7 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path,
path->path.startup_cost = startup_cost;
path->path.total_cost = startup_cost + run_cost;
+ path->path.serial_cost = serial_cost;
}
/*
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index b48f5f28ea..e17f1bb49f 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -1393,12 +1393,15 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
{
/* duplicate clauseids, keep the cheaper one */
Cost ncost;
+ Cost nscost;
Cost ocost;
+ Cost oscost;
Selectivity nselec;
Selectivity oselec;
- cost_bitmap_tree_node(pathinfo->path, &ncost, &nselec);
- cost_bitmap_tree_node(pathinfoarray[i]->path, &ocost, &oselec);
+ cost_bitmap_tree_node(pathinfo->path, &ncost, &nscost, &nselec);
+ cost_bitmap_tree_node(pathinfoarray[i]->path, &ocost, &oscost,
+ &oselec);
if (ncost < ocost)
pathinfoarray[i] = pathinfo;
}
@@ -1510,11 +1513,13 @@ path_usage_comparator(const void *a, const void *b)
PathClauseUsage *pb = *(PathClauseUsage *const *) b;
Cost acost;
Cost bcost;
+ Cost ascost;
+ Cost bscost;
Selectivity aselec;
Selectivity bselec;
- cost_bitmap_tree_node(pa->path, &acost, &aselec);
- cost_bitmap_tree_node(pb->path, &bcost, &bselec);
+ cost_bitmap_tree_node(pa->path, &acost, &ascost, &aselec);
+ cost_bitmap_tree_node(pb->path, &bcost, &bscost, &bselec);
/*
* If costs are the same, sort by selectivity.
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index d159a17fd2..1fd99663a5 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -2787,6 +2787,7 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
/* and set its cost/width fields appropriately */
plan->startup_cost = 0.0;
plan->total_cost = ipath->indextotalcost;
+ plan->serial_cost = ipath->indexserialcost;
plan->plan_rows =
clamp_row_est(ipath->indexselectivity * ipath->path.parent->tuples);
plan->plan_width = 0; /* meaningless */
@@ -4570,6 +4571,7 @@ copy_generic_path_info(Plan *dest, Path *src)
{
dest->startup_cost = src->startup_cost;
dest->total_cost = src->total_cost;
+ dest->serial_cost = src->serial_cost;
dest->plan_rows = src->rows;
dest->plan_width = src->pathtarget->width;
dest->parallel_aware = src->parallel_aware;
@@ -5621,6 +5623,7 @@ materialize_finished_plan(Plan *subplan)
cost_material(&matpath,
subplan->startup_cost,
subplan->total_cost,
+ subplan->serial_cost,
subplan->plan_rows,
subplan->plan_width);
matplan->startup_cost = matpath.startup_cost;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index fb139af2c1..04539a7975 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -947,7 +947,7 @@ choose_hashed_setop(PlannerInfo *root, List *groupClauses,
cost_agg(&hashed_p, root, AGG_HASHED, NULL,
numGroupCols, dNumGroups,
input_path->startup_cost, input_path->total_cost,
- input_path->rows);
+ input_path->serial_cost, input_path->rows);
/*
* Now for the sorted case. Note that the input is *always* unsorted,
@@ -961,7 +961,7 @@ choose_hashed_setop(PlannerInfo *root, List *groupClauses,
0.0, work_mem, -1.0);
cost_group(&sorted_p, root, numGroupCols, dNumGroups,
sorted_p.startup_cost, sorted_p.total_cost,
- input_path->rows);
+ sorted_p.serial_cost, input_path->rows);
/*
* Now make the decision using the top-level tuple fraction. First we
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 16b34fcf46..b13efebe34 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1247,6 +1247,7 @@ create_merge_append_path(PlannerInfo *root,
MergeAppendPath *pathnode = makeNode(MergeAppendPath);
Cost input_startup_cost;
Cost input_total_cost;
+ Cost input_serial_cost;
ListCell *l;
pathnode->path.pathtype = T_MergeAppend;
@@ -1275,6 +1276,7 @@ create_merge_append_path(PlannerInfo *root,
pathnode->path.rows = 0;
input_startup_cost = 0;
input_total_cost = 0;
+ input_serial_cost = 0;
foreach(l, subpaths)
{
Path *subpath = (Path *) lfirst(l);
@@ -1305,6 +1307,7 @@ create_merge_append_path(PlannerInfo *root,
pathnode->limit_tuples);
input_startup_cost += sort_path.startup_cost;
input_total_cost += sort_path.total_cost;
+ input_serial_cost += sort_path.serial_cost;
}
/* All child paths must have same parameterization */
@@ -1315,7 +1318,7 @@ create_merge_append_path(PlannerInfo *root,
cost_merge_append(&pathnode->path, root,
pathkeys, list_length(subpaths),
input_startup_cost, input_total_cost,
- rel->tuples);
+ input_serial_cost, rel->tuples);
return pathnode;
}
@@ -1388,6 +1391,7 @@ create_material_path(RelOptInfo *rel, Path *subpath)
cost_material(&pathnode->path,
subpath->startup_cost,
subpath->total_cost,
+ subpath->serial_cost,
subpath->rows,
subpath->pathtarget->width);
@@ -1572,6 +1576,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
numCols, pathnode->path.rows,
subpath->startup_cost,
subpath->total_cost,
+ subpath->serial_cost,
rel->rows);
}
@@ -2343,7 +2348,7 @@ create_group_path(PlannerInfo *root,
list_length(groupClause),
numGroups,
subpath->startup_cost, subpath->total_cost,
- subpath->rows);
+ subpath->serial_cost, subpath->rows);
/* add tlist eval cost for each output row */
pathnode->path.startup_cost += target->cost.startup;
@@ -2463,7 +2468,7 @@ create_agg_path(PlannerInfo *root,
aggstrategy, aggcosts,
list_length(groupClause), numGroups,
subpath->startup_cost, subpath->total_cost,
- subpath->rows);
+ subpath->serial_cost, subpath->rows);
/* add tlist eval cost for each output row */
pathnode->path.startup_cost += target->cost.startup;
@@ -2543,6 +2548,7 @@ create_groupingsets_path(PlannerInfo *root,
numGroups,
subpath->startup_cost,
subpath->total_cost,
+ subpath->serial_cost,
subpath->rows);
/*
@@ -2583,6 +2589,7 @@ create_groupingsets_path(PlannerInfo *root,
numGroups, /* XXX surely not right for all steps? */
sort_path.startup_cost,
sort_path.total_cost,
+ sort_path.serial_cost,
sort_path.rows);
pathnode->path.total_cost += agg_path.total_cost;
@@ -2705,6 +2712,7 @@ create_windowagg_path(PlannerInfo *root,
list_length(winclause->orderClause),
subpath->startup_cost,
subpath->total_cost,
+ subpath->serial_cost,
subpath->rows);
/* add tlist eval cost for each output row */
@@ -2773,6 +2781,7 @@ create_setop_path(PlannerInfo *root,
pathnode->path.startup_cost = subpath->startup_cost;
pathnode->path.total_cost = subpath->total_cost +
cpu_operator_cost * subpath->rows * list_length(distinctList);
+ pathnode->path.serial_cost = subpath->serial_cost;
pathnode->path.rows = outputRows;
return pathnode;
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index d396ef142f..a5ffc3516f 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -6195,6 +6195,7 @@ typedef struct
/* These are the values the cost estimator must return to the planner */
Cost indexStartupCost; /* index-related startup cost */
Cost indexTotalCost; /* total index-related scan cost */
+ Cost indexSerialCost; /* non-parallelizable portion */
Selectivity indexSelectivity; /* selectivity of index */
double indexCorrelation; /* order correlation of index */
@@ -6217,6 +6218,7 @@ genericcostestimate(PlannerInfo *root,
List *indexOrderBys = path->indexorderbys;
Cost indexStartupCost;
Cost indexTotalCost;
+ Cost indexSerialCost;
Selectivity indexSelectivity;
double indexCorrelation;
double numIndexPages;
@@ -6365,6 +6367,12 @@ genericcostestimate(PlannerInfo *root,
}
/*
+ * Everything after this point is just CPU overhead, which permits
+ * effective parallelism.
+ */
+ indexSerialCost = indexTotalCost;
+
+ /*
* CPU cost: any complex expressions in the indexquals will need to be
* evaluated once at the start of the scan to reduce them to runtime keys
* to pass to the index AM (see nodeIndexscan.c). We model the per-tuple
@@ -6397,6 +6405,7 @@ genericcostestimate(PlannerInfo *root,
*/
costs->indexStartupCost = indexStartupCost;
costs->indexTotalCost = indexTotalCost;
+ costs->indexSerialCost = indexSerialCost;
costs->indexSelectivity = indexSelectivity;
costs->indexCorrelation = indexCorrelation;
costs->numIndexPages = numIndexPages;
@@ -6449,6 +6458,7 @@ add_predicate_to_quals(IndexOptInfo *index, List *indexQuals)
void
btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
Cost *indexStartupCost, Cost *indexTotalCost,
+ Cost *indexSerialCost,
Selectivity *indexSelectivity, double *indexCorrelation)
{
IndexOptInfo *index = path->indexinfo;
@@ -6737,6 +6747,7 @@ btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
*indexStartupCost = costs.indexStartupCost;
*indexTotalCost = costs.indexTotalCost;
+ *indexSerialCost = costs.indexSerialCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
}
@@ -6744,6 +6755,7 @@ btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
void
hashcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
Cost *indexStartupCost, Cost *indexTotalCost,
+ Cost *indexSerialCost,
Selectivity *indexSelectivity, double *indexCorrelation)
{
List *qinfos;
@@ -6783,6 +6795,7 @@ hashcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
*indexStartupCost = costs.indexStartupCost;
*indexTotalCost = costs.indexTotalCost;
+ *indexSerialCost = costs.indexSerialCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
}
@@ -6790,6 +6803,7 @@ hashcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
void
gistcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
Cost *indexStartupCost, Cost *indexTotalCost,
+ Cost *indexSerialCost,
Selectivity *indexSelectivity, double *indexCorrelation)
{
IndexOptInfo *index = path->indexinfo;
@@ -6842,6 +6856,7 @@ gistcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
*indexStartupCost = costs.indexStartupCost;
*indexTotalCost = costs.indexTotalCost;
+ *indexSerialCost = costs.indexSerialCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
}
@@ -6849,6 +6864,7 @@ gistcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
void
spgcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
Cost *indexStartupCost, Cost *indexTotalCost,
+ Cost *indexSerialCost,
Selectivity *indexSelectivity, double *indexCorrelation)
{
IndexOptInfo *index = path->indexinfo;
@@ -6901,6 +6917,7 @@ spgcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
*indexStartupCost = costs.indexStartupCost;
*indexTotalCost = costs.indexTotalCost;
+ *indexSerialCost = costs.indexSerialCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
}
@@ -7200,6 +7217,7 @@ gincost_scalararrayopexpr(PlannerInfo *root,
void
gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
Cost *indexStartupCost, Cost *indexTotalCost,
+ Cost *indexSerialCost,
Selectivity *indexSelectivity, double *indexCorrelation)
{
IndexOptInfo *index = path->indexinfo;
@@ -7505,6 +7523,12 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
dataPagesFetched * spc_random_page_cost;
/*
+ * Everything after this point is just CPU overhead, which permits
+ * effective parallelism.
+ */
+ *indexSerialCost = *indexTotalCost;
+
+ /*
* Add on index qual eval costs, much as in genericcostestimate
*/
qual_arg_cost = other_operands_eval_cost(root, qinfos) +
@@ -7523,6 +7547,7 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
void
brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
Cost *indexStartupCost, Cost *indexTotalCost,
+ Cost *indexSerialCost,
Selectivity *indexSelectivity, double *indexCorrelation)
{
IndexOptInfo *index = path->indexinfo;
@@ -7558,6 +7583,12 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
*/
*indexTotalCost = spc_random_page_cost * numPages * loop_count;
+ /*
+ * Everything after this point is just CPU overhead, which permits
+ * effective parallelism.
+ */
+ *indexSerialCost = *indexTotalCost;
+
*indexSelectivity =
clauselist_selectivity(root, indexQuals,
path->indexinfo->rel->relid,
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
index 35f1061b3a..908b0d11dc 100644
--- a/src/include/access/amapi.h
+++ b/src/include/access/amapi.h
@@ -65,6 +65,7 @@ typedef void (*amcostestimate_function) (struct PlannerInfo *root,
double loop_count,
Cost *indexStartupCost,
Cost *indexTotalCost,
+ Cost *indexSerialCost,
Selectivity *indexSelectivity,
double *indexCorrelation);
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 00b1d35d75..30e5a97afb 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -102,6 +102,7 @@ typedef struct Plan
*/
Cost startup_cost; /* cost expended before fetching any tuples */
Cost total_cost; /* total cost (assuming all tuples fetched) */
+ Cost serial_cost; /* non-parallelizable portion of total cost */
/*
* planner's estimate of result size of this plan step
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index ee7007aace..26417291e6 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -845,6 +845,7 @@ typedef struct Path
double rows; /* estimated number of result tuples */
Cost startup_cost; /* cost expended before fetching any tuples */
Cost total_cost; /* total cost (assuming all tuples fetched) */
+ Cost serial_cost; /* non-parallelizable portion of total cost */
List *pathkeys; /* sort ordering of path's output */
/* pathkeys is a List of PathKey nodes; see above */
@@ -900,10 +901,11 @@ typedef struct Path
* NoMovementScanDirection for an indexscan, but the planner wants to
* distinguish ordered from unordered indexes for building pathkeys.)
*
- * 'indextotalcost' and 'indexselectivity' are saved in the IndexPath so that
- * we need not recompute them when considering using the same index in a
- * bitmap index/heap scan (see BitmapHeapPath). The costs of the IndexPath
- * itself represent the costs of an IndexScan or IndexOnlyScan plan type.
+ * 'indextotalcost', 'indexserialcost', and 'indexselectivity' are saved in
+ * the IndexPath so that we need not recompute them when considering using the
+ * same index in a * bitmap index/heap scan (see BitmapHeapPath). The costs
+ * of the IndexPath itself represent the costs of an IndexScan or IndexOnlyScan
+ * plan type.
*----------
*/
typedef struct IndexPath
@@ -917,6 +919,7 @@ typedef struct IndexPath
List *indexorderbycols;
ScanDirection indexscandir;
Cost indextotalcost;
+ Cost indexserialcost;
Selectivity indexselectivity;
} IndexPath;
diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h
index d4adca6836..6e693d498f 100644
--- a/src/include/optimizer/cost.h
+++ b/src/include/optimizer/cost.h
@@ -82,7 +82,8 @@ extern void cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *bas
Path *bitmapqual, double loop_count);
extern void cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root);
extern void cost_bitmap_or_node(BitmapOrPath *path, PlannerInfo *root);
-extern void cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec);
+extern void cost_bitmap_tree_node(Path *path, Cost *total_cost,
+ Cost *serial_cost, Selectivity *selec);
extern void cost_tidscan(Path *path, PlannerInfo *root,
RelOptInfo *baserel, List *tidquals, ParamPathInfo *param_info);
extern void cost_subqueryscan(SubqueryScanPath *path, PlannerInfo *root,
@@ -101,23 +102,23 @@ extern void cost_sort(Path *path, PlannerInfo *root,
extern void cost_merge_append(Path *path, PlannerInfo *root,
List *pathkeys, int n_streams,
Cost input_startup_cost, Cost input_total_cost,
- double tuples);
+ Cost input_serial_cost, double tuples);
extern void cost_material(Path *path,
Cost input_startup_cost, Cost input_total_cost,
- double tuples, int width);
+ Cost input_serial_cost, double tuples, int width);
extern void cost_agg(Path *path, PlannerInfo *root,
AggStrategy aggstrategy, const AggClauseCosts *aggcosts,
int numGroupCols, double numGroups,
Cost input_startup_cost, Cost input_total_cost,
- double input_tuples);
+ Cost input_serial_cost, double input_tuples);
extern void cost_windowagg(Path *path, PlannerInfo *root,
List *windowFuncs, int numPartCols, int numOrderCols,
Cost input_startup_cost, Cost input_total_cost,
- double input_tuples);
+ Cost input_serial_cost, double input_tuples);
extern void cost_group(Path *path, PlannerInfo *root,
int numGroupCols, double numGroups,
Cost input_startup_cost, Cost input_total_cost,
- double input_tuples);
+ Cost input_serial_cost, double input_tuples);
extern void initial_cost_nestloop(PlannerInfo *root,
JoinCostWorkspace *workspace,
JoinType jointype,
diff --git a/src/include/utils/index_selfuncs.h b/src/include/utils/index_selfuncs.h
index a03e12f518..2e051b74f4 100644
--- a/src/include/utils/index_selfuncs.h
+++ b/src/include/utils/index_selfuncs.h
@@ -27,6 +27,7 @@ extern void brincostestimate(struct PlannerInfo *root,
double loop_count,
Cost *indexStartupCost,
Cost *indexTotalCost,
+ Cost *indexSerialCost,
Selectivity *indexSelectivity,
double *indexCorrelation);
extern void btcostestimate(struct PlannerInfo *root,
@@ -34,6 +35,7 @@ extern void btcostestimate(struct PlannerInfo *root,
double loop_count,
Cost *indexStartupCost,
Cost *indexTotalCost,
+ Cost *indexSerialCost,
Selectivity *indexSelectivity,
double *indexCorrelation);
extern void hashcostestimate(struct PlannerInfo *root,
@@ -41,6 +43,7 @@ extern void hashcostestimate(struct PlannerInfo *root,
double loop_count,
Cost *indexStartupCost,
Cost *indexTotalCost,
+ Cost *indexSerialCost,
Selectivity *indexSelectivity,
double *indexCorrelation);
extern void gistcostestimate(struct PlannerInfo *root,
@@ -48,6 +51,7 @@ extern void gistcostestimate(struct PlannerInfo *root,
double loop_count,
Cost *indexStartupCost,
Cost *indexTotalCost,
+ Cost *indexSerialCost,
Selectivity *indexSelectivity,
double *indexCorrelation);
extern void spgcostestimate(struct PlannerInfo *root,
@@ -55,6 +59,7 @@ extern void spgcostestimate(struct PlannerInfo *root,
double loop_count,
Cost *indexStartupCost,
Cost *indexTotalCost,
+ Cost *indexSerialCost,
Selectivity *indexSelectivity,
double *indexCorrelation);
extern void gincostestimate(struct PlannerInfo *root,
@@ -62,6 +67,7 @@ extern void gincostestimate(struct PlannerInfo *root,
double loop_count,
Cost *indexStartupCost,
Cost *indexTotalCost,
+ Cost *indexSerialCost,
Selectivity *indexSelectivity,
double *indexCorrelation);