PostgreSQL Source Code  git master
auto_explain.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * auto_explain.c
4  *
5  *
6  * Copyright (c) 2008-2022, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  * contrib/auto_explain/auto_explain.c
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include "postgres.h"
14 
15 #include <limits.h>
16 
17 #include "access/parallel.h"
18 #include "commands/explain.h"
19 #include "common/pg_prng.h"
20 #include "executor/instrument.h"
21 #include "jit/jit.h"
22 #include "utils/guc.h"
23 
25 
26 /* GUC variables */
27 static int auto_explain_log_min_duration = -1; /* msec or -1 */
28 static bool auto_explain_log_analyze = false;
29 static bool auto_explain_log_verbose = false;
30 static bool auto_explain_log_buffers = false;
31 static bool auto_explain_log_wal = false;
32 static bool auto_explain_log_triggers = false;
33 static bool auto_explain_log_timing = true;
34 static bool auto_explain_log_settings = false;
38 static double auto_explain_sample_rate = 1;
39 
40 static const struct config_enum_entry format_options[] = {
41  {"text", EXPLAIN_FORMAT_TEXT, false},
42  {"xml", EXPLAIN_FORMAT_XML, false},
43  {"json", EXPLAIN_FORMAT_JSON, false},
44  {"yaml", EXPLAIN_FORMAT_YAML, false},
45  {NULL, 0, false}
46 };
47 
48 static const struct config_enum_entry loglevel_options[] = {
49  {"debug5", DEBUG5, false},
50  {"debug4", DEBUG4, false},
51  {"debug3", DEBUG3, false},
52  {"debug2", DEBUG2, false},
53  {"debug1", DEBUG1, false},
54  {"debug", DEBUG2, true},
55  {"info", INFO, false},
56  {"notice", NOTICE, false},
57  {"warning", WARNING, false},
58  {"log", LOG, false},
59  {NULL, 0, false}
60 };
61 
62 /* Current nesting depth of ExecutorRun calls */
63 static int nesting_level = 0;
64 
65 /* Is the current top-level query to be sampled? */
66 static bool current_query_sampled = false;
67 
68 #define auto_explain_enabled() \
69  (auto_explain_log_min_duration >= 0 && \
70  (nesting_level == 0 || auto_explain_log_nested_statements) && \
71  current_query_sampled)
72 
73 /* Saved hook values in case of unload */
78 
79 void _PG_init(void);
80 
81 static void explain_ExecutorStart(QueryDesc *queryDesc, int eflags);
82 static void explain_ExecutorRun(QueryDesc *queryDesc,
83  ScanDirection direction,
84  uint64 count, bool execute_once);
85 static void explain_ExecutorFinish(QueryDesc *queryDesc);
86 static void explain_ExecutorEnd(QueryDesc *queryDesc);
87 
88 
89 /*
90  * Module load callback
91  */
92 void
93 _PG_init(void)
94 {
95  /* Define custom GUC variables. */
96  DefineCustomIntVariable("auto_explain.log_min_duration",
97  "Sets the minimum execution time above which plans will be logged.",
98  "Zero prints all plans. -1 turns this feature off.",
100  -1,
101  -1, INT_MAX,
102  PGC_SUSET,
103  GUC_UNIT_MS,
104  NULL,
105  NULL,
106  NULL);
107 
108  DefineCustomBoolVariable("auto_explain.log_analyze",
109  "Use EXPLAIN ANALYZE for plan logging.",
110  NULL,
112  false,
113  PGC_SUSET,
114  0,
115  NULL,
116  NULL,
117  NULL);
118 
119  DefineCustomBoolVariable("auto_explain.log_settings",
120  "Log modified configuration parameters affecting query planning.",
121  NULL,
123  false,
124  PGC_SUSET,
125  0,
126  NULL,
127  NULL,
128  NULL);
129 
130  DefineCustomBoolVariable("auto_explain.log_verbose",
131  "Use EXPLAIN VERBOSE for plan logging.",
132  NULL,
134  false,
135  PGC_SUSET,
136  0,
137  NULL,
138  NULL,
139  NULL);
140 
141  DefineCustomBoolVariable("auto_explain.log_buffers",
142  "Log buffers usage.",
143  NULL,
145  false,
146  PGC_SUSET,
147  0,
148  NULL,
149  NULL,
150  NULL);
151 
152  DefineCustomBoolVariable("auto_explain.log_wal",
153  "Log WAL usage.",
154  NULL,
156  false,
157  PGC_SUSET,
158  0,
159  NULL,
160  NULL,
161  NULL);
162 
163  DefineCustomBoolVariable("auto_explain.log_triggers",
164  "Include trigger statistics in plans.",
165  "This has no effect unless log_analyze is also set.",
167  false,
168  PGC_SUSET,
169  0,
170  NULL,
171  NULL,
172  NULL);
173 
174  DefineCustomEnumVariable("auto_explain.log_format",
175  "EXPLAIN format to be used for plan logging.",
176  NULL,
180  PGC_SUSET,
181  0,
182  NULL,
183  NULL,
184  NULL);
185 
186  DefineCustomEnumVariable("auto_explain.log_level",
187  "Log level for the plan.",
188  NULL,
190  LOG,
192  PGC_SUSET,
193  0,
194  NULL,
195  NULL,
196  NULL);
197 
198  DefineCustomBoolVariable("auto_explain.log_nested_statements",
199  "Log nested statements.",
200  NULL,
202  false,
203  PGC_SUSET,
204  0,
205  NULL,
206  NULL,
207  NULL);
208 
209  DefineCustomBoolVariable("auto_explain.log_timing",
210  "Collect timing data, not just row counts.",
211  NULL,
213  true,
214  PGC_SUSET,
215  0,
216  NULL,
217  NULL,
218  NULL);
219 
220  DefineCustomRealVariable("auto_explain.sample_rate",
221  "Fraction of queries to process.",
222  NULL,
224  1.0,
225  0.0,
226  1.0,
227  PGC_SUSET,
228  0,
229  NULL,
230  NULL,
231  NULL);
232 
233  MarkGUCPrefixReserved("auto_explain");
234 
235  /* Install hooks. */
244 }
245 
246 /*
247  * ExecutorStart hook: start up logging if needed
248  */
249 static void
250 explain_ExecutorStart(QueryDesc *queryDesc, int eflags)
251 {
252  /*
253  * At the beginning of each top-level statement, decide whether we'll
254  * sample this statement. If nested-statement explaining is enabled,
255  * either all nested statements will be explained or none will.
256  *
257  * When in a parallel worker, we should do nothing, which we can implement
258  * cheaply by pretending we decided not to sample the current statement.
259  * If EXPLAIN is active in the parent session, data will be collected and
260  * reported back to the parent, and it's no business of ours to interfere.
261  */
262  if (nesting_level == 0)
263  {
266  else
267  current_query_sampled = false;
268  }
269 
270  if (auto_explain_enabled())
271  {
272  /* Enable per-node instrumentation iff log_analyze is required. */
273  if (auto_explain_log_analyze && (eflags & EXEC_FLAG_EXPLAIN_ONLY) == 0)
274  {
276  queryDesc->instrument_options |= INSTRUMENT_TIMER;
277  else
278  queryDesc->instrument_options |= INSTRUMENT_ROWS;
282  queryDesc->instrument_options |= INSTRUMENT_WAL;
283  }
284  }
285 
286  if (prev_ExecutorStart)
287  prev_ExecutorStart(queryDesc, eflags);
288  else
289  standard_ExecutorStart(queryDesc, eflags);
290 
291  if (auto_explain_enabled())
292  {
293  /*
294  * Set up to track total elapsed time in ExecutorRun. Make sure the
295  * space is allocated in the per-query context so it will go away at
296  * ExecutorEnd.
297  */
298  if (queryDesc->totaltime == NULL)
299  {
300  MemoryContext oldcxt;
301 
302  oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
303  queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL, false);
304  MemoryContextSwitchTo(oldcxt);
305  }
306  }
307 }
308 
309 /*
310  * ExecutorRun hook: all we need do is track nesting depth
311  */
312 static void
314  uint64 count, bool execute_once)
315 {
316  nesting_level++;
317  PG_TRY();
318  {
319  if (prev_ExecutorRun)
320  prev_ExecutorRun(queryDesc, direction, count, execute_once);
321  else
322  standard_ExecutorRun(queryDesc, direction, count, execute_once);
323  }
324  PG_FINALLY();
325  {
326  nesting_level--;
327  }
328  PG_END_TRY();
329 }
330 
331 /*
332  * ExecutorFinish hook: all we need do is track nesting depth
333  */
334 static void
336 {
337  nesting_level++;
338  PG_TRY();
339  {
341  prev_ExecutorFinish(queryDesc);
342  else
343  standard_ExecutorFinish(queryDesc);
344  }
345  PG_FINALLY();
346  {
347  nesting_level--;
348  }
349  PG_END_TRY();
350 }
351 
352 /*
353  * ExecutorEnd hook: log results if needed
354  */
355 static void
357 {
358  if (queryDesc->totaltime && auto_explain_enabled())
359  {
360  MemoryContext oldcxt;
361  double msec;
362 
363  /*
364  * Make sure we operate in the per-query context, so any cruft will be
365  * discarded later during ExecutorEnd.
366  */
367  oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
368 
369  /*
370  * Make sure stats accumulation is done. (Note: it's okay if several
371  * levels of hook all do this.)
372  */
373  InstrEndLoop(queryDesc->totaltime);
374 
375  /* Log plan if duration is exceeded. */
376  msec = queryDesc->totaltime->total * 1000.0;
377  if (msec >= auto_explain_log_min_duration)
378  {
380 
384  es->wal = (es->analyze && auto_explain_log_wal);
385  es->timing = (es->analyze && auto_explain_log_timing);
386  es->summary = es->analyze;
389 
390  ExplainBeginOutput(es);
391  ExplainQueryText(es, queryDesc);
392  ExplainPrintPlan(es, queryDesc);
394  ExplainPrintTriggers(es, queryDesc);
395  if (es->costs)
396  ExplainPrintJITSummary(es, queryDesc);
397  ExplainEndOutput(es);
398 
399  /* Remove last line break */
400  if (es->str->len > 0 && es->str->data[es->str->len - 1] == '\n')
401  es->str->data[--es->str->len] = '\0';
402 
403  /* Fix JSON to output an object */
405  {
406  es->str->data[0] = '{';
407  es->str->data[es->str->len - 1] = '}';
408  }
409 
410  /*
411  * Note: we rely on the existing logging of context or
412  * debug_query_string to identify just which statement is being
413  * reported. This isn't ideal but trying to do it here would
414  * often result in duplication.
415  */
417  (errmsg("duration: %.3f ms plan:\n%s",
418  msec, es->str->data),
419  errhidestmt(true)));
420  }
421 
422  MemoryContextSwitchTo(oldcxt);
423  }
424 
425  if (prev_ExecutorEnd)
426  prev_ExecutorEnd(queryDesc);
427  else
428  standard_ExecutorEnd(queryDesc);
429 }
static ExecutorRun_hook_type prev_ExecutorRun
Definition: auto_explain.c:75
static int auto_explain_log_min_duration
Definition: auto_explain.c:27
static bool auto_explain_log_analyze
Definition: auto_explain.c:28
static void explain_ExecutorEnd(QueryDesc *queryDesc)
Definition: auto_explain.c:356
void _PG_init(void)
Definition: auto_explain.c:93
static bool auto_explain_log_wal
Definition: auto_explain.c:31
#define auto_explain_enabled()
Definition: auto_explain.c:68
PG_MODULE_MAGIC
Definition: auto_explain.c:24
static double auto_explain_sample_rate
Definition: auto_explain.c:38
static bool auto_explain_log_nested_statements
Definition: auto_explain.c:37
static bool auto_explain_log_verbose
Definition: auto_explain.c:29
static void explain_ExecutorFinish(QueryDesc *queryDesc)
Definition: auto_explain.c:335
static int nesting_level
Definition: auto_explain.c:63
static bool current_query_sampled
Definition: auto_explain.c:66
static void explain_ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: auto_explain.c:250
static ExecutorStart_hook_type prev_ExecutorStart
Definition: auto_explain.c:74
static const struct config_enum_entry loglevel_options[]
Definition: auto_explain.c:48
static bool auto_explain_log_timing
Definition: auto_explain.c:33
static int auto_explain_log_format
Definition: auto_explain.c:35
static bool auto_explain_log_buffers
Definition: auto_explain.c:30
static bool auto_explain_log_triggers
Definition: auto_explain.c:32
static const struct config_enum_entry format_options[]
Definition: auto_explain.c:40
static ExecutorEnd_hook_type prev_ExecutorEnd
Definition: auto_explain.c:77
static int auto_explain_log_level
Definition: auto_explain.c:36
static void explain_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: auto_explain.c:313
static ExecutorFinish_hook_type prev_ExecutorFinish
Definition: auto_explain.c:76
static bool auto_explain_log_settings
Definition: auto_explain.c:34
int errhidestmt(bool hide_stmt)
Definition: elog.c:1245
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define LOG
Definition: elog.h:25
#define PG_END_TRY()
Definition: elog.h:324
#define DEBUG3
Definition: elog.h:22
#define PG_TRY()
Definition: elog.h:299
#define WARNING
Definition: elog.h:30
#define DEBUG2
Definition: elog.h:23
#define DEBUG1
Definition: elog.h:24
#define PG_FINALLY()
Definition: elog.h:316
#define NOTICE
Definition: elog.h:29
#define INFO
Definition: elog.h:28
#define ereport(elevel,...)
Definition: elog.h:143
#define DEBUG5
Definition: elog.h:20
#define DEBUG4
Definition: elog.h:21
ExecutorEnd_hook_type ExecutorEnd_hook
Definition: execMain.c:75
ExecutorFinish_hook_type ExecutorFinish_hook
Definition: execMain.c:74
ExecutorStart_hook_type ExecutorStart_hook
Definition: execMain.c:72
void standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:148
void standard_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:311
ExecutorRun_hook_type ExecutorRun_hook
Definition: execMain.c:73
void standard_ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:470
void standard_ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:410
void(* ExecutorRun_hook_type)(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: executor.h:69
void(* ExecutorFinish_hook_type)(QueryDesc *queryDesc)
Definition: executor.h:76
void(* ExecutorStart_hook_type)(QueryDesc *queryDesc, int eflags)
Definition: executor.h:65
void(* ExecutorEnd_hook_type)(QueryDesc *queryDesc)
Definition: executor.h:80
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:56
void ExplainEndOutput(ExplainState *es)
Definition: explain.c:4880
void ExplainPrintJITSummary(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:849
void ExplainQueryText(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:969
void ExplainBeginOutput(ExplainState *es)
Definition: explain.c:4849
ExplainState * NewExplainState(void)
Definition: explain.c:311
void ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:757
void ExplainPrintTriggers(ExplainState *es, QueryDesc *queryDesc)
Definition: explain.c:806
@ EXPLAIN_FORMAT_XML
Definition: explain.h:23
@ EXPLAIN_FORMAT_YAML
Definition: explain.h:25
@ EXPLAIN_FORMAT_TEXT
Definition: explain.h:22
@ EXPLAIN_FORMAT_JSON
Definition: explain.h:24
void DefineCustomRealVariable(const char *name, const char *short_desc, const char *long_desc, double *valueAddr, double bootValue, double minValue, double maxValue, GucContext context, int flags, GucRealCheckHook check_hook, GucRealAssignHook assign_hook, GucShowHook show_hook)
Definition: guc.c:9532
void DefineCustomEnumVariable(const char *name, const char *short_desc, const char *long_desc, int *valueAddr, int bootValue, const struct config_enum_entry *options, GucContext context, int flags, GucEnumCheckHook check_hook, GucEnumAssignHook assign_hook, GucShowHook show_hook)
Definition: guc.c:9587
void DefineCustomBoolVariable(const char *name, const char *short_desc, const char *long_desc, bool *valueAddr, bool bootValue, GucContext context, int flags, GucBoolCheckHook check_hook, GucBoolAssignHook assign_hook, GucShowHook show_hook)
Definition: guc.c:9476
void MarkGUCPrefixReserved(const char *className)
Definition: guc.c:9623
void DefineCustomIntVariable(const char *name, const char *short_desc, const char *long_desc, int *valueAddr, int bootValue, int minValue, int maxValue, GucContext context, int flags, GucIntCheckHook check_hook, GucIntAssignHook assign_hook, GucShowHook show_hook)
Definition: guc.c:9502
#define GUC_UNIT_MS
Definition: guc.h:224
@ PGC_SUSET
Definition: guc.h:75
#define IsParallelWorker()
Definition: parallel.h:61
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:140
Instrumentation * InstrAlloc(int n, int instrument_options, bool async_mode)
Definition: instrument.c:31
@ INSTRUMENT_ALL
Definition: instrument.h:63
@ INSTRUMENT_TIMER
Definition: instrument.h:59
@ INSTRUMENT_BUFFERS
Definition: instrument.h:60
@ INSTRUMENT_WAL
Definition: instrument.h:62
@ INSTRUMENT_ROWS
Definition: instrument.h:61
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
double pg_prng_double(pg_prng_state *state)
Definition: pg_prng.c:226
pg_prng_state pg_global_prng_state
Definition: pg_prng.c:28
ScanDirection
Definition: sdir.h:23
MemoryContext es_query_cxt
Definition: execnodes.h:632
bool verbose
Definition: explain.h:41
bool settings
Definition: explain.h:48
bool timing
Definition: explain.h:46
bool analyze
Definition: explain.h:42
StringInfo str
Definition: explain.h:39
ExplainFormat format
Definition: explain.h:49
bool wal
Definition: explain.h:45
bool summary
Definition: explain.h:47
bool costs
Definition: explain.h:43
bool buffers
Definition: explain.h:44
int instrument_options
Definition: execdesc.h:44
EState * estate
Definition: execdesc.h:48
struct Instrumentation * totaltime
Definition: execdesc.h:55
Definition: guc.h:165