v34-0003-Rework-EXPLAIN-for-incremental-sort.patch
text/x-patch
Filename: v34-0003-Rework-EXPLAIN-for-incremental-sort.patch
Type: text/x-patch
Part: 1
Patch
Format: format-patch
Series: patch v34-0003
Subject: Rework EXPLAIN for incremental sort
| File | + | − |
|---|---|---|
| src/backend/commands/explain.c | 122 | 131 |
| src/backend/executor/nodeIncrementalSort.c | 91 | 30 |
| src/include/nodes/execnodes.h | 19 | 10 |
| src/test/regress/expected/incremental_sort.out | 160 | 0 |
| src/test/regress/sql/incremental_sort.sql | 10 | 0 |
From 83dabf98119a2d8f0b5c420da694fdbd1eeb5078 Mon Sep 17 00:00:00 2001
From: James Coleman <jtc331@gmail.com>
Date: Sat, 7 Mar 2020 17:09:39 -0500
Subject: [PATCH v34 3/3] Rework EXPLAIN for incremental sort
---
src/backend/commands/explain.c | 253 +++++++++---------
src/backend/executor/nodeIncrementalSort.c | 121 ++++++---
src/include/nodes/execnodes.h | 29 +-
.../regress/expected/incremental_sort.out | 160 +++++++++++
src/test/regress/sql/incremental_sort.sql | 10 +
5 files changed, 402 insertions(+), 171 deletions(-)
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 14aedec919..8262c54e6a 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -2701,80 +2701,114 @@ show_sort_info(SortState *sortstate, ExplainState *es)
}
}
-/*
- * If it's EXPLAIN ANALYZE, show tuplesort stats for a incremental sort node
- */
+
static void
-show_incremental_sort_info(IncrementalSortState *incrsortstate,
- ExplainState *es)
+show_incremental_sort_group_info(IncrementalSortGroupInfo *groupInfo,
+ const char *groupLabel, ExplainState *es)
{
- if (es->analyze && incrsortstate->sort_Done &&
- incrsortstate->fullsort_state != NULL)
+ const char *sortMethodName;
+ const char *spaceTypeName;
+ ListCell *methodCell;
+ int methodCount = list_length(groupInfo->sortMethods);
+
+ if (es->format == EXPLAIN_FORMAT_TEXT)
{
- /* TODO: is it valid to get space used etc. only once given we re-use the sort? */
- /* TODO: maybe show average, min, max sort group size? */
-
- Tuplesortstate *fullsort_state = incrsortstate->fullsort_state;
- TuplesortInstrumentation fullsort_stats;
- const char *fullsort_sortMethod;
- const char *fullsort_spaceType;
- Tuplesortstate *prefixsort_state = incrsortstate->prefixsort_state;
- TuplesortInstrumentation prefixsort_stats;
- const char *prefixsort_sortMethod;
- const char *prefixsort_spaceType;
-
- tuplesort_get_stats(fullsort_state, &fullsort_stats);
- fullsort_sortMethod = tuplesort_method_name(fullsort_stats.sortMethod);
- fullsort_spaceType = tuplesort_space_type_name(fullsort_stats.spaceType);
- if (prefixsort_state != NULL)
+ appendStringInfoSpaces(es->str, es->indent * 2);
+ appendStringInfo(es->str, "%s Groups: %ld (Methods: ", groupLabel,
+ groupInfo->groupCount);
+ foreach(methodCell, groupInfo->sortMethods)
{
- tuplesort_get_stats(prefixsort_state, &prefixsort_stats);
- prefixsort_sortMethod = tuplesort_method_name(prefixsort_stats.sortMethod);
- prefixsort_spaceType = tuplesort_space_type_name(prefixsort_stats.spaceType);
+ sortMethodName = tuplesort_method_name(methodCell->int_value);
+ appendStringInfo(es->str, "%s", sortMethodName);
+ if (foreach_current_index(methodCell) < methodCount - 1)
+ appendStringInfo(es->str, ", ");
}
+ appendStringInfo(es->str, ")");
- if (es->format == EXPLAIN_FORMAT_TEXT)
+ if (groupInfo->maxMemorySpaceUsed > 0)
{
- appendStringInfoSpaces(es->str, es->indent * 2);
- appendStringInfo(es->str, "Sort Method: Full: %s %s: %ldkB",
- fullsort_sortMethod, fullsort_spaceType,
- fullsort_stats.spaceUsed);
- if (prefixsort_state != NULL)
- appendStringInfo(es->str, ", Prefix-only: %s %s: %ldkB\n",
- prefixsort_sortMethod, prefixsort_spaceType,
- prefixsort_stats.spaceUsed);
- else
- appendStringInfo(es->str, "\n");
- appendStringInfoSpaces(es->str, es->indent * 2);
- appendStringInfo(es->str, "Sort Groups: Full: %ld",
- incrsortstate->fullsort_group_count);
- if (prefixsort_state != NULL)
- appendStringInfo(es->str, ", Prefix-only: %ld\n",
- incrsortstate->prefixsort_group_count);
- else
- appendStringInfo(es->str, "\n");
+ long avgSpace = groupInfo->totalMemorySpaceUsed / groupInfo->groupCount;
+ spaceTypeName = tuplesort_space_type_name(SORT_SPACE_TYPE_MEMORY);
+ appendStringInfo(es->str, " %s: %ldkB (avg), %ldkB (max)",
+ spaceTypeName, avgSpace,
+ groupInfo->maxMemorySpaceUsed);
}
- else
+
+ if (groupInfo->maxDiskSpaceUsed > 0)
{
- /* TODO */
- ExplainPropertyText("Full Sort Method", fullsort_sortMethod, es);
- ExplainPropertyInteger("Full Sort Space Used", "kB",
- fullsort_stats.spaceUsed, es);
- ExplainPropertyText("Full Sort Space Type", fullsort_spaceType, es);
- ExplainPropertyInteger("Full Sort Groups", NULL,
- incrsortstate->fullsort_group_count, es);
-
- if (prefixsort_state != NULL)
- {
- ExplainPropertyText("Prefix Sort Method", prefixsort_sortMethod, es);
- ExplainPropertyInteger("Prefix Sort Space Used", "kB",
- prefixsort_stats.spaceUsed, es);
- ExplainPropertyText("Prefix Sort Space Type", prefixsort_spaceType, es);
- ExplainPropertyInteger("Prefix Sort Groups", NULL,
- incrsortstate->prefixsort_group_count, es);
- }
+ long avgSpace = groupInfo->totalDiskSpaceUsed / groupInfo->groupCount;
+ spaceTypeName = tuplesort_space_type_name(SORT_SPACE_TYPE_DISK);
+ /* Add a semicolon separator only if memory stats were printed. */
+ if (groupInfo->maxMemorySpaceUsed > 0)
+ appendStringInfo(es->str, ";");
+ appendStringInfo(es->str, " %s: %ldkB (avg), %ldkB (max)",
+ spaceTypeName, avgSpace,
+ groupInfo->maxDiskSpaceUsed);
+ }
+
+ appendStringInfo(es->str, "\n");
+ }
+ else
+ {
+ List *methodNames = NIL;
+ StringInfoData groupName;
+
+ initStringInfo(&groupName);
+ appendStringInfo(&groupName, "%s Groups", groupLabel);
+ ExplainOpenGroup("Incremental Sort Groups", groupName.data, true, es);
+ ExplainPropertyInteger("Group Count", NULL, groupInfo->groupCount, es);
+
+ foreach(methodCell, groupInfo->sortMethods)
+ {
+ sortMethodName = tuplesort_method_name(methodCell->int_value);
+ methodNames = lappend(methodNames, sortMethodName);
+ }
+ ExplainPropertyList("Sort Methods Used", methodNames, es);
+
+ if (groupInfo->maxMemorySpaceUsed > 0)
+ {
+ long avgSpace = groupInfo->totalMemorySpaceUsed / groupInfo->groupCount;
+
+ ExplainPropertyInteger("Average Sort Space Used", "kB", avgSpace, es);
+ ExplainPropertyInteger("Maximum Sort Space Used", "kB",
+ groupInfo->maxMemorySpaceUsed, es);
+ spaceTypeName = tuplesort_space_type_name(SORT_SPACE_TYPE_MEMORY);
+ ExplainPropertyText("Sort Space Type", spaceTypeName, es);
+ }
+ if (groupInfo->maxDiskSpaceUsed > 0)
+ {
+ long avgSpace = groupInfo->totalDiskSpaceUsed / groupInfo->groupCount;
+
+ ExplainPropertyInteger("Average Sort Space Used", "kB", avgSpace, es);
+ ExplainPropertyInteger("Maximum Sort Space Used", "kB",
+ groupInfo->maxDiskSpaceUsed, es);
+ spaceTypeName = tuplesort_space_type_name(SORT_SPACE_TYPE_MEMORY);
+ ExplainPropertyText("Sort Space Type", spaceTypeName, es);
}
+
+ ExplainCloseGroup("Incremental Sort Groups", "XXX Groups", true, es);
}
+}
+
+/*
+ * If it's EXPLAIN ANALYZE, show tuplesort stats for a incremental sort node
+ */
+static void
+show_incremental_sort_info(IncrementalSortState *incrsortstate,
+ ExplainState *es)
+{
+ IncrementalSortGroupInfo *fullsortGroupInfo;
+ IncrementalSortGroupInfo *prefixsortGroupInfo;
+
+ if (!(es->analyze && incrsortstate->sort_Done))
+ return;
+
+ fullsortGroupInfo = &incrsortstate->incsort_info.fullsortGroupInfo;
+ if (fullsortGroupInfo->groupCount > 0)
+ show_incremental_sort_group_info(fullsortGroupInfo, "Full-sort", es);
+ prefixsortGroupInfo = &incrsortstate->incsort_info.prefixsortGroupInfo;
+ if (prefixsortGroupInfo->groupCount > 0)
+ show_incremental_sort_group_info(prefixsortGroupInfo, "Presorted", es);
if (incrsortstate->shared_info != NULL)
{
@@ -2785,79 +2819,36 @@ show_incremental_sort_info(IncrementalSortState *incrsortstate,
{
IncrementalSortInfo *incsort_info =
&incrsortstate->shared_info->sinfo[n];
- TuplesortInstrumentation *fullsort_instrument;
- const char *fullsort_sortMethod;
- const char *fullsort_spaceType;
- long fullsort_spaceUsed;
- int64 fullsort_group_count;
- TuplesortInstrumentation *prefixsort_instrument;
- const char *prefixsort_sortMethod;
- const char *prefixsort_spaceType;
- long prefixsort_spaceUsed;
- int64 prefixsort_group_count;
-
- fullsort_instrument = &incsort_info->fullsort_instrument;
- fullsort_group_count = incsort_info->fullsort_group_count;
-
- prefixsort_instrument = &incsort_info->prefixsort_instrument;
- prefixsort_group_count = incsort_info->prefixsort_group_count;
-
- if (fullsort_instrument->sortMethod == SORT_TYPE_STILL_IN_PROGRESS)
- continue; /* ignore any unfilled slots */
-
- fullsort_sortMethod = tuplesort_method_name(
- fullsort_instrument->sortMethod);
- fullsort_spaceType = tuplesort_space_type_name(
- fullsort_instrument->spaceType);
- fullsort_spaceUsed = fullsort_instrument->spaceUsed;
+ /*
+ * XXX: The previous version of the patch chcked:
+ * fullsort_instrument->sortMethod == SORT_TYPE_STILL_IN_PROGRESS
+ * and continued if the condition was true (with the comment "ignore
+ * any unfilled slots").
+ * I'm not convinced that makes sense since the same sort instrument
+ * can have been used multiple times, so the last time it being used
+ * being still in progress, doesn't seem to be relevant.
+ * Instead I'm now checking to see if the group count for each group
+ * info is 0. If both are 0, then we exclude the worker since it
+ * didn't contribute anything meaningful.
+ */
+ fullsortGroupInfo = &incsort_info->fullsortGroupInfo;
+ prefixsortGroupInfo = &incsort_info->prefixsortGroupInfo;
+ if (fullsortGroupInfo->groupCount == 0 &&
+ prefixsortGroupInfo->groupCount == 0)
+ continue;
- if (prefixsort_instrument)
+ if (!opened_group)
{
- prefixsort_sortMethod = tuplesort_method_name(
- prefixsort_instrument->sortMethod);
- prefixsort_spaceType = tuplesort_space_type_name(
- prefixsort_instrument->spaceType);
- prefixsort_spaceUsed = prefixsort_instrument->spaceUsed;
+ ExplainOpenGroup("Workers", "Workers", false, es);
+ opened_group = true;
}
- if (es->format == EXPLAIN_FORMAT_TEXT)
- {
- appendStringInfoSpaces(es->str, es->indent * 2);
- appendStringInfo(es->str,
- "Worker %d: Full Sort Method: %s %s: %ldkB Groups: %ld",
- n, fullsort_sortMethod, fullsort_spaceType,
- fullsort_spaceUsed, fullsort_group_count);
- if (prefixsort_instrument)
- appendStringInfo(es->str,
- ", Prefix Sort Method: %s %s: %ldkB Groups: %ld\n",
- prefixsort_sortMethod, prefixsort_spaceType,
- prefixsort_spaceUsed, prefixsort_group_count);
- else
- appendStringInfo(es->str, "\n");
- }
- else
- {
- if (!opened_group)
- {
- ExplainOpenGroup("Workers", "Workers", false, es);
- opened_group = true;
- }
- ExplainOpenGroup("Worker", NULL, true, es);
- ExplainPropertyInteger("Worker Number", NULL, n, es);
- ExplainPropertyText("Full Sort Method", fullsort_sortMethod, es);
- ExplainPropertyInteger("Full Sort Space Used", "kB", fullsort_spaceUsed, es);
- ExplainPropertyText("Full Sort Space Type", fullsort_spaceType, es);
- ExplainPropertyInteger("Full Sort Groups", NULL, fullsort_group_count, es);
- if (prefixsort_instrument)
- {
- ExplainPropertyText("Prefix Sort Method", prefixsort_sortMethod, es);
- ExplainPropertyInteger("Prefix Sort Space Used", "kB", prefixsort_spaceUsed, es);
- ExplainPropertyText("Prefix Sort Space Type", prefixsort_spaceType, es);
- ExplainPropertyInteger("Prefix Sort Groups", NULL, prefixsort_group_count, es);
- }
- ExplainCloseGroup("Worker", NULL, true, es);
- }
+ if (fullsortGroupInfo->groupCount > 0)
+ show_incremental_sort_group_info(fullsortGroupInfo, "Full-sort", es);
+ if (prefixsortGroupInfo->groupCount > 0)
+ show_incremental_sort_group_info(prefixsortGroupInfo, "Presorted", es);
}
+
if (opened_group)
ExplainCloseGroup("Workers", "Workers", false, es);
}
diff --git a/src/backend/executor/nodeIncrementalSort.c b/src/backend/executor/nodeIncrementalSort.c
index c3b903e568..e6f749a798 100644
--- a/src/backend/executor/nodeIncrementalSort.c
+++ b/src/backend/executor/nodeIncrementalSort.c
@@ -68,6 +68,47 @@
#include "utils/lsyscache.h"
#include "utils/tuplesort.h"
+static void
+instrumentSortedGroup(PlanState *pstate, IncrementalSortGroupInfo *groupInfo,
+ Tuplesortstate *sortState)
+{
+ IncrementalSortState *node = castNode(IncrementalSortState, pstate);
+ TuplesortInstrumentation sort_instr;
+
+ groupInfo->groupCount++;
+
+ tuplesort_get_stats(sortState, &sort_instr);
+ switch (sort_instr.spaceType)
+ {
+ case SORT_SPACE_TYPE_DISK:
+ groupInfo->totalDiskSpaceUsed += sort_instr.spaceUsed;
+ if (sort_instr.spaceUsed > groupInfo->maxDiskSpaceUsed)
+ groupInfo->maxDiskSpaceUsed = sort_instr.spaceUsed;
+
+ break;
+ case SORT_SPACE_TYPE_MEMORY:
+ groupInfo->totalMemorySpaceUsed += sort_instr.spaceUsed;
+ if (sort_instr.spaceUsed > groupInfo->maxMemorySpaceUsed)
+ groupInfo->maxMemorySpaceUsed = sort_instr.spaceUsed;
+
+ break;
+ }
+
+ if (!list_member_int(groupInfo->sortMethods, sort_instr.sortMethod))
+ groupInfo->sortMethods = lappend_int(groupInfo->sortMethods,
+ sort_instr.sortMethod);
+
+ /* Record shared stats if we're a parallel worker. */
+ if (node->shared_info && node->am_worker)
+ {
+ Assert(IsParallelWorker());
+ Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
+
+ memcpy(&node->shared_info->sinfo[ParallelWorkerNumber],
+ &node->incsort_info, sizeof(IncrementalSortInfo));
+ }
+}
+
/*
* Prepare information for presorted_keys comparison.
*/
@@ -199,8 +240,9 @@ isCurrentGroup(IncrementalSortState *node, TupleTableSlot *pivot, TupleTableSlot
* one different prefix key group before the large prefix key group.
*/
static void
-switchToPresortedPrefixMode(IncrementalSortState *node)
+switchToPresortedPrefixMode(PlanState *pstate)
{
+ IncrementalSortState *node = castNode(IncrementalSortState, pstate);
ScanDirection dir;
int64 nTuples = 0;
bool lastTuple = false;
@@ -355,7 +397,11 @@ switchToPresortedPrefixMode(IncrementalSortState *node)
*/
SO1_printf("Sorting presorted prefix tuplesort with %ld tuples\n", nTuples);
tuplesort_performsort(node->prefixsort_state);
- node->prefixsort_group_count++;
+
+ if (pstate->instrument != NULL)
+ instrumentSortedGroup(pstate,
+ &node->incsort_info.prefixsortGroupInfo,
+ node->prefixsort_state);
if (node->bounded)
{
@@ -479,7 +525,7 @@ ExecIncrementalSort(PlanState *pstate)
*/
SO1_printf("Re-calling switchToPresortedPrefixMode() because n_fullsort_remaining is > 0 (%ld)\n",
node->n_fullsort_remaining);
- switchToPresortedPrefixMode(node);
+ switchToPresortedPrefixMode(pstate);
}
else
{
@@ -602,7 +648,11 @@ ExecIncrementalSort(PlanState *pstate)
SO1_printf("Sorting fullsort with %ld tuples\n", nTuples);
tuplesort_performsort(fullsort_state);
- node->fullsort_group_count++;
+
+ if (pstate->instrument != NULL)
+ instrumentSortedGroup(pstate,
+ &node->incsort_info.fullsortGroupInfo,
+ fullsort_state);
SO_printf("Setting execution_status to INCSORT_READFULLSORT (final tuple) \n");
node->execution_status = INCSORT_READFULLSORT;
@@ -673,7 +723,12 @@ ExecIncrementalSort(PlanState *pstate)
*/
SO1_printf("Sorting fullsort tuplesort with %ld tuples\n", nTuples);
tuplesort_performsort(fullsort_state);
- node->fullsort_group_count++;
+
+ if (pstate->instrument != NULL)
+ instrumentSortedGroup(pstate,
+ &node->incsort_info.fullsortGroupInfo,
+ fullsort_state);
+
SO_printf("Setting execution_status to INCSORT_READFULLSORT (found end of group)\n");
node->execution_status = INCSORT_READFULLSORT;
break;
@@ -705,7 +760,10 @@ ExecIncrementalSort(PlanState *pstate)
*/
SO1_printf("Sorting fullsort tuplesort with %ld tuples\n", nTuples);
tuplesort_performsort(fullsort_state);
- node->fullsort_group_count++;
+ if (pstate->instrument != NULL)
+ instrumentSortedGroup(pstate,
+ &node->incsort_info.fullsortGroupInfo,
+ fullsort_state);
/*
* If the full sort tuplesort happened to switch into top-n heapsort mode
@@ -735,7 +793,7 @@ ExecIncrementalSort(PlanState *pstate)
node->n_fullsort_remaining = nTuples;
/* Transition the tuples to the presorted prefix tuplesort. */
- switchToPresortedPrefixMode(node);
+ switchToPresortedPrefixMode(pstate);
/*
* Since we know we had tuples to move to the presorted prefix
@@ -801,7 +859,12 @@ ExecIncrementalSort(PlanState *pstate)
/* Perform the sort and return the tuples to the inner plan nodes. */
SO1_printf("Sorting presorted prefix tuplesort with >= %ld tuples\n", nTuples);
tuplesort_performsort(node->prefixsort_state);
- node->prefixsort_group_count++;
+
+ if (pstate->instrument != NULL)
+ instrumentSortedGroup(pstate,
+ &node->incsort_info.prefixsortGroupInfo,
+ node->prefixsort_state);
+
SO_printf("Setting execution_status to INCSORT_READPREFIXSORT (found end of group)\n");
node->execution_status = INCSORT_READPREFIXSORT;
@@ -828,26 +891,6 @@ ExecIncrementalSort(PlanState *pstate)
*/
node->sort_Done = true;
- /* Record shared stats if we're a parallel worker. */
- if (node->shared_info && node->am_worker)
- {
- IncrementalSortInfo *incsort_info =
- &node->shared_info->sinfo[ParallelWorkerNumber];
-
- Assert(IsParallelWorker());
- Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
-
- tuplesort_get_stats(fullsort_state, &incsort_info->fullsort_instrument);
- incsort_info->fullsort_group_count = node->fullsort_group_count;
-
- if (node->prefixsort_state)
- {
- tuplesort_get_stats(node->prefixsort_state,
- &incsort_info->prefixsort_instrument);
- incsort_info->prefixsort_group_count = node->prefixsort_group_count;
- }
- }
-
/*
* Get the first or next tuple from tuplesort. Returns NULL if no more
* tuples.
@@ -900,10 +943,28 @@ ExecInitIncrementalSort(IncrementalSort *node, EState *estate, int eflags)
incrsortstate->transfer_tuple = NULL;
incrsortstate->n_fullsort_remaining = 0;
incrsortstate->bound_Done = 0;
- incrsortstate->fullsort_group_count = 0;
- incrsortstate->prefixsort_group_count = 0;
incrsortstate->presorted_keys = NULL;
+ if (incrsortstate->ss.ps.instrument != NULL)
+ {
+ IncrementalSortGroupInfo *fullsortGroupInfo =
+ &incrsortstate->incsort_info.fullsortGroupInfo;
+ IncrementalSortGroupInfo *prefixsortGroupInfo =
+ &incrsortstate->incsort_info.prefixsortGroupInfo;
+ fullsortGroupInfo->groupCount = 0;
+ fullsortGroupInfo->maxDiskSpaceUsed = 0;
+ fullsortGroupInfo->totalDiskSpaceUsed = 0;
+ fullsortGroupInfo->maxMemorySpaceUsed = 0;
+ fullsortGroupInfo->totalMemorySpaceUsed = 0;
+ fullsortGroupInfo->sortMethods = NIL;
+ prefixsortGroupInfo->groupCount = 0;
+ prefixsortGroupInfo->maxDiskSpaceUsed = 0;
+ prefixsortGroupInfo->totalDiskSpaceUsed = 0;
+ prefixsortGroupInfo->maxMemorySpaceUsed = 0;
+ prefixsortGroupInfo->totalMemorySpaceUsed = 0;
+ prefixsortGroupInfo->sortMethods = NIL;
+ }
+
/*
* Miscellaneous initialization
*
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index f905e384a2..0934482123 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -2022,18 +2022,26 @@ typedef struct SortState
SharedSortInfo *shared_info; /* one entry per worker */
} SortState;
-/* ----------------
- * Shared memory container for per-worker incremental sort information
- * ----------------
- */
+typedef struct IncrementalSortGroupInfo
+{
+ int64 groupCount;
+ long maxDiskSpaceUsed;
+ long totalDiskSpaceUsed;
+ long maxMemorySpaceUsed;
+ long totalMemorySpaceUsed;
+ List *sortMethods;
+} IncrementalSortGroupInfo;
+
typedef struct IncrementalSortInfo
{
- TuplesortInstrumentation fullsort_instrument;
- int64 fullsort_group_count;
- TuplesortInstrumentation prefixsort_instrument;
- int64 prefixsort_group_count;
+ IncrementalSortGroupInfo fullsortGroupInfo;
+ IncrementalSortGroupInfo prefixsortGroupInfo;
} IncrementalSortInfo;
+/* ----------------
+ * Shared memory container for per-worker incremental sort information
+ * ----------------
+ */
typedef struct SharedIncrementalSortInfo
{
int num_workers;
@@ -2067,8 +2075,9 @@ typedef struct IncrementalSortState
Tuplesortstate *prefixsort_state; /* private state of tuplesort.c */
/* the keys by which the input path is already sorted */
PresortedKeyData *presorted_keys;
- int64 fullsort_group_count; /* number of groups with equal presorted keys */
- int64 prefixsort_group_count; /* number of groups with equal presorted keys */
+
+ IncrementalSortInfo incsort_info;
+
/* slot for pivot tuple defining values of presorted keys within group */
TupleTableSlot *group_pivot;
TupleTableSlot *transfer_tuple;
diff --git a/src/test/regress/expected/incremental_sort.out b/src/test/regress/expected/incremental_sort.out
index 3a58efdf91..7892b111d7 100644
--- a/src/test/regress/expected/incremental_sort.out
+++ b/src/test/regress/expected/incremental_sort.out
@@ -436,6 +436,82 @@ select * from (select * from t order by a) s order by a, b limit 55;
2 | 55
(55 rows)
+-- Test EXPLAIN ANALYZE (text output) with only a fullsort group.
+explain (analyze, costs off, summary off, timing off)
+select * from (select * from t order by a) s order by a, b limit 55;
+ QUERY PLAN
+-------------------------------------------------------------------------------------------------
+ Limit (actual rows=55 loops=1)
+ -> Incremental Sort (actual rows=55 loops=1)
+ Sort Key: t.a, t.b
+ Presorted Key: t.a
+ Full-sort Groups: 2 (Methods: quicksort, top-N heapsort) Memory: 27kB (avg), 27kB (max)
+ -> Sort (actual rows=100 loops=1)
+ Sort Key: t.a
+ Sort Method: quicksort Memory: 30kB
+ -> Seq Scan on t (actual rows=100 loops=1)
+(9 rows)
+
+explain (analyze, costs off, summary off, timing off, format json)
+select * from (select * from t order by a) s order by a, b limit 55;
+ QUERY PLAN
+-------------------------------------------------------------------
+ [ +
+ { +
+ "Plan": { +
+ "Node Type": "Limit", +
+ "Parallel Aware": false, +
+ "Actual Rows": 55, +
+ "Actual Loops": 1, +
+ "Plans": [ +
+ { +
+ "Node Type": "Incremental Sort", +
+ "Parent Relationship": "Outer", +
+ "Parallel Aware": false, +
+ "Actual Rows": 55, +
+ "Actual Loops": 1, +
+ "Sort Key": ["t.a", "t.b"], +
+ "Presorted Key": ["t.a"], +
+ "Full-sort Groups": { +
+ "Group Count": 2, +
+ "Sort Methods Used": ["quicksort", "top-N heapsort"],+
+ "Average Sort Space Used": 27, +
+ "Maximum Sort Space Used": 27, +
+ "Sort Space Type": "Memory" +
+ }, +
+ "Plans": [ +
+ { +
+ "Node Type": "Sort", +
+ "Parent Relationship": "Outer", +
+ "Parallel Aware": false, +
+ "Actual Rows": 100, +
+ "Actual Loops": 1, +
+ "Sort Key": ["t.a"], +
+ "Sort Method": "quicksort", +
+ "Sort Space Used": 30, +
+ "Sort Space Type": "Memory", +
+ "Plans": [ +
+ { +
+ "Node Type": "Seq Scan", +
+ "Parent Relationship": "Outer", +
+ "Parallel Aware": false, +
+ "Relation Name": "t", +
+ "Alias": "t", +
+ "Actual Rows": 100, +
+ "Actual Loops": 1 +
+ } +
+ ] +
+ } +
+ ] +
+ } +
+ ] +
+ }, +
+ "Triggers": [ +
+ ] +
+ } +
+ ]
+(1 row)
+
delete from t;
-- An initial small group followed by a large group.
insert into t(a, b) select (case when i < 5 then i else 9 end), i from generate_series(1, 100) n(i);
@@ -526,6 +602,90 @@ select * from (select * from t order by a) s order by a, b limit 70;
9 | 70
(70 rows)
+-- Test EXPLAIN ANALYZE (text output) with both fullsort and presorted groups.
+explain (analyze, costs off, summary off, timing off)
+select * from (select * from t order by a) s order by a, b limit 70;
+ QUERY PLAN
+---------------------------------------------------------------------------------
+ Limit (actual rows=70 loops=1)
+ -> Incremental Sort (actual rows=70 loops=1)
+ Sort Key: t.a, t.b
+ Presorted Key: t.a
+ Full-sort Groups: 1 (Methods: quicksort) Memory: 28kB (avg), 28kB (max)
+ Presorted Groups: 5 (Methods: quicksort) Memory: 26kB (avg), 30kB (max)
+ -> Sort (actual rows=100 loops=1)
+ Sort Key: t.a
+ Sort Method: quicksort Memory: 30kB
+ -> Seq Scan on t (actual rows=100 loops=1)
+(10 rows)
+
+explain (analyze, costs off, summary off, timing off, format json)
+select * from (select * from t order by a) s order by a, b limit 70;
+ QUERY PLAN
+---------------------------------------------------
+ [ +
+ { +
+ "Plan": { +
+ "Node Type": "Limit", +
+ "Parallel Aware": false, +
+ "Actual Rows": 70, +
+ "Actual Loops": 1, +
+ "Plans": [ +
+ { +
+ "Node Type": "Incremental Sort", +
+ "Parent Relationship": "Outer", +
+ "Parallel Aware": false, +
+ "Actual Rows": 70, +
+ "Actual Loops": 1, +
+ "Sort Key": ["t.a", "t.b"], +
+ "Presorted Key": ["t.a"], +
+ "Full-sort Groups": { +
+ "Group Count": 1, +
+ "Sort Methods Used": ["quicksort"], +
+ "Average Sort Space Used": 28, +
+ "Maximum Sort Space Used": 28, +
+ "Sort Space Type": "Memory" +
+ }, +
+ "Presorted Groups": { +
+ "Group Count": 5, +
+ "Sort Methods Used": ["quicksort"], +
+ "Average Sort Space Used": 26, +
+ "Maximum Sort Space Used": 30, +
+ "Sort Space Type": "Memory" +
+ }, +
+ "Plans": [ +
+ { +
+ "Node Type": "Sort", +
+ "Parent Relationship": "Outer", +
+ "Parallel Aware": false, +
+ "Actual Rows": 100, +
+ "Actual Loops": 1, +
+ "Sort Key": ["t.a"], +
+ "Sort Method": "quicksort", +
+ "Sort Space Used": 30, +
+ "Sort Space Type": "Memory", +
+ "Plans": [ +
+ { +
+ "Node Type": "Seq Scan", +
+ "Parent Relationship": "Outer",+
+ "Parallel Aware": false, +
+ "Relation Name": "t", +
+ "Alias": "t", +
+ "Actual Rows": 100, +
+ "Actual Loops": 1 +
+ } +
+ ] +
+ } +
+ ] +
+ } +
+ ] +
+ }, +
+ "Triggers": [ +
+ ] +
+ } +
+ ]
+(1 row)
+
delete from t;
-- Small groups of 10 tuples each tested around each mode transition point.
insert into t(a, b) select i / 10, i from generate_series(1, 70) n(i);
diff --git a/src/test/regress/sql/incremental_sort.sql b/src/test/regress/sql/incremental_sort.sql
index b9df37412f..9320a10b91 100644
--- a/src/test/regress/sql/incremental_sort.sql
+++ b/src/test/regress/sql/incremental_sort.sql
@@ -39,12 +39,22 @@ delete from t;
insert into t(a, b) select (case when i < 50 then 1 else 2 end), i from generate_series(1, 100) n(i);
explain (costs off) select * from (select * from t order by a) s order by a, b limit 55;
select * from (select * from t order by a) s order by a, b limit 55;
+-- Test EXPLAIN ANALYZE (text output) with only a fullsort group.
+explain (analyze, costs off, summary off, timing off)
+select * from (select * from t order by a) s order by a, b limit 55;
+explain (analyze, costs off, summary off, timing off, format json)
+select * from (select * from t order by a) s order by a, b limit 55;
delete from t;
-- An initial small group followed by a large group.
insert into t(a, b) select (case when i < 5 then i else 9 end), i from generate_series(1, 100) n(i);
explain (costs off) select * from (select * from t order by a) s order by a, b limit 70;
select * from (select * from t order by a) s order by a, b limit 70;
+-- Test EXPLAIN ANALYZE (text output) with both fullsort and presorted groups.
+explain (analyze, costs off, summary off, timing off)
+select * from (select * from t order by a) s order by a, b limit 70;
+explain (analyze, costs off, summary off, timing off, format json)
+select * from (select * from t order by a) s order by a, b limit 70;
delete from t;
-- Small groups of 10 tuples each tested around each mode transition point.
--
2.17.1