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.
This commit is contained in:
parent
c7464720a3
commit
d2a4a4069f
@ -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 @@
|
|||||||
#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,
|
|||||||
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,
|
|||||||
((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,
|
|||||||
|
|
||||||
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 @@
|
|||||||
* 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
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
REVERSEDIRECTION(state);
|
REVERSEDIRECTION(state);
|
||||||
|
|
||||||
state->status = TSS_SORTEDINMEM;
|
state->status = TSS_SORTEDINMEM;
|
||||||
|
state->boundUsed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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,
|
|||||||
|
|
||||||
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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user