mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
Show estimated number of groups for Incremental Sort in EXPLAIN
Incremental Sort's costs heavily depend on the estimated number of input groups with equal presorted key values. Overestimations can cause the planner to choose Incremental Sort over Sort when Sort would have been a better choice. Here, we add the planner's estimate to EXPLAIN to allow easier understanding of why Incremental Sort has been chosen. Author: Ilia Evdokimov <ilya.evdokimov@tantorlabs.com> Reviewed-by: Enrique Sánchez <enriqueesanchz@gmail.com> Reviewed-by: David Rowley <dgrowleyml@gmail.com> Reviewed-by: solai v <solai.cdac@gmail.com> Discussion: https://postgr.es/m/10682fef-3748-43f5-a932-7adcdd9bd2b8%40tantorlabs.com
This commit is contained in:
@@ -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)
|
||||
</screen>
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -2548,6 +2548,7 @@ typedef struct IncrementalSortPath
|
||||
{
|
||||
SortPath spath;
|
||||
int nPresortedCols; /* number of presorted columns */
|
||||
Cardinality numGroups; /* estimated number of groups in input */
|
||||
} IncrementalSortPath;
|
||||
|
||||
/*
|
||||
|
||||
@@ -1171,6 +1171,8 @@ typedef struct IncrementalSort
|
||||
Sort sort;
|
||||
/* number of presorted columns */
|
||||
int nPresortedCols;
|
||||
/* estimated number of groups in input */
|
||||
Cardinality numGroups;
|
||||
} IncrementalSort;
|
||||
|
||||
/* ---------------
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user