Commit ea569d64 authored by Tomas Vondra's avatar Tomas Vondra

Add SETTINGS option to EXPLAIN, to print modified settings.

Query planning is affected by a number of configuration options, and it
may be crucial to know which of those options were set to non-default
values.  With this patch you can say EXPLAIN (SETTINGS ON) to include
that information in the query plan.  Only options affecting planning,
with values different from the built-in default are printed.

This patch also adds auto_explain.log_settings option, providing the
same capability in auto_explain module.

Author: Tomas Vondra
Reviewed-by: Rafia Sabih, John Naylor
Discussion: https://postgr.es/m/e1791b4c-df9c-be02-edc5-7c8874944be0@2ndquadrant.com
parent d1f04b96
......@@ -28,6 +28,7 @@ static bool auto_explain_log_verbose = false;
static bool auto_explain_log_buffers = false;
static bool auto_explain_log_triggers = false;
static bool auto_explain_log_timing = true;
static bool auto_explain_log_settings = false;
static int auto_explain_log_format = EXPLAIN_FORMAT_TEXT;
static int auto_explain_log_level = LOG;
static bool auto_explain_log_nested_statements = false;
......@@ -112,6 +113,17 @@ _PG_init(void)
NULL,
NULL);
DefineCustomBoolVariable("auto_explain.log_settings",
"Log modified configuration parameters affecting query planning.",
NULL,
&auto_explain_log_settings,
false,
PGC_SUSET,
0,
NULL,
NULL,
NULL);
DefineCustomBoolVariable("auto_explain.log_verbose",
"Use EXPLAIN VERBOSE for plan logging.",
NULL,
......@@ -356,6 +368,7 @@ explain_ExecutorEnd(QueryDesc *queryDesc)
es->timing = (es->analyze && auto_explain_log_timing);
es->summary = es->analyze;
es->format = auto_explain_log_format;
es->settings = auto_explain_log_settings;
ExplainBeginOutput(es);
ExplainQueryText(es, queryDesc);
......
......@@ -169,6 +169,24 @@ LOAD 'auto_explain';
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>auto_explain.log_settings</varname> (<type>boolean</type>)
<indexterm>
<primary><varname>auto_explain.log_settings</varname> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
<varname>auto_explain.log_settings</varname> controls whether information
about modified configuration options are printed when execution plan is logged.
Only options affecting query planning with value different from the built-in
default value are included in the output. This parameter is off by default.
Only superusers can change this setting.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>auto_explain.log_format</varname> (<type>enum</type>)
......
......@@ -39,6 +39,7 @@ EXPLAIN [ ANALYZE ] [ VERBOSE ] <replaceable class="parameter">statement</replac
ANALYZE [ <replaceable class="parameter">boolean</replaceable> ]
VERBOSE [ <replaceable class="parameter">boolean</replaceable> ]
COSTS [ <replaceable class="parameter">boolean</replaceable> ]
SETTINGS [ <replaceable class="parameter">boolean</replaceable> ]
BUFFERS [ <replaceable class="parameter">boolean</replaceable> ]
TIMING [ <replaceable class="parameter">boolean</replaceable> ]
SUMMARY [ <replaceable class="parameter">boolean</replaceable> ]
......@@ -152,6 +153,17 @@ ROLLBACK;
</listitem>
</varlistentry>
<varlistentry>
<term><literal>SETTINGS</literal></term>
<listitem>
<para>
Include information on configuration parameters. Specifically, include
options affecting query planning with value different from the built-in
default value. This parameter defaults to <literal>FALSE</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>BUFFERS</literal></term>
<listitem>
......
......@@ -29,6 +29,7 @@
#include "storage/bufmgr.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/guc_tables.h"
#include "utils/json.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
......@@ -162,6 +163,8 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString,
es->costs = defGetBoolean(opt);
else if (strcmp(opt->defname, "buffers") == 0)
es->buffers = defGetBoolean(opt);
else if (strcmp(opt->defname, "settings") == 0)
es->settings = defGetBoolean(opt);
else if (strcmp(opt->defname, "timing") == 0)
{
timing_set = true;
......@@ -596,6 +599,73 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
ExplainCloseGroup("Query", NULL, true, es);
}
/*
* ExplainPrintSettings -
* Print summary of modified settings affecting query planning.
*/
static void
ExplainPrintSettings(ExplainState *es)
{
int num;
struct config_generic **gucs;
/* bail out if information about settings not requested */
if (!es->settings)
return;
/* request an array of relevant settings */
gucs = get_explain_guc_options(&num);
/* also bail out of there are no options */
if (!num)
return;
if (es->format != EXPLAIN_FORMAT_TEXT)
{
int i;
ExplainOpenGroup("Settings", "Settings", true, es);
for (i = 0; i < num; i++)
{
char *setting;
struct config_generic *conf = gucs[i];
setting = GetConfigOptionByName(conf->name, NULL, true);
ExplainPropertyText(conf->name, setting, es);
}
ExplainCloseGroup("Settings", "Settings", true, es);
}
else
{
int i;
StringInfoData str;
initStringInfo(&str);
for (i = 0; i < num; i++)
{
char *setting;
struct config_generic *conf = gucs[i];
if (i > 0)
appendStringInfoString(&str, ", ");
setting = GetConfigOptionByName(conf->name, NULL, true);
if (setting)
appendStringInfo(&str, "%s = '%s'", conf->name, setting);
else
appendStringInfo(&str, "%s = NULL", conf->name);
}
if (num > 0)
ExplainPropertyText("Settings", str.data, es);
}
}
/*
* ExplainPrintPlan -
* convert a QueryDesc's plan tree to text and append it to es->str
......@@ -633,6 +703,12 @@ ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
if (IsA(ps, GatherState) &&((Gather *) ps->plan)->invisible)
ps = outerPlanState(ps);
ExplainNode(ps, NIL, NULL, NULL, es);
/*
* If requested, include information about GUC parameters with values
* that don't match the built-in defaults.
*/
ExplainPrintSettings(es);
}
/*
......
This diff is collapsed.
......@@ -35,6 +35,7 @@ typedef struct ExplainState
bool buffers; /* print buffer usage */
bool timing; /* print detailed node timing */
bool summary; /* print total planning and execution timing */
bool settings; /* print modified settings */
ExplainFormat format; /* output format */
/* state for output formatting --- not reset for each new plan tree */
int indent; /* current indentation level */
......
......@@ -227,6 +227,8 @@ typedef enum
#define GUC_UNIT_MIN 0x30000 /* value is in minutes */
#define GUC_UNIT_TIME 0xF0000 /* mask for time-related units */
#define GUC_EXPLAIN 0x100000 /* include in explain */
#define GUC_UNIT (GUC_UNIT_MEMORY | GUC_UNIT_TIME)
......
......@@ -267,5 +267,6 @@ extern void build_guc_variables(void);
extern const char *config_enum_lookup_by_value(struct config_enum *record, int val);
extern bool config_enum_lookup_by_name(struct config_enum *record,
const char *value, int *retval);
extern struct config_generic **get_explain_guc_options(int *num);
#endif /* GUC_TABLES_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment