1
0
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:
David Rowley
2026-08-11 13:30:07 +12:00
parent 086f6f1760
commit d29d469bec
8 changed files with 31 additions and 7 deletions

View File

@@ -325,6 +325,7 @@ EXPLAIN SELECT * FROM tenk1 ORDER BY hundred, ten LIMIT 100;
-&gt; Incremental Sort (cost=19.35..2033.39 rows=10000 width=244)
Sort Key: hundred, ten
Presorted Key: hundred
Estimated Groups: 100
-&gt; Index Scan using tenk1_hundred on tenk1 (cost=0.29..1574.20 rows=10000 width=244)
</screen>

View File

@@ -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;

View File

@@ -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
{

View File

@@ -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;

View File

@@ -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;

View File

@@ -2548,6 +2548,7 @@ typedef struct IncrementalSortPath
{
SortPath spath;
int nPresortedCols; /* number of presorted columns */
Cardinality numGroups; /* estimated number of groups in input */
} IncrementalSortPath;
/*

View File

@@ -1171,6 +1171,8 @@ typedef struct IncrementalSort
Sort sort;
/* number of presorted columns */
int nPresortedCols;
/* estimated number of groups in input */
Cardinality numGroups;
} IncrementalSort;
/* ---------------

View File

@@ -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,