not all jointypes done - rest in theory is serial_cost
authorRobert Haas <rhaas@postgresql.org>
Wed, 23 Mar 2016 11:57:46 +0000 (07:57 -0400)
committerRobert Haas <rhaas@postgresql.org>
Wed, 23 Mar 2016 11:57:46 +0000 (07:57 -0400)
15 files changed:
src/backend/commands/explain.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/path/costsize.c
src/backend/optimizer/path/indxpath.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/prep/prepunion.c
src/backend/optimizer/util/pathnode.c
src/backend/utils/adt/selfuncs.c
src/include/access/amapi.h
src/include/nodes/plannodes.h
src/include/nodes/relation.h
src/include/optimizer/cost.h
src/include/utils/index_selfuncs.h

index 787b0b93cced229ab3d3ee1fde77c7784173a74d..d9ba63f8c9e9ddb9a188ff4e9062cf34d8ff0cb5 100644 (file)
@@ -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);
                }
index 6b5d1d6efce66e7949d18e176c0f148b932fc28b..546ed3d3f616920c32323f1e138a51c94ee3ded7 100644 (file)
@@ -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);
index 32d03f7f257ca483b6d340c0992bab0fe50fe6d4..2306877208a777d1338932e6e86b635dab57b2b0 100644 (file)
@@ -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");
 }
 
index 6db0492e152ada149ccf6ee9a30bba67d50dffb1..59ebab49ca1c1db5cf285b59f2700c79fa27bcaf 100644 (file)
@@ -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);
index 9f572d759b7c7635c40becb36bbddd12849dcbd5..ed3f4c6608ba7123ea7533f0211cf7c26c24b164 100644 (file)
@@ -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;
 }
 
 /*
index b48f5f28ea9a5ac1c0e60d7d6055852e78118db5..e17f1bb49fe36795fd7101e7d0e79da21d2f358b 100644 (file)
@@ -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.
index d159a17fd264ace9478945197343e827bc04151c..1fd99663a5d4dad69b65eb607878c5af9c7c0912 100644 (file)
@@ -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;
index fb139af2c1c9488b29f64a7535ed6b429e62e26d..04539a79758abbff2dacd111145643e19f0d936f 100644 (file)
@@ -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
index 16b34fcf46a51898e3c3ed037c741cd03fc5f75b..b13efebe34d7c18b532c2257c935c17a1fc8d091 100644 (file)
@@ -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;
index d396ef142f9563ce5f620152983a873c082439c8..a5ffc3516f9c22f1a3e215e98a562971bf1165ac 100644 (file)
@@ -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;
@@ -6364,6 +6366,12 @@ genericcostestimate(PlannerInfo *root,
                indexTotalCost = numIndexPages * spc_random_page_cost;
        }
 
+       /*
+        * 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
@@ -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;
@@ -7504,6 +7522,12 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
        *indexTotalCost = *indexStartupCost +
                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
         */
@@ -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,
index 35f1061b3a19ae4f2543b94d69ff4dae1fe21b0b..908b0d11dce9524c9371f9b2ff53cc89e5ca7f6a 100644 (file)
@@ -65,6 +65,7 @@ typedef void (*amcostestimate_function) (struct PlannerInfo *root,
                                                                                                         double loop_count,
                                                                                                         Cost *indexStartupCost,
                                                                                                         Cost *indexTotalCost,
+                                                                                                        Cost *indexSerialCost,
                                                                                           Selectivity *indexSelectivity,
                                                                                                   double *indexCorrelation);
 
index 00b1d35d75993b03b3184a2c4c8e18520e3aa6cb..30e5a97afb4d3ef64bdb42ac2730464786df68eb 100644 (file)
@@ -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
index ee7007aacec6ff1d92bb450ca84f5995481fdec2..26417291e691335a0b7fadca3744b6656575414d 100644 (file)
@@ -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;
 
index d4adca6836a30ead68c5299bd77da66d3ba34129..6e693d498f93f2f9e1246bf78e04f90f413eaf18 100644 (file)
@@ -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,
index a03e12f518f83a18f157fcd14892e67d80c0c3fb..2e051b74f427081268a324f08acbe058422402c7 100644 (file)
@@ -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);