diff options
author | Robert Haas | 2016-03-23 11:57:46 +0000 |
---|---|---|
committer | Robert Haas | 2016-03-23 11:57:46 +0000 |
commit | 0336843939401dab8d8fbfe75e0631fea5d4c060 (patch) | |
tree | f6dae5de5651a4a231044f56f7c860bc816dcf0a | |
parent | b283096534b9c514a92a70c98c033015b6792ba7 (diff) |
not all jointypes done - rest in theory isserial_cost
-rw-r--r-- | src/backend/commands/explain.c | 7 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 1 | ||||
-rw-r--r-- | src/backend/nodes/outfuncs.c | 3 | ||||
-rw-r--r-- | src/backend/nodes/readfuncs.c | 1 | ||||
-rw-r--r-- | src/backend/optimizer/path/costsize.c | 151 | ||||
-rw-r--r-- | src/backend/optimizer/path/indxpath.c | 13 | ||||
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 3 | ||||
-rw-r--r-- | src/backend/optimizer/prep/prepunion.c | 4 | ||||
-rw-r--r-- | src/backend/optimizer/util/pathnode.c | 15 | ||||
-rw-r--r-- | src/backend/utils/adt/selfuncs.c | 31 | ||||
-rw-r--r-- | src/include/access/amapi.h | 1 | ||||
-rw-r--r-- | src/include/nodes/plannodes.h | 1 | ||||
-rw-r--r-- | src/include/nodes/relation.h | 11 | ||||
-rw-r--r-- | src/include/optimizer/cost.h | 13 | ||||
-rw-r--r-- | src/include/utils/index_selfuncs.h | 6 |
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); |