Skip to content

Commit 85ce524

Browse files
Ilia Evdokimovhackorum
authored andcommitted
Show estimated number of groups for IncrementalSort in EXPLAIN
IncrementalSort cost heavily depends on the estimated number of groups with equal presorted key values. A bad estimate can cause the planner to choose IncrementalSort over Sort even when it would actually be slower, with no visible indication of why.
1 parent 6e89028 commit 85ce524

8 files changed

Lines changed: 30 additions & 7 deletions

File tree

doc/src/sgml/perform.sgml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ EXPLAIN SELECT * FROM tenk1 ORDER BY hundred, ten LIMIT 100;
325325
-> Incremental Sort (cost=19.35..2033.39 rows=10000 width=244)
326326
Sort Key: hundred, ten
327327
Presorted Key: hundred
328+
Estimated Groups: 100
328329
-> Index Scan using tenk1_hundred on tenk1 (cost=0.29..1574.20 rows=10000 width=244)
329330
</screen>
330331

src/backend/commands/explain.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3306,11 +3306,16 @@ static void
33063306
show_incremental_sort_info(IncrementalSortState *incrsortstate,
33073307
ExplainState *es)
33083308
{
3309+
IncrementalSort *plan = (IncrementalSort *) incrsortstate->ss.ps.plan;
33093310
IncrementalSortGroupInfo *fullsortGroupInfo;
33103311
IncrementalSortGroupInfo *prefixsortGroupInfo;
33113312

33123313
fullsortGroupInfo = &incrsortstate->incsort_info.fullsortGroupInfo;
33133314

3315+
if (es->costs)
3316+
ExplainPropertyFloat("Estimated Groups", NULL,
3317+
plan->numGroups, 0, es);
3318+
33143319
if (!es->analyze)
33153320
return;
33163321

src/backend/optimizer/path/costsize.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2046,6 +2046,9 @@ cost_tuplesort(Cost *startup_cost, Cost *run_cost,
20462046
* 'presorted_keys' is the number of leading pathkeys by which the input path
20472047
* is sorted.
20482048
*
2049+
* If p_numGroups is not NULL, *p_numGroups is set to the estimated number of
2050+
* sort groups (groups of tuples sharing equal presorted-key values).
2051+
*
20492052
* We estimate the number of groups into which the relation is divided by the
20502053
* leading pathkeys, and then calculate the cost of sorting a single group
20512054
* with tuplesort using cost_tuplesort().
@@ -2056,7 +2059,8 @@ cost_incremental_sort(Path *path,
20562059
int input_disabled_nodes,
20572060
Cost input_startup_cost, Cost input_total_cost,
20582061
double input_tuples, int width, Cost comparison_cost, int sort_mem,
2059-
double limit_tuples)
2062+
double limit_tuples,
2063+
Cardinality *p_numGroups)
20602064
{
20612065
Cost startup_cost,
20622066
run_cost,
@@ -2172,6 +2176,9 @@ cost_incremental_sort(Path *path,
21722176
*/
21732177
run_cost += 2.0 * cpu_tuple_cost * input_groups;
21742178

2179+
if (p_numGroups)
2180+
*p_numGroups = input_groups;
2181+
21752182
path->rows = input_tuples;
21762183

21772184
/*
@@ -2407,7 +2414,8 @@ cost_append(AppendPath *apath, PlannerInfo *root)
24072414
subpath->pathtarget->width,
24082415
0.0,
24092416
work_mem,
2410-
apath->limit_tuples);
2417+
apath->limit_tuples,
2418+
NULL);
24112419
}
24122420
else
24132421
{
@@ -3850,7 +3858,8 @@ initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace,
38503858
outer_path->pathtarget->width,
38513859
0.0,
38523860
work_mem,
3853-
-1.0);
3861+
-1.0,
3862+
NULL);
38543863
}
38553864
else
38563865
{

src/backend/optimizer/plan/createplan.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2074,6 +2074,7 @@ create_incrementalsort_plan(PlannerInfo *root, IncrementalSortPath *best_path,
20742074
best_path->nPresortedCols);
20752075

20762076
copy_generic_path_info(&plan->sort.plan, (Path *) best_path);
2077+
plan->numGroups = best_path->numGroups;
20772078

20782079
return plan;
20792080
}
@@ -5469,7 +5470,8 @@ label_incrementalsort_with_costsize(PlannerInfo *root, IncrementalSort *plan,
54695470
lefttree->plan_width,
54705471
0.0,
54715472
work_mem,
5472-
limit_tuples);
5473+
limit_tuples,
5474+
&plan->numGroups);
54735475
plan->sort.plan.startup_cost = sort_path.startup_cost;
54745476
plan->sort.plan.total_cost = sort_path.total_cost;
54755477
plan->sort.plan.plan_rows = lefttree->plan_rows;

src/backend/optimizer/util/pathnode.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,7 +1605,8 @@ create_merge_append_path(PlannerInfo *root,
16051605
subpath->pathtarget->width,
16061606
0.0,
16071607
work_mem,
1608-
pathnode->limit_tuples);
1608+
pathnode->limit_tuples,
1609+
NULL);
16091610
}
16101611
else
16111612
{
@@ -2883,7 +2884,8 @@ create_incremental_sort_path(PlannerInfo *root,
28832884
subpath->rows,
28842885
subpath->pathtarget->width,
28852886
0.0, /* XXX comparison_cost shouldn't be 0? */
2886-
work_mem, limit_tuples);
2887+
work_mem, limit_tuples,
2888+
&sort->numGroups);
28872889

28882890
sort->nPresortedCols = presorted_keys;
28892891

src/include/nodes/pathnodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2548,6 +2548,7 @@ typedef struct IncrementalSortPath
25482548
{
25492549
SortPath spath;
25502550
int nPresortedCols; /* number of presorted columns */
2551+
Cardinality numGroups; /* estimated number of groups */
25512552
} IncrementalSortPath;
25522553

25532554
/*

src/include/nodes/plannodes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,6 +1171,8 @@ typedef struct IncrementalSort
11711171
Sort sort;
11721172
/* number of presorted columns */
11731173
int nPresortedCols;
1174+
/* estimated number of groups (groups with equal presorted keys) */
1175+
Cardinality numGroups;
11741176
} IncrementalSort;
11751177

11761178
/* ---------------

src/include/optimizer/cost.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ extern void cost_incremental_sort(Path *path,
118118
int input_disabled_nodes,
119119
Cost input_startup_cost, Cost input_total_cost,
120120
double input_tuples, int width, Cost comparison_cost, int sort_mem,
121-
double limit_tuples);
121+
double limit_tuples,
122+
Cardinality *p_numGroups);
122123
extern void cost_append(AppendPath *apath, PlannerInfo *root);
123124
extern void cost_merge_append(Path *path, PlannerInfo *root,
124125
List *pathkeys, int n_streams,

0 commit comments

Comments
 (0)