mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 00:03:57 -04:00 
			
		
		
		
	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 | ||||
|  * | ||||
|  * 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); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
| /*
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user