*** ./doc/src/sgml/config.sgml.orig 2008-03-11 16:59:09.000000000 +0000
--- ./doc/src/sgml/config.sgml 2008-07-03 14:20:15.000000000 +0100
***************
*** 2674,2679 ****
--- 2674,2700 ----
+
+ debug_explain_min_duration (integer)
+
+ debug_explain_min_duration> configuration parameter
+
+
+
+ This option, together with ,
+ enables logging of debug messages explaining all SQL queries which
+ run for at least the specified number of milliseconds. Setting this
+ to zero (the default) will cause all statement execution plans to be
+ explained, when is on.
+
+
+
+ When if off, no statements
+ are explained, and this parameter has no effect.
+
+
+
+
silent_mode (boolean)
***************
*** 2794,2799 ****
--- 2815,2822 ----
debug_print_rewritten (boolean)
debug_print_plan (boolean)
debug_pretty_print (boolean)
+
+ debug_explain_plan (boolean)
debug_print_parse> configuration parameter
***************
*** 2806,2811 ****
--- 2829,2837 ----
debug_pretty_print> configuration parameter
+
+ debug_explain_plan> configuration parameter
+
These parameters enable various debugging output to be emitted.
***************
*** 2813,2824 ****
the resulting parse tree, the query rewriter output, or the
execution plan. debug_pretty_print indents
these displays to produce a more readable but much longer
! output format. client_min_messages or
log_min_messages must be
DEBUG1 or lower to actually send this output
to the client or the server log, respectively.
These parameters are off by default.
--- 2839,2867 ----
the resulting parse tree, the query rewriter output, or the
execution plan. debug_pretty_print indents
these displays to produce a more readable but much longer
! output format. debug_explain_plan prints
! the plan for each executed query in the same format as
! EXPLAIN ANALYZE>. This includes queries executed from
! within functions. client_min_messages or
log_min_messages must be
DEBUG1 or lower to actually send this output
to the client or the server log, respectively.
These parameters are off by default.
+
+
+
+ The reports produced by debug_explain_plan
+ are produced at a lower level in the database, as each query
+ is executed, including queries executed from functions, so
+ the output may be more verbose that of EXPLAIN ANALYZE>
+ and the timings may differ. When this option is used together
+ with , all queries
+ will be instrumented, but only those which run for at least the
+ specified number of milliseconds will have their execution plans
+ reported.
+
+
*** ./src/backend/commands/explain.c.orig 2008-01-01 19:45:49.000000000 +0000
--- ./src/backend/commands/explain.c 2008-06-27 12:06:19.000000000 +0100
***************
*** 39,65 ****
/* Hook for plugins to get control in explain_get_index_name() */
explain_get_index_name_hook_type explain_get_index_name_hook = NULL;
-
- typedef struct ExplainState
- {
- /* options */
- bool printTList; /* print plan targetlists */
- bool printAnalyze; /* print actual times */
- /* other states */
- PlannedStmt *pstmt; /* top of plan */
- List *rtable; /* range table */
- } ExplainState;
-
static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
const char *queryString,
ParamListInfo params, TupOutputState *tstate);
static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
StringInfo buf);
- static double elapsed_time(instr_time *starttime);
- static void explain_outNode(StringInfo str,
- Plan *plan, PlanState *planstate,
- Plan *outer_plan,
- int indent, ExplainState *es);
static void show_plan_tlist(Plan *plan,
StringInfo str, int indent, ExplainState *es);
static void show_scan_qual(List *qual, const char *qlabel,
--- 39,49 ----
***************
*** 402,408 ****
}
/* Compute elapsed time in seconds since given timestamp */
! static double
elapsed_time(instr_time *starttime)
{
instr_time endtime;
--- 386,392 ----
}
/* Compute elapsed time in seconds since given timestamp */
! double
elapsed_time(instr_time *starttime)
{
instr_time endtime;
***************
*** 436,442 ****
* side of a join with the current node. This is only interesting for
* deciphering runtime keys of an inner indexscan.
*/
! static void
explain_outNode(StringInfo str,
Plan *plan, PlanState *planstate,
Plan *outer_plan,
--- 420,426 ----
* side of a join with the current node. This is only interesting for
* deciphering runtime keys of an inner indexscan.
*/
! void
explain_outNode(StringInfo str,
Plan *plan, PlanState *planstate,
Plan *outer_plan,
*** ./src/backend/executor/execMain.c.orig 2008-04-21 04:49:51.000000000 +0100
--- ./src/backend/executor/execMain.c 2008-07-03 09:49:52.000000000 +0100
***************
*** 39,44 ****
--- 39,45 ----
#include "catalog/heap.h"
#include "catalog/namespace.h"
#include "catalog/toasting.h"
+ #include "commands/explain.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "executor/execdebug.h"
***************
*** 52,57 ****
--- 53,59 ----
#include "utils/acl.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
+ #include "utils/guc.h"
#include "utils/snapmgr.h"
#include "utils/tqual.h"
***************
*** 185,190 ****
--- 187,200 ----
}
/*
+ * If we are explaining all queries, enable instrumentation.
+ * Even if we are only explaining the slow queries, we still
+ * need to instrument them all.
+ */
+ if (Debug_explain_plan)
+ queryDesc->doInstrument = true;
+
+ /*
* Copy other important information into the EState
*/
estate->es_snapshot = queryDesc->snapshot;
***************
*** 227,232 ****
--- 237,245 ----
bool sendTuples;
TupleTableSlot *result;
MemoryContext oldcontext;
+ bool explainPlan = Debug_explain_plan;
+ instr_time starttime;
+ double totaltime;
/* sanity checks */
Assert(queryDesc != NULL);
***************
*** 236,241 ****
--- 249,265 ----
Assert(estate != NULL);
/*
+ * If explaining all queries, record the start time before running
+ * the query. This is not quite the same as EXPLAIN ANALYSE, which
+ * starts timing before ExecutorStart(). Here we are only timing
+ * how long the query takes to run, once initialised and also
+ * excluding any triggers (which may themselves run queries which
+ * will be instrumented separately).
+ */
+ if (explainPlan)
+ INSTR_TIME_SET_CURRENT(starttime);
+
+ /*
* Switch into per-query memory context
*/
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
***************
*** 279,284 ****
--- 303,341 ----
MemoryContextSwitchTo(oldcontext);
+ /*
+ * If explaining queries and this one was slow enough, log the
+ * execution plan using the same format as EXPLAIN ANALYSE
+ */
+ totaltime = elapsed_time(&starttime);
+ if (explainPlan && totaltime * 1000 >= Debug_explain_min_duration)
+ {
+ ExplainState *es;
+ StringInfoData buf;
+
+ es = (ExplainState *) palloc0(sizeof(ExplainState));
+
+ es->printTList = false;
+ es->printAnalyze = true;
+ es->pstmt = queryDesc->plannedstmt;
+ es->rtable = queryDesc->plannedstmt->rtable;
+
+ initStringInfo(&buf);
+ explain_outNode(&buf,
+ queryDesc->plannedstmt->planTree,
+ queryDesc->planstate,
+ NULL, 0, es);
+
+ appendStringInfo(&buf, "Query runtime: %.3f ms",
+ 1000.0 * totaltime);
+
+ ereport(DEBUG1,
+ (errmsg("Query plan:\n%s", buf.data)));
+
+ pfree(buf.data);
+ pfree(es);
+ }
+
return result;
}
*** ./src/backend/utils/misc/guc.c.orig 2008-05-26 19:54:36.000000000 +0100
--- ./src/backend/utils/misc/guc.c 2008-07-03 09:49:30.000000000 +0100
***************
*** 194,199 ****
--- 194,201 ----
bool Debug_print_parse = false;
bool Debug_print_rewritten = false;
bool Debug_pretty_print = false;
+ bool Debug_explain_plan = false;
+ int Debug_explain_min_duration = 0;
bool log_parser_stats = false;
bool log_planner_stats = false;
***************
*** 686,691 ****
--- 688,701 ----
false, NULL, NULL
},
{
+ {"debug_explain_plan", PGC_USERSET, LOGGING_WHAT,
+ gettext_noop("Explains the execution plan to server log."),
+ NULL
+ },
+ &Debug_explain_plan,
+ false, NULL, NULL
+ },
+ {
{"log_parser_stats", PGC_SUSET, STATS_MONITORING,
gettext_noop("Writes parser performance statistics to the server log."),
NULL
***************
*** 1567,1572 ****
--- 1577,1593 ----
},
{
+ {"debug_explain_min_duration", PGC_USERSET, LOGGING_WHEN,
+ gettext_noop("Sets the minimum execution time above which "
+ "statements will be explained."),
+ gettext_noop("0 causes all statements to be explained."),
+ GUC_UNIT_MS
+ },
+ &Debug_explain_min_duration,
+ 0, 0, INT_MAX / 1000, NULL, NULL
+ },
+
+ {
{"log_autovacuum_min_duration", PGC_SIGHUP, LOGGING_WHAT,
gettext_noop("Sets the minimum execution time above which "
"autovacuum actions will be logged."),
*** ./src/backend/utils/misc/postgresql.conf.sample.orig 2008-01-30 18:35:55.000000000 +0000
--- ./src/backend/utils/misc/postgresql.conf.sample 2008-07-03 10:08:57.000000000 +0100
***************
*** 313,318 ****
--- 313,322 ----
# and their durations, > 0 logs only
# statements running at least this time.
+ #debug_explain_min_duration = 0 # limits the output of debug_explain_plan
+ # to queries which run for at least the
+ # the specified number of milliseconds.
+
#silent_mode = off # DO NOT USE without syslog or
# logging_collector
# (change requires restart)
***************
*** 323,328 ****
--- 327,333 ----
#debug_print_rewritten = off
#debug_print_plan = off
#debug_pretty_print = off
+ #debug_explain_plan = off
#log_checkpoints = off
#log_connections = off
#log_disconnections = off
*** ./src/include/commands/explain.h.orig 2008-01-01 19:45:57.000000000 +0000
--- ./src/include/commands/explain.h 2008-06-27 12:06:19.000000000 +0100
***************
*** 14,19 ****
--- 14,30 ----
#define EXPLAIN_H
#include "executor/executor.h"
+ #include "executor/instrument.h"
+
+ typedef struct ExplainState
+ {
+ /* options */
+ bool printTList; /* print plan targetlists */
+ bool printAnalyze; /* print actual times */
+ /* other states */
+ PlannedStmt *pstmt; /* top of plan */
+ List *rtable; /* range table */
+ } ExplainState;
/* Hook for plugins to get control in ExplainOneQuery() */
typedef void (*ExplainOneQuery_hook_type) (Query *query,
***************
*** 41,44 ****
--- 52,62 ----
extern void ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
ExplainStmt *stmt, TupOutputState *tstate);
+ extern void explain_outNode(StringInfo str,
+ Plan *plan, PlanState *planstate,
+ Plan *outer_plan,
+ int indent, ExplainState *es);
+
+ extern double elapsed_time(instr_time *starttime);
+
#endif /* EXPLAIN_H */
*** ./src/include/utils/guc.h.orig 2008-01-01 19:45:59.000000000 +0000
--- ./src/include/utils/guc.h 2008-07-02 20:46:55.000000000 +0100
***************
*** 117,122 ****
--- 117,124 ----
extern bool Debug_print_parse;
extern bool Debug_print_rewritten;
extern bool Debug_pretty_print;
+ extern bool Debug_explain_plan;
+ extern int Debug_explain_min_duration;
extern bool log_parser_stats;
extern bool log_planner_stats;