diff --git a/doc/src/sgml/perform.sgml b/doc/src/sgml/perform.sgml index 604e8578a8d..ea8da01b779 100644 --- a/doc/src/sgml/perform.sgml +++ b/doc/src/sgml/perform.sgml @@ -325,6 +325,7 @@ EXPLAIN SELECT * FROM tenk1 ORDER BY hundred, ten LIMIT 100; -> Incremental Sort (cost=19.35..2033.39 rows=10000 width=244) Sort Key: hundred, ten Presorted Key: hundred + Estimated Groups: 100 -> Index Scan using tenk1_hundred on tenk1 (cost=0.29..1574.20 rows=10000 width=244) diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index a40d03d35f3..f223c12f294 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -3306,11 +3306,16 @@ static void show_incremental_sort_info(IncrementalSortState *incrsortstate, ExplainState *es) { + IncrementalSort *plan = (IncrementalSort *) incrsortstate->ss.ps.plan; IncrementalSortGroupInfo *fullsortGroupInfo; IncrementalSortGroupInfo *prefixsortGroupInfo; fullsortGroupInfo = &incrsortstate->incsort_info.fullsortGroupInfo; + if (es->costs) + ExplainPropertyFloat("Estimated Groups", NULL, + plan->numGroups, 0, es); + if (!es->analyze) return; diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index ac523ecf9a8..fd794c946ab 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -2049,6 +2049,9 @@ cost_tuplesort(Cost *startup_cost, Cost *run_cost, * We estimate the number of groups into which the relation is divided by the * leading pathkeys, and then calculate the cost of sorting a single group * with tuplesort using cost_tuplesort(). + * + * If num_groups is not NULL, *num_groups gets set to the estimated number of + * sort groups. */ void cost_incremental_sort(Path *path, @@ -2056,7 +2059,8 @@ cost_incremental_sort(Path *path, int input_disabled_nodes, Cost input_startup_cost, Cost input_total_cost, double input_tuples, int width, Cost comparison_cost, int sort_mem, - double limit_tuples) + double limit_tuples, + Cardinality *num_groups) { Cost startup_cost, run_cost, @@ -2184,6 +2188,10 @@ cost_incremental_sort(Path *path, path->startup_cost = startup_cost; path->total_cost = startup_cost + run_cost; + + /* set output parameter values */ + if (num_groups) + *num_groups = input_groups; } /* @@ -2407,7 +2415,8 @@ cost_append(AppendPath *apath, PlannerInfo *root) subpath->pathtarget->width, 0.0, work_mem, - apath->limit_tuples); + apath->limit_tuples, + NULL); } else { @@ -3850,7 +3859,8 @@ initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace, outer_path->pathtarget->width, 0.0, work_mem, - -1.0); + -1.0, + NULL); } else { diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index ab392ef60fe..79b83a4d305 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -2074,6 +2074,7 @@ create_incrementalsort_plan(PlannerInfo *root, IncrementalSortPath *best_path, best_path->nPresortedCols); copy_generic_path_info(&plan->sort.plan, (Path *) best_path); + plan->numGroups = best_path->numGroups; return plan; } @@ -5469,7 +5470,8 @@ label_incrementalsort_with_costsize(PlannerInfo *root, IncrementalSort *plan, lefttree->plan_width, 0.0, work_mem, - limit_tuples); + limit_tuples, + &plan->numGroups); plan->sort.plan.startup_cost = sort_path.startup_cost; plan->sort.plan.total_cost = sort_path.total_cost; plan->sort.plan.plan_rows = lefttree->plan_rows; diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 3875e3dd571..a8dcad72958 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -1605,7 +1605,8 @@ create_merge_append_path(PlannerInfo *root, subpath->pathtarget->width, 0.0, work_mem, - pathnode->limit_tuples); + pathnode->limit_tuples, + NULL); } else { @@ -2883,7 +2884,8 @@ create_incremental_sort_path(PlannerInfo *root, subpath->rows, subpath->pathtarget->width, 0.0, /* XXX comparison_cost shouldn't be 0? */ - work_mem, limit_tuples); + work_mem, limit_tuples, + &sort->numGroups); sort->nPresortedCols = presorted_keys; diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index 27a2c6815b7..d9650315016 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -2548,6 +2548,7 @@ typedef struct IncrementalSortPath { SortPath spath; int nPresortedCols; /* number of presorted columns */ + Cardinality numGroups; /* estimated number of groups in input */ } IncrementalSortPath; /* diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index b880ce0f4be..2fe6b61afaf 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -1171,6 +1171,8 @@ typedef struct IncrementalSort Sort sort; /* number of presorted columns */ int nPresortedCols; + /* estimated number of groups in input */ + Cardinality numGroups; } IncrementalSort; /* --------------- diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h index bda3f1690c0..14255c900fc 100644 --- a/src/include/optimizer/cost.h +++ b/src/include/optimizer/cost.h @@ -118,7 +118,8 @@ extern void cost_incremental_sort(Path *path, int input_disabled_nodes, Cost input_startup_cost, Cost input_total_cost, double input_tuples, int width, Cost comparison_cost, int sort_mem, - double limit_tuples); + double limit_tuples, + Cardinality *num_groups); extern void cost_append(AppendPath *apath, PlannerInfo *root); extern void cost_merge_append(Path *path, PlannerInfo *root, List *pathkeys, int n_streams,