Commit d2a4a406 authored by Tom Lane's avatar Tom Lane

Add a line to the EXPLAIN ANALYZE output for a Sort node, showing the

actual sort strategy and amount of space used.  By popular demand.
parent c7464720
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.162 2007/04/27 22:05:47 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.163 2007/05/04 21:29:52 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/guc.h" #include "utils/guc.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/tuplesort.h"
typedef struct ExplainState typedef struct ExplainState
...@@ -58,6 +59,8 @@ static void show_upper_qual(List *qual, const char *qlabel, Plan *plan, ...@@ -58,6 +59,8 @@ static void show_upper_qual(List *qual, const char *qlabel, Plan *plan,
static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols, static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
const char *qlabel, const char *qlabel,
StringInfo str, int indent, ExplainState *es); StringInfo str, int indent, ExplainState *es);
static void show_sort_info(SortState *sortstate,
StringInfo str, int indent, ExplainState *es);
/* /*
* ExplainQuery - * ExplainQuery -
...@@ -818,6 +821,8 @@ explain_outNode(StringInfo str, ...@@ -818,6 +821,8 @@ explain_outNode(StringInfo str,
((Sort *) plan)->sortColIdx, ((Sort *) plan)->sortColIdx,
"Sort Key", "Sort Key",
str, indent, es); str, indent, es);
show_sort_info((SortState *) planstate,
str, indent, es);
break; break;
case T_Result: case T_Result:
show_upper_qual((List *) ((Result *) plan)->resconstantqual, show_upper_qual((List *) ((Result *) plan)->resconstantqual,
...@@ -1123,3 +1128,25 @@ show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols, ...@@ -1123,3 +1128,25 @@ show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
appendStringInfo(str, "\n"); appendStringInfo(str, "\n");
} }
/*
* If it's EXPLAIN ANALYZE, show tuplesort explain info for a sort node
*/
static void
show_sort_info(SortState *sortstate,
StringInfo str, int indent, ExplainState *es)
{
Assert(IsA(sortstate, SortState));
if (es->printAnalyze && sortstate->sort_Done &&
sortstate->tuplesortstate != NULL)
{
char *sortinfo;
int i;
sortinfo = tuplesort_explain((Tuplesortstate *) sortstate->tuplesortstate);
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " %s\n", sortinfo);
pfree(sortinfo);
}
}
...@@ -91,7 +91,7 @@ ...@@ -91,7 +91,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.75 2007/05/04 01:13:44 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.76 2007/05/04 21:29:53 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -196,6 +196,7 @@ struct Tuplesortstate ...@@ -196,6 +196,7 @@ struct Tuplesortstate
bool randomAccess; /* did caller request random access? */ bool randomAccess; /* did caller request random access? */
bool bounded; /* did caller specify a maximum number of bool bounded; /* did caller specify a maximum number of
* tuples to return? */ * tuples to return? */
bool boundUsed; /* true if we made use of a bounded heap */
int bound; /* if bounded, the maximum number of tuples */ int bound; /* if bounded, the maximum number of tuples */
long availMem; /* remaining memory available, in bytes */ long availMem; /* remaining memory available, in bytes */
long allowedMem; /* total memory allowed, in bytes */ long allowedMem; /* total memory allowed, in bytes */
...@@ -505,6 +506,8 @@ tuplesort_begin_common(int workMem, bool randomAccess) ...@@ -505,6 +506,8 @@ tuplesort_begin_common(int workMem, bool randomAccess)
state->status = TSS_INITIAL; state->status = TSS_INITIAL;
state->randomAccess = randomAccess; state->randomAccess = randomAccess;
state->bounded = false;
state->boundUsed = false;
state->allowedMem = workMem * 1024L; state->allowedMem = workMem * 1024L;
state->availMem = state->allowedMem; state->availMem = state->allowedMem;
state->sortcontext = sortcontext; state->sortcontext = sortcontext;
...@@ -2113,6 +2116,64 @@ tuplesort_restorepos(Tuplesortstate *state) ...@@ -2113,6 +2116,64 @@ tuplesort_restorepos(Tuplesortstate *state)
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
} }
/*
* tuplesort_explain - produce a line of information for EXPLAIN ANALYZE
*
* This can be called after tuplesort_performsort() finishes to obtain
* printable summary information about how the sort was performed.
*
* The result is a palloc'd string.
*/
char *
tuplesort_explain(Tuplesortstate *state)
{
char *result = (char *) palloc(100);
long spaceUsed;
/*
* Note: it might seem we should print both memory and disk usage for a
* disk-based sort. However, the current code doesn't track memory space
* accurately once we have begun to return tuples to the caller (since
* we don't account for pfree's the caller is expected to do), so we
* cannot rely on availMem in a disk sort. This does not seem worth the
* overhead to fix. Is it worth creating an API for the memory context
* code to tell us how much is actually used in sortcontext?
*/
if (state->tapeset)
spaceUsed = LogicalTapeSetBlocks(state->tapeset) * (BLCKSZ / 1024);
else
spaceUsed = (state->allowedMem - state->availMem + 1023) / 1024;
switch (state->status)
{
case TSS_SORTEDINMEM:
if (state->boundUsed)
snprintf(result, 100,
"Sort Method: top-N heapsort Memory: %ldkB",
spaceUsed);
else
snprintf(result, 100,
"Sort Method: quicksort Memory: %ldkB",
spaceUsed);
break;
case TSS_SORTEDONTAPE:
snprintf(result, 100,
"Sort Method: external sort Disk: %ldkB",
spaceUsed);
break;
case TSS_FINALMERGE:
snprintf(result, 100,
"Sort Method: external merge Disk: %ldkB",
spaceUsed);
break;
default:
snprintf(result, 100, "sort still in progress");
break;
}
return result;
}
/* /*
* Heap manipulation routines, per Knuth's Algorithm 5.2.3H. * Heap manipulation routines, per Knuth's Algorithm 5.2.3H.
...@@ -2216,6 +2277,7 @@ sort_bounded_heap(Tuplesortstate *state) ...@@ -2216,6 +2277,7 @@ sort_bounded_heap(Tuplesortstate *state)
REVERSEDIRECTION(state); REVERSEDIRECTION(state);
state->status = TSS_SORTEDINMEM; state->status = TSS_SORTEDINMEM;
state->boundUsed = true;
} }
/* /*
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/tuplesort.h,v 1.26 2007/05/04 01:13:45 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/tuplesort.h,v 1.27 2007/05/04 21:29:53 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -74,6 +74,8 @@ extern bool tuplesort_getdatum(Tuplesortstate *state, bool forward, ...@@ -74,6 +74,8 @@ extern bool tuplesort_getdatum(Tuplesortstate *state, bool forward,
extern void tuplesort_end(Tuplesortstate *state); extern void tuplesort_end(Tuplesortstate *state);
extern char *tuplesort_explain(Tuplesortstate *state);
extern int tuplesort_merge_order(long allowedMem); extern int tuplesort_merge_order(long allowedMem);
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment