From d2a4a4069f1677d74267c04d558a8be83a382098 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 4 May 2007 21:29:53 +0000 Subject: [PATCH] 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. --- src/backend/commands/explain.c | 29 +++++++++++++- src/backend/utils/sort/tuplesort.c | 64 +++++++++++++++++++++++++++++- src/include/utils/tuplesort.h | 4 +- 3 files changed, 94 insertions(+), 3 deletions(-) diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 592eeba417..608ebf93ce 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994-5, Regents of the University of California * * 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/guc.h" #include "utils/lsyscache.h" +#include "utils/tuplesort.h" 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, const char *qlabel, StringInfo str, int indent, ExplainState *es); +static void show_sort_info(SortState *sortstate, + StringInfo str, int indent, ExplainState *es); /* * ExplainQuery - @@ -818,6 +821,8 @@ explain_outNode(StringInfo str, ((Sort *) plan)->sortColIdx, "Sort Key", str, indent, es); + show_sort_info((SortState *) planstate, + str, indent, es); break; case T_Result: show_upper_qual((List *) ((Result *) plan)->resconstantqual, @@ -1123,3 +1128,25 @@ show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols, 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); + } +} diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c index e4fc74b3e9..707112d5fb 100644 --- a/src/backend/utils/sort/tuplesort.c +++ b/src/backend/utils/sort/tuplesort.c @@ -91,7 +91,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * 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 bounded; /* did caller specify a maximum number of * tuples to return? */ + bool boundUsed; /* true if we made use of a bounded heap */ int bound; /* if bounded, the maximum number of tuples */ long availMem; /* remaining memory available, 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->randomAccess = randomAccess; + state->bounded = false; + state->boundUsed = false; state->allowedMem = workMem * 1024L; state->availMem = state->allowedMem; state->sortcontext = sortcontext; @@ -2113,6 +2116,64 @@ tuplesort_restorepos(Tuplesortstate *state) 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. @@ -2216,6 +2277,7 @@ sort_bounded_heap(Tuplesortstate *state) REVERSEDIRECTION(state); state->status = TSS_SORTEDINMEM; + state->boundUsed = true; } /* diff --git a/src/include/utils/tuplesort.h b/src/include/utils/tuplesort.h index c736896a9a..b522c3ef7b 100644 --- a/src/include/utils/tuplesort.h +++ b/src/include/utils/tuplesort.h @@ -13,7 +13,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * 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 char *tuplesort_explain(Tuplesortstate *state); + extern int tuplesort_merge_order(long allowedMem); /*