pg.ddx.io  pgsql-hackers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
New EXPLAIN option: ALL
49+ messages / 15 participants
[nested] [flat]

* New EXPLAIN option: ALL
@ 2019-05-07 07:30  David Fetter <david@fetter.org>
  0 siblings, 4 replies; 49+ messages in thread

From: David Fetter @ 2019-05-07 07:30 UTC (permalink / raw)
  To: pgsql-hackers

Folks,

It can get a little tedious turning on (or off) all the boolean
options to EXPLAIN, so please find attached a shortcut.

Best,
David.
-- 
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate

Attachments:

v1-0001-Add-an-ALL-option-to-EXPLAIN.patch (text/x-diff, 2.5K) download From 8de75e81eb7161c712e2af97b0619a69f33c6b91 Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Tue, 7 May 2019 00:26:29 -0700 Subject: [PATCH v1] Add an ALL option to EXPLAIN To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit which starts all boolean options at once. diff --git a/doc/src/sgml/ref/explain.sgml b/doc/src/sgml/ref/explain.sgml index 385d10411f..ade3793c5f 100644 --- a/doc/src/sgml/ref/explain.sgml +++ b/doc/src/sgml/ref/explain.sgml @@ -43,6 +43,7 @@ EXPLAIN [ ANALYZE ] [ VERBOSE ] <replaceable class="parameter">statement</replac BUFFERS [ <replaceable class="parameter">boolean</replaceable> ] TIMING [ <replaceable class="parameter">boolean</replaceable> ] SUMMARY [ <replaceable class="parameter">boolean</replaceable> ] + ALL [ <replaceable class="parameter">boolean</replaceable> ] FORMAT { TEXT | XML | JSON | YAML } </synopsis> </refsynopsisdiv> @@ -224,6 +225,16 @@ ROLLBACK; </listitem> </varlistentry> + <varlistentry> + <term><literal>ALL</literal></term> + <listitem> + <para> + Include (or exclude) all of the above settings before examining the rest + of the options. It defaults to <literal>FALSE</literal>. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><literal>FORMAT</literal></term> <listitem> diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index a6c6de78f1..966f4566c7 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -151,6 +151,26 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, bool summary_set = false; /* Parse options list. */ + /* First, see whether ALL is set */ + foreach(lc, stmt->options) + { + DefElem *opt = (DefElem *) lfirst(lc); + + if (strcmp(opt->defname, "all") == 0) + { + es->analyze = defGetBoolean(opt); + es->verbose = defGetBoolean(opt); + es->costs = defGetBoolean(opt); + es->buffers = defGetBoolean(opt); + es->settings = defGetBoolean(opt); + timing_set = true; + es->timing = defGetBoolean(opt); + summary_set = true; + es->timing = defGetBoolean(opt); + } + } + + /* If you add another boolean option here, remember to add it above, too */ foreach(lc, stmt->options) { DefElem *opt = (DefElem *) lfirst(lc); --------------2.21.0--
^ permalink raw reply [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 07:50  David Fetter <david@fetter.org>
  parent: David Fetter <david@fetter.org>
  3 siblings, 1 reply; 49+ messages in thread

From: David Fetter @ 2019-05-07 07:50 UTC (permalink / raw)
  To: pgsql-hackers

On Tue, May 07, 2019 at 09:30:47AM +0200, David Fetter wrote:
> Folks,
> 
> It can get a little tedious turning on (or off) all the boolean
> options to EXPLAIN, so please find attached a shortcut.
> 
> Best,
> David.

It helps to have a working patch for this.

Best,
David.
-- 
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate

Attachments:

v2-0001-Add-an-ALL-option-to-EXPLAIN.patch (text/x-diff, 4.3K) download From d62669c5b1d22c18949ad5d6ae3f6b23b49819e3 Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Tue, 7 May 2019 00:26:29 -0700 Subject: [PATCH v2] Add an ALL option to EXPLAIN To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit which starts all boolean options at once. diff --git a/doc/src/sgml/ref/explain.sgml b/doc/src/sgml/ref/explain.sgml index 385d10411f..ade3793c5f 100644 --- a/doc/src/sgml/ref/explain.sgml +++ b/doc/src/sgml/ref/explain.sgml @@ -43,6 +43,7 @@ EXPLAIN [ ANALYZE ] [ VERBOSE ] <replaceable class="parameter">statement</replac BUFFERS [ <replaceable class="parameter">boolean</replaceable> ] TIMING [ <replaceable class="parameter">boolean</replaceable> ] SUMMARY [ <replaceable class="parameter">boolean</replaceable> ] + ALL [ <replaceable class="parameter">boolean</replaceable> ] FORMAT { TEXT | XML | JSON | YAML } </synopsis> </refsynopsisdiv> @@ -224,6 +225,16 @@ ROLLBACK; </listitem> </varlistentry> + <varlistentry> + <term><literal>ALL</literal></term> + <listitem> + <para> + Include (or exclude) all of the above settings before examining the rest + of the options. It defaults to <literal>FALSE</literal>. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><literal>FORMAT</literal></term> <listitem> diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index a6c6de78f1..7ad73e4482 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -151,6 +151,26 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, bool summary_set = false; /* Parse options list. */ + /* First, see whether ALL is set */ + foreach(lc, stmt->options) + { + DefElem *opt = (DefElem *) lfirst(lc); + + if (strcmp(opt->defname, "all") == 0) + { + es->analyze = defGetBoolean(opt); + es->verbose = defGetBoolean(opt); + es->costs = defGetBoolean(opt); + es->buffers = defGetBoolean(opt); + es->settings = defGetBoolean(opt); + timing_set = true; + es->timing = defGetBoolean(opt); + summary_set = true; + es->timing = defGetBoolean(opt); + } + } + + /* If you add another boolean option here, remember to add it above, too */ foreach(lc, stmt->options) { DefElem *opt = (DefElem *) lfirst(lc); @@ -194,6 +214,8 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, opt->defname, p), parser_errposition(pstate, opt->location))); } + else if (strcmp(opt->defname, "all") == 0) + ; /* Do nothing */ else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 3dc0e8a4fb..4a69f9711c 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10704,6 +10704,7 @@ explain_option_elem: explain_option_name: NonReservedWord { $$ = $1; } | analyze_keyword { $$ = "analyze"; } + | ALL { $$ = "all"; } ; explain_option_arg: diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index bcddc7601e..8177f9c6da 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -2862,9 +2862,9 @@ psql_completion(const char *text, int start, int end) * one word, so the above test is correct. */ if (ends_with(prev_wd, '(') || ends_with(prev_wd, ',')) - COMPLETE_WITH("ANALYZE", "VERBOSE", "COSTS", "BUFFERS", + COMPLETE_WITH("ALL", "ANALYZE", "VERBOSE", "COSTS", "BUFFERS", "TIMING", "SUMMARY", "FORMAT"); - else if (TailMatches("ANALYZE|VERBOSE|COSTS|BUFFERS|TIMING|SUMMARY")) + else if (TailMatches("ALL|ANALYZE|VERBOSE|COSTS|BUFFERS|TIMING|SUMMARY")) COMPLETE_WITH("ON", "OFF"); else if (TailMatches("FORMAT")) COMPLETE_WITH("TEXT", "XML", "JSON", "YAML"); @@ -2874,7 +2874,8 @@ psql_completion(const char *text, int start, int end) "VERBOSE"); else if (Matches("EXPLAIN", "(*)") || Matches("EXPLAIN", "VERBOSE") || - Matches("EXPLAIN", "ANALYZE", "VERBOSE")) + Matches("EXPLAIN", "ANALYZE", "VERBOSE") || + Matches("EXPLAIN", "ALL")) COMPLETE_WITH("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE"); /* FETCH && MOVE */ --------------2.21.0--
^ permalink raw reply [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 08:13  Sergei Kornilov <sk@zsrv.org>
  parent: David Fetter <david@fetter.org>
  0 siblings, 1 reply; 49+ messages in thread

From: Sergei Kornilov @ 2019-05-07 08:13 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; pgsql-hackers

Hi

I liked this idea.

+			timing_set = true;
+			es->timing = defGetBoolean(opt);
+			summary_set = true;
+			es->timing = defGetBoolean(opt);

second es->timing should be es->summary, right?

regards, Sergei





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 09:03  Rafia Sabih <rafia.pghackers@gmail.com>
  parent: David Fetter <david@fetter.org>
  3 siblings, 1 reply; 49+ messages in thread

From: Rafia Sabih @ 2019-05-07 09:03 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; +Cc: pgsql-hackers

On Tue, 7 May 2019 at 09:30, David Fetter <david@fetter.org> wrote:
>
> Folks,
>
> It can get a little tedious turning on (or off) all the boolean
> options to EXPLAIN, so please find attached a shortcut.
>

I don't understand this, do you mind explaining a bit may be with an
example on how you want it to work.
-- 
Regards,
Rafia Sabih





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 15:41  Andres Freund <andres@anarazel.de>
  parent: David Fetter <david@fetter.org>
  3 siblings, 1 reply; 49+ messages in thread

From: Andres Freund @ 2019-05-07 15:41 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; +Cc: pgsql-hackers

Hi,

On 2019-05-07 09:30:47 +0200, David Fetter wrote:
> It can get a little tedious turning on (or off) all the boolean
> options to EXPLAIN, so please find attached a shortcut.

I'm not convinced this is a good idea - it seems likely that we'll add
conflicting options at some point, and then this will just be a pain in
the neck.

Greetings,

Andres Freund





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 16:28  David Fetter <david@fetter.org>
  parent: Sergei Kornilov <sk@zsrv.org>
  0 siblings, 0 replies; 49+ messages in thread

From: David Fetter @ 2019-05-07 16:28 UTC (permalink / raw)
  To: Sergei Kornilov <sk@zsrv.org>; +Cc: pgsql-hackers

On Tue, May 07, 2019 at 11:13:15AM +0300, Sergei Kornilov wrote:
> Hi
> 
> I liked this idea.
> 
> +			timing_set = true;
> +			es->timing = defGetBoolean(opt);
> +			summary_set = true;
> +			es->timing = defGetBoolean(opt);
> 
> second es->timing should be es->summary, right?

You are correct! Sorry about the copy-paste-o.

Best,
David.
-- 
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate

Attachments:

v2-0001-Add-an-ALL-option-to-EXPLAIN.patch (text/x-diff, 4.3K) download From 424d82c9ff519c02ae266700ed1f4b40ac9c495f Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Tue, 7 May 2019 00:26:29 -0700 Subject: [PATCH v2] Add an ALL option to EXPLAIN To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit which starts all boolean options at once. diff --git a/doc/src/sgml/ref/explain.sgml b/doc/src/sgml/ref/explain.sgml index 385d10411f..ade3793c5f 100644 --- a/doc/src/sgml/ref/explain.sgml +++ b/doc/src/sgml/ref/explain.sgml @@ -43,6 +43,7 @@ EXPLAIN [ ANALYZE ] [ VERBOSE ] <replaceable class="parameter">statement</replac BUFFERS [ <replaceable class="parameter">boolean</replaceable> ] TIMING [ <replaceable class="parameter">boolean</replaceable> ] SUMMARY [ <replaceable class="parameter">boolean</replaceable> ] + ALL [ <replaceable class="parameter">boolean</replaceable> ] FORMAT { TEXT | XML | JSON | YAML } </synopsis> </refsynopsisdiv> @@ -224,6 +225,16 @@ ROLLBACK; </listitem> </varlistentry> + <varlistentry> + <term><literal>ALL</literal></term> + <listitem> + <para> + Include (or exclude) all of the above settings before examining the rest + of the options. It defaults to <literal>FALSE</literal>. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><literal>FORMAT</literal></term> <listitem> diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index a6c6de78f1..f58b9d7290 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -151,6 +151,26 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, bool summary_set = false; /* Parse options list. */ + /* First, see whether ALL is set */ + foreach(lc, stmt->options) + { + DefElem *opt = (DefElem *) lfirst(lc); + + if (strcmp(opt->defname, "all") == 0) + { + es->analyze = defGetBoolean(opt); + es->verbose = defGetBoolean(opt); + es->costs = defGetBoolean(opt); + es->buffers = defGetBoolean(opt); + es->settings = defGetBoolean(opt); + timing_set = true; + es->timing = defGetBoolean(opt); + summary_set = true; + es->summary_set = defGetBoolean(opt); + } + } + + /* If you add another boolean option here, remember to add it above, too */ foreach(lc, stmt->options) { DefElem *opt = (DefElem *) lfirst(lc); @@ -194,6 +214,8 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, opt->defname, p), parser_errposition(pstate, opt->location))); } + else if (strcmp(opt->defname, "all") == 0) + ; /* Do nothing */ else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 3dc0e8a4fb..4a69f9711c 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10704,6 +10704,7 @@ explain_option_elem: explain_option_name: NonReservedWord { $$ = $1; } | analyze_keyword { $$ = "analyze"; } + | ALL { $$ = "all"; } ; explain_option_arg: diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index bcddc7601e..8177f9c6da 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -2862,9 +2862,9 @@ psql_completion(const char *text, int start, int end) * one word, so the above test is correct. */ if (ends_with(prev_wd, '(') || ends_with(prev_wd, ',')) - COMPLETE_WITH("ANALYZE", "VERBOSE", "COSTS", "BUFFERS", + COMPLETE_WITH("ALL", "ANALYZE", "VERBOSE", "COSTS", "BUFFERS", "TIMING", "SUMMARY", "FORMAT"); - else if (TailMatches("ANALYZE|VERBOSE|COSTS|BUFFERS|TIMING|SUMMARY")) + else if (TailMatches("ALL|ANALYZE|VERBOSE|COSTS|BUFFERS|TIMING|SUMMARY")) COMPLETE_WITH("ON", "OFF"); else if (TailMatches("FORMAT")) COMPLETE_WITH("TEXT", "XML", "JSON", "YAML"); @@ -2874,7 +2874,8 @@ psql_completion(const char *text, int start, int end) "VERBOSE"); else if (Matches("EXPLAIN", "(*)") || Matches("EXPLAIN", "VERBOSE") || - Matches("EXPLAIN", "ANALYZE", "VERBOSE")) + Matches("EXPLAIN", "ANALYZE", "VERBOSE") || + Matches("EXPLAIN", "ALL")) COMPLETE_WITH("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE"); /* FETCH && MOVE */ --------------2.21.0--
^ permalink raw reply [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 16:31  David Fetter <david@fetter.org>
  parent: Rafia Sabih <rafia.pghackers@gmail.com>
  0 siblings, 2 replies; 49+ messages in thread

From: David Fetter @ 2019-05-07 16:31 UTC (permalink / raw)
  To: Rafia Sabih <rafia.pghackers@gmail.com>; +Cc: pgsql-hackers

On Tue, May 07, 2019 at 11:03:23AM +0200, Rafia Sabih wrote:
> On Tue, 7 May 2019 at 09:30, David Fetter <david@fetter.org> wrote:
> >
> > Folks,
> >
> > It can get a little tedious turning on (or off) all the boolean
> > options to EXPLAIN, so please find attached a shortcut.
> 
> I don't understand this, do you mind explaining a bit may be with an
> example on how you want it to work.

If you're tuning a query interactively, it's a lot simpler to prepend,
for example,

    EXPLAIN (ALL, FORMAT JSON)

to it than to prepend something along the lines of

    EXPLAIN(ANALYZE, VERBOSE, COSTS, BUFFERS, SETTINGS, TIMING, SUMMARY, PARTRIDGE_IN_A_PEAR_TREE, FORMAT JSON)

to it.

Best,
David.
-- 
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 16:34  David Fetter <david@fetter.org>
  parent: Andres Freund <andres@anarazel.de>
  0 siblings, 1 reply; 49+ messages in thread

From: David Fetter @ 2019-05-07 16:34 UTC (permalink / raw)
  To: Andres Freund <andres@anarazel.de>; +Cc: pgsql-hackers

On Tue, May 07, 2019 at 08:41:47AM -0700, Andres Freund wrote:
> Hi,
> 
> On 2019-05-07 09:30:47 +0200, David Fetter wrote:
> > It can get a little tedious turning on (or off) all the boolean
> > options to EXPLAIN, so please find attached a shortcut.
> 
> I'm not convinced this is a good idea - it seems likely that we'll
> add conflicting options at some point, and then this will just be a
> pain in the neck.

I already left out FORMAT for a similar reason, namely that it's not a
boolean, so it's not part of flipping on (or off) all the switches.

Are you seeing a point in the future where there'd be both mutually
exclusive boolean options and no principled reason to choose among
them?  If so, what might it look like?

Best,
David.
-- 
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 16:44  Andres Freund <andres@anarazel.de>
  parent: David Fetter <david@fetter.org>
  0 siblings, 1 reply; 49+ messages in thread

From: Andres Freund @ 2019-05-07 16:44 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; +Cc: pgsql-hackers

Hi,

On 2019-05-07 18:34:11 +0200, David Fetter wrote:
> On Tue, May 07, 2019 at 08:41:47AM -0700, Andres Freund wrote:
> > On 2019-05-07 09:30:47 +0200, David Fetter wrote:
> > > It can get a little tedious turning on (or off) all the boolean
> > > options to EXPLAIN, so please find attached a shortcut.
> > 
> > I'm not convinced this is a good idea - it seems likely that we'll
> > add conflicting options at some point, and then this will just be a
> > pain in the neck.
> 
> I already left out FORMAT for a similar reason, namely that it's not a
> boolean, so it's not part of flipping on (or off) all the switches.

Which is already somewhat hard to explain.

Imagine if we had CPU_PROFILE = on (which'd be *extremely*
useful). Would you want that to be switched on automatically?  How about
RECORD_IO_TRACE?  How about DISTINCT_BUFFERS which'd be like BUFFERS
except that we'd track how many different buffers are accessed using HLL
or such? Would also be extremely useful.


> Are you seeing a point in the future where there'd be both mutually
> exclusive boolean options and no principled reason to choose among
> them?  If so, what might it look like?

Yes. CPU_PROFILE_PERF, CPU_PROFILE_VTUNE. And lots more.


Greetings,

Andres Freund





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 21:23  David Fetter <david@fetter.org>
  parent: Andres Freund <andres@anarazel.de>
  0 siblings, 1 reply; 49+ messages in thread

From: David Fetter @ 2019-05-07 21:23 UTC (permalink / raw)
  To: Andres Freund <andres@anarazel.de>; +Cc: pgsql-hackers

On Tue, May 07, 2019 at 09:44:30AM -0700, Andres Freund wrote:
> Hi,
> 
> On 2019-05-07 18:34:11 +0200, David Fetter wrote:
> > On Tue, May 07, 2019 at 08:41:47AM -0700, Andres Freund wrote:
> > > On 2019-05-07 09:30:47 +0200, David Fetter wrote:
> > > > It can get a little tedious turning on (or off) all the boolean
> > > > options to EXPLAIN, so please find attached a shortcut.
> > > 
> > > I'm not convinced this is a good idea - it seems likely that we'll
> > > add conflicting options at some point, and then this will just be a
> > > pain in the neck.
> > 
> > I already left out FORMAT for a similar reason, namely that it's not a
> > boolean, so it's not part of flipping on (or off) all the switches.
> 
> Which is already somewhat hard to explain.
> 
> Imagine if we had CPU_PROFILE = on (which'd be *extremely*
> useful). Would you want that to be switched on automatically?  How about
> RECORD_IO_TRACE?  How about DISTINCT_BUFFERS which'd be like BUFFERS
> except that we'd track how many different buffers are accessed using HLL
> or such? Would also be extremely useful.
> 
> 
> > Are you seeing a point in the future where there'd be both mutually
> > exclusive boolean options and no principled reason to choose among
> > them?  If so, what might it look like?
> 
> Yes. CPU_PROFILE_PERF, CPU_PROFILE_VTUNE. And lots more.

Thanks for clarifying.

Would you agree that there's a problem here as I described as
motivation for people who operate databases?

If so, do you have one or more abbreviations in mind that aren't
called ALL? I realize that Naming Things™ is one of two hard problems
in computer science, but it's still one we have to tackle.

Best,
David.
-- 
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 21:45  Peter Geoghegan <pg@bowt.ie>
  parent: David Fetter <david@fetter.org>
  1 sibling, 0 replies; 49+ messages in thread

From: Peter Geoghegan @ 2019-05-07 21:45 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; +Cc: Rafia Sabih <rafia.pghackers@gmail.com>; pgsql-hackers

On Tue, May 7, 2019 at 9:31 AM David Fetter <david@fetter.org> wrote:
> If you're tuning a query interactively, it's a lot simpler to prepend,
> for example,
>
>     EXPLAIN (ALL, FORMAT JSON)
>
> to it than to prepend something along the lines of
>
>     EXPLAIN(ANALYZE, VERBOSE, COSTS, BUFFERS, SETTINGS, TIMING, SUMMARY, PARTRIDGE_IN_A_PEAR_TREE, FORMAT JSON)
>
> to it.

FWIW, I have the following in my psqlrc:

\set ea 'EXPLAIN (ANALYZE, SETTINGS, VERBOSE, BUFFERS) '

The idea behind that is that I can prepend ":ea" as needed, rather
than doing a lot of typing each time, as in:

:ea SELECT ...


--
Peter Geoghegan





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 21:54  Andres Freund <andres@anarazel.de>
  parent: David Fetter <david@fetter.org>
  0 siblings, 1 reply; 49+ messages in thread

From: Andres Freund @ 2019-05-07 21:54 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; +Cc: pgsql-hackers

Hi,

On 2019-05-07 23:23:55 +0200, David Fetter wrote:
> Would you agree that there's a problem here as I described as
> motivation for people who operate databases?

Yea, but I don't think the solution is where you seek it.  I think the
problem is that our defaults for EXPLAIN, in particular EXPLAIN ANALYZE,
are dumb. And that your desire for ALL stems from that, rather than it
being desirable on its own.

We really e.g. should just enable BUFFERS by default. The reason we
can't is that right now we have checks like:
EXPLAIN (BUFFERS) SELECT 1;
ERROR:  22023: EXPLAIN option BUFFERS requires ANALYZE
LOCATION:  ExplainQuery, explain.c:206

but we ought to simply remove them. There's no benefit, and besides
preventing from enabling BUFFERS by default it means that
enabling/disabling ANALYZE is more work than necessary.


> If so, do you have one or more abbreviations in mind that aren't
> called ALL? I realize that Naming Things™ is one of two hard problems
> in computer science, but it's still one we have to tackle.

As I said, I don't think ALL is a good idea under any name.  Like it
just makes no sense to have ANALYZE, SUMMARY, VERBOSE, BUFFERS,
SETTINGS, FORMAT controlled by one option, unless you call it DWIM. It's
several separate axis (query is executed or not (ANALYZE), verbosity
(SUMMARY, VERBOSE), collecting additional information (BUFFERS, TIMING),
output format).

Greetings,

Andres Freund





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 22:06  Tom Lane <tgl@sss.pgh.pa.us>
  parent: Andres Freund <andres@anarazel.de>
  0 siblings, 1 reply; 49+ messages in thread

From: Tom Lane @ 2019-05-07 22:06 UTC (permalink / raw)
  To: Andres Freund <andres@anarazel.de>; +Cc: David Fetter <david@fetter.org>; pgsql-hackers

Andres Freund <andres@anarazel.de> writes:
> As I said, I don't think ALL is a good idea under any name.  Like it
> just makes no sense to have ANALYZE, SUMMARY, VERBOSE, BUFFERS,
> SETTINGS, FORMAT controlled by one option, unless you call it DWIM. It's
> several separate axis (query is executed or not (ANALYZE), verbosity
> (SUMMARY, VERBOSE), collecting additional information (BUFFERS, TIMING),
> output format).

FWIW, I find this line of argument fairly convincing.  There may well
be a case for rethinking just how EXPLAIN's options behave, but "ALL"
doesn't seem like a good conceptual model.

One idea that comes to mind is that VERBOSE could be redefined as some
sort of package of primitive options, including all of the "additional
information" options, with the ability to turn individual ones off again
if you wanted.  So for example (VERBOSE, BUFFERS OFF) would give you
everything except buffer stats.  We'd need a separate flag/flags to
control what VERBOSE originally did, but that doesn't bother me ---
it's an opportunity for more clarity of definition, anyway.

I do feel that it's a good idea to keep ANALYZE separate. "Execute
the query or not" is a mighty fundamental thing.  I've never liked
that name for the option though --- maybe we could deprecate it
in favor of EXECUTE?

			regards, tom lane





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 22:12  Stephen Frost <sfrost@snowman.net>
  parent: Tom Lane <tgl@sss.pgh.pa.us>
  0 siblings, 2 replies; 49+ messages in thread

From: Stephen Frost @ 2019-05-07 22:12 UTC (permalink / raw)
  To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Andres Freund <andres@anarazel.de>; David Fetter <david@fetter.org>; pgsql-hackers

Greetings,

* Tom Lane (tgl@sss.pgh.pa.us) wrote:
> Andres Freund <andres@anarazel.de> writes:
> > As I said, I don't think ALL is a good idea under any name.  Like it
> > just makes no sense to have ANALYZE, SUMMARY, VERBOSE, BUFFERS,
> > SETTINGS, FORMAT controlled by one option, unless you call it DWIM. It's
> > several separate axis (query is executed or not (ANALYZE), verbosity
> > (SUMMARY, VERBOSE), collecting additional information (BUFFERS, TIMING),
> > output format).
> 
> FWIW, I find this line of argument fairly convincing.  There may well
> be a case for rethinking just how EXPLAIN's options behave, but "ALL"
> doesn't seem like a good conceptual model.
> 
> One idea that comes to mind is that VERBOSE could be redefined as some
> sort of package of primitive options, including all of the "additional
> information" options, with the ability to turn individual ones off again
> if you wanted.  So for example (VERBOSE, BUFFERS OFF) would give you
> everything except buffer stats.  We'd need a separate flag/flags to
> control what VERBOSE originally did, but that doesn't bother me ---
> it's an opportunity for more clarity of definition, anyway.

I'm generally in favor of doing something like what Tom is suggesting
with VERBOSE, but I also feel like it should be the default for formats
like JSON.  If you're asking for the output in JSON, then we really
should include everything that a flag like VERBOSE would contain because
you're pretty clearly planning to copy/paste that output into something
else to read it anyway.

> I do feel that it's a good idea to keep ANALYZE separate. "Execute
> the query or not" is a mighty fundamental thing.  I've never liked
> that name for the option though --- maybe we could deprecate it
> in favor of EXECUTE?

Let's not fool ourselves by saying we'd 'deprecate' it because that
implies, at least to me, that there's some intention of later on
removing it and people will potentially propose patches to do that,
which we will then almost certainly spend hours arguing about with the
result being that we don't actually remove it.

I'm all in favor of adding an alias for analyze called 'execute', as
that makes a lot more sense and then updating our documentation to use
it, with 'analyze is accepted as an alias' as a footnote.

Thanks,

Stephen

Attachments:

  signature.asc (application/pgp-signature, 818B) download

^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 22:25  Tom Lane <tgl@sss.pgh.pa.us>
  parent: Stephen Frost <sfrost@snowman.net>
  1 sibling, 3 replies; 49+ messages in thread

From: Tom Lane @ 2019-05-07 22:25 UTC (permalink / raw)
  To: Stephen Frost <sfrost@snowman.net>; +Cc: Andres Freund <andres@anarazel.de>; David Fetter <david@fetter.org>; pgsql-hackers

Stephen Frost <sfrost@snowman.net> writes:
> I'm generally in favor of doing something like what Tom is suggesting
> with VERBOSE, but I also feel like it should be the default for formats
> like JSON.  If you're asking for the output in JSON, then we really
> should include everything that a flag like VERBOSE would contain because
> you're pretty clearly planning to copy/paste that output into something
> else to read it anyway.

Meh --- I don't especially care for non-orthogonal behaviors like that.
If you wanted JSON but *not* all of the additional info, how would you
specify that?  (The implementation I had in mind would make VERBOSE OFF
more or less a no-op, so that wouldn't get you there.)

>> I do feel that it's a good idea to keep ANALYZE separate. "Execute
>> the query or not" is a mighty fundamental thing.  I've never liked
>> that name for the option though --- maybe we could deprecate it
>> in favor of EXECUTE?

> Let's not fool ourselves by saying we'd 'deprecate' it because that
> implies, at least to me, that there's some intention of later on
> removing it

True, the odds of ever actually removing it are small :-(.  I meant
mostly changing all of our docs to use the other spelling, except
for some footnote.  Maybe we could call ANALYZE a "legacy spelling"
of EXECUTE.

			regards, tom lane





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 22:39  David Fetter <david@fetter.org>
  parent: Stephen Frost <sfrost@snowman.net>
  1 sibling, 1 reply; 49+ messages in thread

From: David Fetter @ 2019-05-07 22:39 UTC (permalink / raw)
  To: Stephen Frost <sfrost@snowman.net>; +Cc: Tom Lane <tgl@sss.pgh.pa.us>; Andres Freund <andres@anarazel.de>; pgsql-hackers

On Tue, May 07, 2019 at 06:12:56PM -0400, Stephen Frost wrote:
> Greetings,
> 
> * Tom Lane (tgl@sss.pgh.pa.us) wrote:
> > 
> > One idea that comes to mind is that VERBOSE could be redefined as
> > some sort of package of primitive options, including all of the
> > "additional information" options, with the ability to turn
> > individual ones off again if you wanted.  So for example (VERBOSE,
> > BUFFERS OFF) would give you everything except buffer stats.  We'd
> > need a separate flag/flags to control what VERBOSE originally did,
> > but that doesn't bother me --- it's an opportunity for more
> > clarity of definition, anyway.
> 
> I'm generally in favor of doing something like what Tom is
> suggesting with VERBOSE, but I also feel like it should be the
> default for formats like JSON.  If you're asking for the output in
> JSON, then we really should include everything that a flag like
> VERBOSE would contain because you're pretty clearly planning to
> copy/paste that output into something else to read it anyway.

So basically, every format but text gets the full treatment for
(essentially) the functionality I wrapped up in ALL?  That makes a lot
of sense.

> > I do feel that it's a good idea to keep ANALYZE separate. "Execute
> > the query or not" is a mighty fundamental thing.  I've never liked
> > that name for the option though --- maybe we could deprecate it
> > in favor of EXECUTE?
> 
> Let's not fool ourselves by saying we'd 'deprecate' it because that
> implies, at least to me, that there's some intention of later on
> removing it and people will potentially propose patches to do that,
> which we will then almost certainly spend hours arguing about with the
> result being that we don't actually remove it.

Excellent point.

> I'm all in favor of adding an alias for analyze called 'execute', as
> that makes a lot more sense and then updating our documentation to
> use it, with 'analyze is accepted as an alias' as a footnote.

How about making ANALYZE a backward-compatibility feature in the sense
of replacing examples, docs, etc., with EXECUTE? If most of our users
are in the future, this makes those same users's better without
qualification, and helps some positive fraction of our current users.

On a slightly related topic, we haven't, to date, made any promises
about what EXPLAIN will put out, but as we make more machine-readable
versions, we should at least think about its schema and versioning
of same.

Best,
David.
-- 
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 22:51  Stephen Frost <sfrost@snowman.net>
  parent: Tom Lane <tgl@sss.pgh.pa.us>
  2 siblings, 0 replies; 49+ messages in thread

From: Stephen Frost @ 2019-05-07 22:51 UTC (permalink / raw)
  To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Andres Freund <andres@anarazel.de>; David Fetter <david@fetter.org>; pgsql-hackers

Greetings,

* Tom Lane (tgl@sss.pgh.pa.us) wrote:
> Stephen Frost <sfrost@snowman.net> writes:
> > I'm generally in favor of doing something like what Tom is suggesting
> > with VERBOSE, but I also feel like it should be the default for formats
> > like JSON.  If you're asking for the output in JSON, then we really
> > should include everything that a flag like VERBOSE would contain because
> > you're pretty clearly planning to copy/paste that output into something
> > else to read it anyway.
> 
> Meh --- I don't especially care for non-orthogonal behaviors like that.
> If you wanted JSON but *not* all of the additional info, how would you
> specify that?  (The implementation I had in mind would make VERBOSE OFF
> more or less a no-op, so that wouldn't get you there.)

You'd do it the same way you proposed for verbose- eg: BUFFERS OFF, et
al, but, really, the point here is that what you're doing with the JSON
result is fundamentally different- you're going to paste it into some
other tool and it should be that tool's job to manage the visualization
of it and what's included or not in what you see.  Passing the
information about what should be seen in the json-based EXPLAIN viewer
by way of omitting things from the JSON output strikes me as downright
odd, and doesn't give that other tool the ability to show that data if
the users ends up wanting it without rerunning the query.

> >> I do feel that it's a good idea to keep ANALYZE separate. "Execute
> >> the query or not" is a mighty fundamental thing.  I've never liked
> >> that name for the option though --- maybe we could deprecate it
> >> in favor of EXECUTE?
> 
> > Let's not fool ourselves by saying we'd 'deprecate' it because that
> > implies, at least to me, that there's some intention of later on
> > removing it
> 
> True, the odds of ever actually removing it are small :-(.  I meant
> mostly changing all of our docs to use the other spelling, except
> for some footnote.  Maybe we could call ANALYZE a "legacy spelling"
> of EXECUTE.

Sure, that'd be fine too.

Thanks,

Stephen

Attachments:

  signature.asc (application/pgp-signature, 818B) download

^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-07 22:58  Stephen Frost <sfrost@snowman.net>
  parent: David Fetter <david@fetter.org>
  0 siblings, 0 replies; 49+ messages in thread

From: Stephen Frost @ 2019-05-07 22:58 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; +Cc: Tom Lane <tgl@sss.pgh.pa.us>; Andres Freund <andres@anarazel.de>; pgsql-hackers

Greetings,

* David Fetter (david@fetter.org) wrote:
> On Tue, May 07, 2019 at 06:12:56PM -0400, Stephen Frost wrote:
> > * Tom Lane (tgl@sss.pgh.pa.us) wrote:
> > > One idea that comes to mind is that VERBOSE could be redefined as
> > > some sort of package of primitive options, including all of the
> > > "additional information" options, with the ability to turn
> > > individual ones off again if you wanted.  So for example (VERBOSE,
> > > BUFFERS OFF) would give you everything except buffer stats.  We'd
> > > need a separate flag/flags to control what VERBOSE originally did,
> > > but that doesn't bother me --- it's an opportunity for more
> > > clarity of definition, anyway.
> > 
> > I'm generally in favor of doing something like what Tom is
> > suggesting with VERBOSE, but I also feel like it should be the
> > default for formats like JSON.  If you're asking for the output in
> > JSON, then we really should include everything that a flag like
> > VERBOSE would contain because you're pretty clearly planning to
> > copy/paste that output into something else to read it anyway.
> 
> So basically, every format but text gets the full treatment for
> (essentially) the functionality I wrapped up in ALL?  That makes a lot
> of sense.

Something along those lines is what I was thinking, yes, and it's what
at least some other projects do (admittedly, that's at least partially
my fault because I'm thinking of the 'info' command for pgbackrest, but
David Steele seemed to think it made sense also, at least).

> > I'm all in favor of adding an alias for analyze called 'execute', as
> > that makes a lot more sense and then updating our documentation to
> > use it, with 'analyze is accepted as an alias' as a footnote.
> 
> How about making ANALYZE a backward-compatibility feature in the sense
> of replacing examples, docs, etc., with EXECUTE? If most of our users
> are in the future, this makes those same users's better without
> qualification, and helps some positive fraction of our current users.

I'd rather not refer to it as a backwards-compatibility feature since
we, thankfully, don't typically do that and I generally think that's the
right way to go- but in some cases, like this one, having a 'legacy'
spelling or an alias seems to be darn near free without opening the box
of trying to provide backwards compatibility for everything.

> On a slightly related topic, we haven't, to date, made any promises
> about what EXPLAIN will put out, but as we make more machine-readable
> versions, we should at least think about its schema and versioning
> of same.

Not really sure that I agree on this point.  Do you see a reason to need
versioning or schema when the schema is, essentially, included in each
result since it's JSON or the other machine-readable formats?  I can
imagine that we might need a version if we decided to redefine some
existing field in a non-compatible or non-sensible way, but is that
possibility likely enough to warrent adding versioning and complicating
everything downstream?  I have a hard time seeing that.

Thanks,

Stephen

Attachments:

  signature.asc (application/pgp-signature, 818B) download

^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-08 20:03  Robert Haas <robertmhaas@gmail.com>
  parent: Tom Lane <tgl@sss.pgh.pa.us>
  2 siblings, 0 replies; 49+ messages in thread

From: Robert Haas @ 2019-05-08 20:03 UTC (permalink / raw)
  To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Stephen Frost <sfrost@snowman.net>; Andres Freund <andres@anarazel.de>; David Fetter <david@fetter.org>; pgsql-hackers

On Tue, May 7, 2019 at 6:25 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Meh --- I don't especially care for non-orthogonal behaviors like that.
> If you wanted JSON but *not* all of the additional info, how would you
> specify that?  (The implementation I had in mind would make VERBOSE OFF
> more or less a no-op, so that wouldn't get you there.)

+1.  Assuming we know which information the user wants on the basis of
their choice of output format seems like a bad idea.  I mean, suppose
we introduced a new option that gathered lots of additional detail but
made the query run 3x slower.  Would everyone want that enabled all
the time any time they chose a non-text format?  Probably not.

If people want BUFFERS turned on essentially all the time, then let's
just flip the default for that, so that EXPLAIN ANALYZE does the
equivalent of what EXPLAIN (ANALYZE, BUFFERS) currently does, and make
people say EXPLAIN (ANALYZE, BUFFERS OFF) if they don't want all that
detail.  I think that's more or less what Andres was suggesting
upthread.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-08 20:09  Robert Haas <robertmhaas@gmail.com>
  parent: David Fetter <david@fetter.org>
  1 sibling, 0 replies; 49+ messages in thread

From: Robert Haas @ 2019-05-08 20:09 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; +Cc: Rafia Sabih <rafia.pghackers@gmail.com>; pgsql-hackers

On Tue, May 7, 2019 at 12:31 PM David Fetter <david@fetter.org> wrote:
> If you're tuning a query interactively, it's a lot simpler to prepend,
> for example,
>
>     EXPLAIN (ALL, FORMAT JSON)
>
> to it than to prepend something along the lines of
>
>     EXPLAIN(ANALYZE, VERBOSE, COSTS, BUFFERS, SETTINGS, TIMING, SUMMARY, PARTRIDGE_IN_A_PEAR_TREE, FORMAT JSON)
>
> to it.

This is something of an exaggeration of what could ever be necessary,
because COSTS and TIMING default to TRUE and SUMMARY defaults to TRUE
when ANALYZE is specified, and the PARTRIDGE_IN_A_PEAR_TREE option
seems not to have made it into the tree this cycle.

But you could need EXPLAIN (ANALYZE, VERBOSE, BUFFERS, SETTINGS,
FORMAT JSON), which is not quite so long, but admittedly still
somewhat long.  Flipping some of the defaults seems like it might be
the way to go.  I think turning SETTINGS and BUFFERS on by default
would be pretty sensible.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-08 21:22  Vik Fearing <vik.fearing@2ndquadrant.com>
  parent: David Fetter <david@fetter.org>
  3 siblings, 1 reply; 49+ messages in thread

From: Vik Fearing @ 2019-05-08 21:22 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; pgsql-hackers

On 07/05/2019 09:30, David Fetter wrote:
> Folks,
> 
> It can get a little tedious turning on (or off) all the boolean
> options to EXPLAIN, so please find attached a shortcut.

I would rather have a set of gucs such as default_explain_buffers,
default_explain_summary, and default_explain_format.

Of course if you default BUFFERS to on(*) and don't do ANALYZE, that
should not result in an error.

(*) Defaulting BUFFERS to on is something I want regardless of anything
else we do.
-- 
Vik Fearing                                          +33 6 46 75 15 36
http://2ndQuadrant.fr     PostgreSQL : Expertise, Formation et Support





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-08 22:31  Nasby, Jim <nasbyj@amazon.com>
  parent: Vik Fearing <vik.fearing@2ndquadrant.com>
  0 siblings, 0 replies; 49+ messages in thread

From: Nasby, Jim @ 2019-05-08 22:31 UTC (permalink / raw)
  To: Vik Fearing <vik.fearing@2ndquadrant.com>; +Cc: David Fetter <david@fetter.org>; pgsql-hackers


> On May 8, 2019, at 4:22 PM, Vik Fearing <vik.fearing@2ndquadrant.com> wrote:
> 
> On 07/05/2019 09:30, David Fetter wrote:
>> Folks,
>> 
>> It can get a little tedious turning on (or off) all the boolean
>> options to EXPLAIN, so please find attached a shortcut.
> 
> I would rather have a set of gucs such as default_explain_buffers,
> default_explain_summary, and default_explain_format.
> 
> Of course if you default BUFFERS to on(*) and don't do ANALYZE, that
> should not result in an error.
> 
> (*) Defaulting BUFFERS to on is something I want regardless of anything
> else we do.

I think this, plus Tom’s suggesting of changing what VERBOSE does, is the best way to handle this. Especially since VERBOSE is IMHO pretty useless...

I’m +1 on trying to move away from ANALYZE as well, though I think it’s mostly orthogonal...



^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-13 05:51  David Fetter <david@fetter.org>
  parent: Tom Lane <tgl@sss.pgh.pa.us>
  2 siblings, 2 replies; 49+ messages in thread

From: David Fetter @ 2019-05-13 05:51 UTC (permalink / raw)
  To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Stephen Frost <sfrost@snowman.net>; Andres Freund <andres@anarazel.de>; pgsql-hackers

On Tue, May 07, 2019 at 06:25:12PM -0400, Tom Lane wrote:
> Stephen Frost <sfrost@snowman.net> writes:
> > I'm generally in favor of doing something like what Tom is suggesting
> > with VERBOSE, but I also feel like it should be the default for formats
> > like JSON.  If you're asking for the output in JSON, then we really
> > should include everything that a flag like VERBOSE would contain because
> > you're pretty clearly planning to copy/paste that output into something
> > else to read it anyway.
> 
> Meh --- I don't especially care for non-orthogonal behaviors like that.
> If you wanted JSON but *not* all of the additional info, how would you
> specify that?  (The implementation I had in mind would make VERBOSE OFF
> more or less a no-op, so that wouldn't get you there.)
> 
> >> I do feel that it's a good idea to keep ANALYZE separate. "Execute
> >> the query or not" is a mighty fundamental thing.  I've never liked
> >> that name for the option though --- maybe we could deprecate it
> >> in favor of EXECUTE?
> 
> > Let's not fool ourselves by saying we'd 'deprecate' it because that
> > implies, at least to me, that there's some intention of later on
> > removing it
> 
> True, the odds of ever actually removing it are small :-(.  I meant
> mostly changing all of our docs to use the other spelling, except
> for some footnote.  Maybe we could call ANALYZE a "legacy spelling"
> of EXECUTE.

I tried changing it to EXEC (EXPLAIN EXECUTE is already a thing), but
got a giant flock of reduce-reduce conflicts along with a few
shift-reduce conflicts.

How do I fix this?

Best,
David.
-- 
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate

Attachments:

v1-0001-WIP-broken-Changed-EXPLAIN-ANALYZE-to-EXPLAIN-EXE.patch (text/x-diff, 104.7K) download From c8cdcf6ea0ee25b7159898a09210fc343b14e5e5 Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Sun, 12 May 2019 21:48:09 -0700 Subject: [PATCH v1] WIP (broken): Changed EXPLAIN ANALYZE to EXPLAIN EXEC To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit - In passing, changed a few of EXPLAIN's defaults diff --git a/doc/src/sgml/ref/explain.sgml b/doc/src/sgml/ref/explain.sgml index 385d10411f..63a3faede8 100644 --- a/doc/src/sgml/ref/explain.sgml +++ b/doc/src/sgml/ref/explain.sgml @@ -32,11 +32,11 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> EXPLAIN [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] <replaceable class="parameter">statement</replaceable> -EXPLAIN [ ANALYZE ] [ VERBOSE ] <replaceable class="parameter">statement</replaceable> +EXPLAIN [ EXEC ] [ VERBOSE ] <replaceable class="parameter">statement</replaceable> <phrase>where <replaceable class="parameter">option</replaceable> can be one of:</phrase> - ANALYZE [ <replaceable class="parameter">boolean</replaceable> ] + EXEC [ <replaceable class="parameter">boolean</replaceable> ] VERBOSE [ <replaceable class="parameter">boolean</replaceable> ] COSTS [ <replaceable class="parameter">boolean</replaceable> ] SETTINGS [ <replaceable class="parameter">boolean</replaceable> ] @@ -76,36 +76,37 @@ EXPLAIN [ ANALYZE ] [ VERBOSE ] <replaceable class="parameter">statement</replac </para> <para> - The <literal>ANALYZE</literal> option causes the statement to be actually + The <literal>EXEC</literal> option causes the statement to be actually executed, not only planned. Then actual run time statistics are added to the display, including the total elapsed time expended within each plan node (in milliseconds) and the total number of rows it actually returned. This is useful for seeing whether the planner's estimates - are close to reality. + are close to reality. For historical reasons, ANALYZE and ANALYSE can be + used instead of EXEC. </para> <important> <para> Keep in mind that the statement is actually executed when - the <literal>ANALYZE</literal> option is used. Although + the <literal>EXEC</literal> option is used. Although <command>EXPLAIN</command> will discard any output that a <command>SELECT</command> would return, other side effects of the statement will happen as usual. If you wish to use - <command>EXPLAIN ANALYZE</command> on an + <command>EXPLAIN EXEC</command> on an <command>INSERT</command>, <command>UPDATE</command>, <command>DELETE</command>, <command>CREATE TABLE AS</command>, or <command>EXECUTE</command> statement without letting the command affect your data, use this approach: <programlisting> BEGIN; -EXPLAIN ANALYZE ...; +EXPLAIN EXEC ...; ROLLBACK; </programlisting> </para> </important> <para> - Only the <literal>ANALYZE</literal> and <literal>VERBOSE</literal> options + Only the <literal>EXEC</literal> and <literal>VERBOSE</literal> options can be specified, and only in that order, without surrounding the option list in parentheses. Prior to <productname>PostgreSQL</productname> 9.0, the unparenthesized syntax was the only one supported. It is expected that @@ -118,7 +119,7 @@ ROLLBACK; <variablelist> <varlistentry> - <term><literal>ANALYZE</literal></term> + <term><literal>EXEC</literal></term> <listitem> <para> Carry out the command and show actual run times and other statistics. @@ -159,7 +160,7 @@ ROLLBACK; <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>. + default value. This parameter defaults to <literal>TRUE</literal>. </para> </listitem> </varlistentry> @@ -186,8 +187,8 @@ ROLLBACK; The number of blocks shown for an upper-level node includes those used by all its child nodes. In text format, only non-zero values are printed. This parameter may only be - used when <literal>ANALYZE</literal> is also enabled. It defaults to - <literal>FALSE</literal>. + used when <literal>EXEC</literal> is also enabled. It defaults to + <literal>TRUE</literal>. </para> </listitem> </varlistentry> @@ -203,7 +204,7 @@ ROLLBACK; not exact times, are needed. Run time of the entire statement is always measured, even when node-level timing is turned off with this option. - This parameter may only be used when <literal>ANALYZE</literal> is also + This parameter may only be used when <literal>EXEC</literal> is also enabled. It defaults to <literal>TRUE</literal>. </para> </listitem> @@ -215,9 +216,9 @@ ROLLBACK; <para> Include summary information (e.g., totaled timing information) after the query plan. Summary information is included by default when - <literal>ANALYZE</literal> is used but otherwise is not included by + <literal>EXEC</literal> is used but otherwise is not included by default, but can be enabled using this option. Planning time in - <command>EXPLAIN EXECUTE</command> includes the time required to fetch + <command>EXPLAIN EXEC</command> includes the time required to fetch the plan from the cache and the time required for re-planning, if necessary. </para> @@ -295,8 +296,8 @@ ROLLBACK; <para> In order to measure the run-time cost of each node in the execution plan, the current implementation of <command>EXPLAIN - ANALYZE</command> adds profiling overhead to query execution. - As a result, running <command>EXPLAIN ANALYZE</command> + EXEC</command> adds profiling overhead to query execution. + As a result, running <command>EXPLAIN EXEC</command> on a query can sometimes take significantly longer than executing the query normally. The amount of overhead depends on the nature of the query, as well as the platform being used. The worst case occurs @@ -423,7 +424,7 @@ PREPARE query(int, int) AS SELECT sum(bar) FROM test WHERE id &gt; $1 AND id &lt; $2 GROUP BY foo; -EXPLAIN ANALYZE EXECUTE query(100, 200); +EXPLAIN EXEC EXECUTE query(100, 200); QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 3dc0e8a4fb..c1057ca729 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10632,7 +10632,7 @@ opt_vacuum_relation_list: /***************************************************************************** * * QUERY: - * EXPLAIN [ANALYZE] [VERBOSE] query + * EXPLAIN [EXEC] [VERBOSE] query * EXPLAIN ( options ) query * *****************************************************************************/ @@ -10645,11 +10645,11 @@ ExplainStmt: n->options = NIL; $$ = (Node *) n; } - | EXPLAIN analyze_keyword opt_verbose ExplainableStmt + | EXPLAIN exec_keyword opt_verbose ExplainableStmt { ExplainStmt *n = makeNode(ExplainStmt); n->query = $4; - n->options = list_make1(makeDefElem("analyze", NULL, @2)); + n->options = list_make1(makeDefElem("exec", NULL, @2)); if ($3) n->options = lappend(n->options, makeDefElem("verbose", NULL, @3)); @@ -10703,7 +10703,7 @@ explain_option_elem: explain_option_name: NonReservedWord { $$ = $1; } - | analyze_keyword { $$ = "analyze"; } + | exec_keyword { $$ = "execute"; } ; explain_option_arg: @@ -10712,6 +10712,12 @@ explain_option_arg: | /* EMPTY */ { $$ = NULL; } ; +exec_keyword: + EXECUTE {} + | ANALYZE /* Legacy */ {} + | ANALYSE /* British and legacy */ {} + ; + /***************************************************************************** * * QUERY: diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h index db48f29501..09cc806d7e 100644 --- a/src/include/commands/explain.h +++ b/src/include/commands/explain.h @@ -30,8 +30,8 @@ typedef struct ExplainState StringInfo str; /* output buffer */ /* options */ bool verbose; /* be verbose */ - bool analyze; /* print actual times */ bool costs; /* print estimated costs */ + bool exec; /* actually execute the query, measure it */ bool buffers; /* print buffer usage */ bool timing; /* print detailed node timing */ bool summary; /* print total planning and execution timing */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index eb4c8b5e79..72730fcfaf 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -52,7 +52,7 @@ * mean that the plan can't queue any AFTER triggers; just that the caller * is responsible for there being a trigger context for them to be queued in. */ -#define EXEC_FLAG_EXPLAIN_ONLY 0x0001 /* EXPLAIN, no ANALYZE */ +#define EXEC_FLAG_EXPLAIN_ONLY 0x0001 /* EXPLAIN, no EXEC */ #define EXEC_FLAG_REWIND 0x0002 /* need efficient rescan */ #define EXEC_FLAG_BACKWARD 0x0004 /* need backward scan */ #define EXEC_FLAG_MARK 0x0008 /* need mark/restore */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index ff3328752e..51f9263e0b 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -2189,7 +2189,7 @@ typedef struct GatherMergeState } GatherMergeState; /* ---------------- - * Values displayed by EXPLAIN ANALYZE + * Values displayed by EXPLAIN EXEC * ---------------- */ typedef struct HashInstrumentation diff --git a/contrib/auto_explain/auto_explain.c b/contrib/auto_explain/auto_explain.c index edc50f9368..1aeda40ea1 100644 --- a/contrib/auto_explain/auto_explain.c +++ b/contrib/auto_explain/auto_explain.c @@ -23,7 +23,7 @@ PG_MODULE_MAGIC; /* GUC variables */ static int auto_explain_log_min_duration = -1; /* msec or -1 */ -static bool auto_explain_log_analyze = false; +static bool auto_explain_log_exec = false; static bool auto_explain_log_verbose = false; static bool auto_explain_log_buffers = false; static bool auto_explain_log_triggers = false; @@ -102,10 +102,10 @@ _PG_init(void) NULL, NULL); - DefineCustomBoolVariable("auto_explain.log_analyze", - "Use EXPLAIN ANALYZE for plan logging.", + DefineCustomBoolVariable("auto_explain.log_exec", + "Use EXPLAIN EXEC for plan logging.", NULL, - &auto_explain_log_analyze, + &auto_explain_log_exec, false, PGC_SUSET, 0, @@ -148,7 +148,7 @@ _PG_init(void) DefineCustomBoolVariable("auto_explain.log_triggers", "Include trigger statistics in plans.", - "This has no effect unless log_analyze is also set.", + "This has no effect unless log_exec is also set.", &auto_explain_log_triggers, false, PGC_SUSET, @@ -258,8 +258,8 @@ explain_ExecutorStart(QueryDesc *queryDesc, int eflags) if (auto_explain_enabled() && current_query_sampled) { - /* Enable per-node instrumentation iff log_analyze is required. */ - if (auto_explain_log_analyze && (eflags & EXEC_FLAG_EXPLAIN_ONLY) == 0) + /* Enable per-node instrumentation iff log_exec is required. */ + if (auto_explain_log_exec && (eflags & EXEC_FLAG_EXPLAIN_ONLY) == 0) { if (auto_explain_log_timing) queryDesc->instrument_options |= INSTRUMENT_TIMER; @@ -362,18 +362,18 @@ explain_ExecutorEnd(QueryDesc *queryDesc) { ExplainState *es = NewExplainState(); - es->analyze = (queryDesc->instrument_options && auto_explain_log_analyze); + es->exec = (queryDesc->instrument_options && auto_explain_log_exec); es->verbose = auto_explain_log_verbose; - es->buffers = (es->analyze && auto_explain_log_buffers); - es->timing = (es->analyze && auto_explain_log_timing); - es->summary = es->analyze; + es->buffers = (es->exec && auto_explain_log_buffers); + es->timing = (es->exec && auto_explain_log_timing); + es->summary = es->exec; es->format = auto_explain_log_format; es->settings = auto_explain_log_settings; ExplainBeginOutput(es); ExplainQueryText(es, queryDesc); ExplainPrintPlan(es, queryDesc); - if (es->analyze && auto_explain_log_triggers) + if (es->exec && auto_explain_log_triggers) ExplainPrintTriggers(es, queryDesc); if (es->costs) ExplainPrintJITSummary(es, queryDesc); diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c index 85534a3a76..58e88c9957 100644 --- a/contrib/file_fdw/file_fdw.c +++ b/contrib/file_fdw/file_fdw.c @@ -661,7 +661,7 @@ fileBeginForeignScan(ForeignScanState *node, int eflags) FileFdwExecutionState *festate; /* - * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL. + * Do nothing in EXPLAIN (no EXEC) case. node->fdw_state stays NULL. */ if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return; diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 4cbfb12a66..e84d31cd7f 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -1413,7 +1413,7 @@ postgresBeginForeignScan(ForeignScanState *node, int eflags) int numParams; /* - * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL. + * Do nothing in EXPLAIN (no EXEC) case. node->fdw_state stays NULL. */ if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return; @@ -1804,7 +1804,7 @@ postgresBeginForeignModify(ModifyTableState *mtstate, RangeTblEntry *rte; /* - * Do nothing in EXPLAIN (no ANALYZE) case. resultRelInfo->ri_FdwState + * Do nothing in EXPLAIN (no EXEC) case. resultRelInfo->ri_FdwState * stays NULL. */ if (eflags & EXEC_FLAG_EXPLAIN_ONLY) @@ -2345,7 +2345,7 @@ postgresBeginDirectModify(ForeignScanState *node, int eflags) int numParams; /* - * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL. + * Do nothing in EXPLAIN (no EXEC) case. node->fdw_state stays NULL. */ if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return; @@ -2477,7 +2477,7 @@ postgresIterateDirectModify(ForeignScanState *node) if (dmstate->set_processed) estate->es_processed += dmstate->num_tuples; - /* Increment the tuple count for EXPLAIN ANALYZE if necessary. */ + /* Increment the tuple count for EXPLAIN EXEC if necessary. */ if (instr) instr->tuplecount += dmstate->num_tuples; diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index a6c6de78f1..15dd95e3b7 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -147,6 +147,7 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, TupOutputState *tstate; List *rewritten; ListCell *lc; + bool timing_buffers_set = false; bool timing_set = false; bool summary_set = false; @@ -155,14 +156,17 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, { DefElem *opt = (DefElem *) lfirst(lc); - if (strcmp(opt->defname, "analyze") == 0) - es->analyze = defGetBoolean(opt); + if (strcmp(opt->defname, "exec") == 0) + es->exec = defGetBoolean(opt); else if (strcmp(opt->defname, "verbose") == 0) es->verbose = defGetBoolean(opt); else if (strcmp(opt->defname, "costs") == 0) es->costs = defGetBoolean(opt); else if (strcmp(opt->defname, "buffers") == 0) + { + buffers_set = true; es->buffers = defGetBoolean(opt); + } else if (strcmp(opt->defname, "settings") == 0) es->settings = defGetBoolean(opt); else if (strcmp(opt->defname, "timing") == 0) @@ -202,22 +206,21 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, parser_errposition(pstate, opt->location))); } - if (es->buffers && !es->analyze) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("EXPLAIN option BUFFERS requires ANALYZE"))); + /* Turn buffers off automatically when exec isn't set */ + if (!es->exec) + es->buffers = false; /* if the timing was not set explicitly, set default value */ - es->timing = (timing_set) ? es->timing : es->analyze; + es->timing = (timing_set) ? es->timing : es->exec; - /* check that timing is used with EXPLAIN ANALYZE */ - if (es->timing && !es->analyze) + /* check that timing is used with EXPLAIN EXEC */ + if (es->timing && !es->exec) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("EXPLAIN option TIMING requires ANALYZE"))); + errmsg("EXPLAIN option TIMING requires EXEC"))); /* if the summary was not set explicitly, set default value */ - es->summary = (summary_set) ? es->summary : es->analyze; + es->summary = (summary_set) ? es->summary : es->exec; /* * Parse analysis was done already, but we still have to run the rule @@ -286,8 +289,11 @@ NewExplainState(void) { ExplainState *es = (ExplainState *) palloc0(sizeof(ExplainState)); - /* Set default options (most fields can be left as zeroes). */ + /* Set default options (fields can be left as zeroes). */ es->costs = true; + es->buffers = true; + es->settings = true; + es->timing = true; /* Prepare output buffer. */ es->str = makeStringInfo(); @@ -415,7 +421,7 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, /* * Likewise for DECLARE CURSOR. * - * Notice that if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll + * Notice that if you say EXPLAIN EXEC DECLARE CURSOR then we'll * actually run the query. This is different from pre-8.3 behavior * but seems more useful than not running the query. No cursor will * be created, however. @@ -475,9 +481,9 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, Assert(plannedstmt->commandType != CMD_UTILITY); - if (es->analyze && es->timing) + if (es->exec && es->timing) instrument_option |= INSTRUMENT_TIMER; - else if (es->analyze) + else if (es->exec) instrument_option |= INSTRUMENT_ROWS; if (es->buffers) @@ -512,7 +518,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, dest, params, queryEnv, instrument_option); /* Select execution options */ - if (es->analyze) + if (es->exec) eflags = 0; /* default run-to-completion flags */ else eflags = EXEC_FLAG_EXPLAIN_ONLY; @@ -523,11 +529,11 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, ExecutorStart(queryDesc, eflags); /* Execute the plan for statistics if asked for */ - if (es->analyze) + if (es->exec) { ScanDirection dir; - /* EXPLAIN ANALYZE CREATE TABLE AS WITH NO DATA is weird */ + /* EXPLAIN EXEC CREATE TABLE AS WITH NO DATA is weird */ if (into && into->skipData) dir = NoMovementScanDirection; else @@ -556,7 +562,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, } /* Print info about runtime of triggers */ - if (es->analyze) + if (es->exec) ExplainPrintTriggers(es, queryDesc); /* @@ -581,7 +587,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, PopActiveSnapshot(); /* We need a CCI just in case query expanded to multiple plans */ - if (es->analyze) + if (es->exec) CommandCounterIncrement(); totaltime += elapsed_time(&starttime); @@ -592,7 +598,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, * user can set SUMMARY OFF to not have the timing information included in * the output). By default, ANALYZE sets SUMMARY to true. */ - if (es->summary && es->analyze) + if (es->summary && es->exec) ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3, es); @@ -834,7 +840,7 @@ ExplainPrintJIT(ExplainState *es, int jit_flags, "Expressions", jit_flags & PGJIT_EXPR ? "true" : "false", "Deforming", jit_flags & PGJIT_DEFORM ? "true" : "false"); - if (es->analyze && es->timing) + if (es->exec && es->timing) { appendStringInfoSpaces(es->str, es->indent * 2); appendStringInfo(es->str, @@ -860,7 +866,7 @@ ExplainPrintJIT(ExplainState *es, int jit_flags, ExplainPropertyBool("Deforming", jit_flags & PGJIT_DEFORM, es); ExplainCloseGroup("Options", "Options", true, es); - if (es->analyze && es->timing) + if (es->exec && es->timing) { ExplainOpenGroup("Timing", "Timing", true, es); @@ -1505,7 +1511,7 @@ ExplainNode(PlanState *planstate, List *ancestors, if (planstate->instrument) InstrEndLoop(planstate->instrument); - if (es->analyze && + if (es->exec && planstate->instrument && planstate->instrument->nloops > 0) { double nloops = planstate->instrument->nloops; @@ -1537,7 +1543,7 @@ ExplainNode(PlanState *planstate, List *ancestors, ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es); } } - else if (es->analyze) + else if (es->exec) { if (es->format == EXPLAIN_FORMAT_TEXT) appendStringInfoString(es->str, " (never executed)"); @@ -1606,7 +1612,7 @@ ExplainNode(PlanState *planstate, List *ancestors, if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); - if (es->analyze) + if (es->exec) ExplainPropertyFloat("Heap Fetches", NULL, planstate->instrument->ntuples2, 0, es); break; @@ -1624,7 +1630,7 @@ ExplainNode(PlanState *planstate, List *ancestors, if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); - if (es->analyze) + if (es->exec) show_tidbitmap_info((BitmapHeapScanState *) planstate, es); break; case T_SampleScan: @@ -1658,7 +1664,7 @@ ExplainNode(PlanState *planstate, List *ancestors, if (gather->initParam) show_eval_params(gather->initParam, es); - if (es->analyze) + if (es->exec) { int nworkers; @@ -1704,7 +1710,7 @@ ExplainNode(PlanState *planstate, List *ancestors, if (gm->initParam) show_eval_params(gm->initParam, es); - if (es->analyze) + if (es->exec) { int nworkers; @@ -1869,7 +1875,7 @@ ExplainNode(PlanState *planstate, List *ancestors, show_buffer_usage(es, &planstate->instrument->bufusage); /* Show worker detail */ - if (es->analyze && es->verbose && planstate->worker_instrument) + if (es->exec && es->verbose && planstate->worker_instrument) { WorkerInstrumentation *w = planstate->worker_instrument; bool opened_group = false; @@ -2531,12 +2537,12 @@ show_tablesample(TableSampleClause *tsc, PlanState *planstate, } /* - * If it's EXPLAIN ANALYZE, show tuplesort stats for a sort node + * If it's EXPLAIN EXEC, show tuplesort stats for a sort node */ static void show_sort_info(SortState *sortstate, ExplainState *es) { - if (!es->analyze) + if (!es->exec) return; if (sortstate->sort_Done && sortstate->tuplesortstate != NULL) @@ -2716,7 +2722,7 @@ show_hash_info(HashState *hashstate, ExplainState *es) } /* - * If it's EXPLAIN ANALYZE, show exact/lossy pages for a BitmapHeapScan node + * If it's EXPLAIN EXEC, show exact/lossy pages for a BitmapHeapScan node */ static void show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es) @@ -2744,7 +2750,7 @@ show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es) } /* - * If it's EXPLAIN ANALYZE, show instrumentation information for a plan node + * If it's EXPLAIN EXEC, show instrumentation information for a plan node * * "which" identifies which instrumentation counter to print */ @@ -2755,7 +2761,7 @@ show_instrumentation_count(const char *qlabel, int which, double nfiltered; double nloops; - if (!es->analyze || !planstate->instrument) + if (!es->exec || !planstate->instrument) return; if (which == 2) @@ -3283,8 +3289,8 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors, show_instrumentation_count("Rows Removed by Conflict Filter", 1, &mtstate->ps, es); } - /* EXPLAIN ANALYZE display of actual outcome for each tuple proposed */ - if (es->analyze && mtstate->ps.instrument) + /* EXPLAIN EXEC display of actual outcome for each tuple proposed */ + if (es->exec && mtstate->ps.instrument) { double total; double insert_path; diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 2beb378145..8c4320df58 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -2365,7 +2365,7 @@ FindTriggerIncompatibleWithInheritance(TriggerDesc *trigdesc) * trigdata: trigger descriptor. * tgindx: trigger's index in finfo and instr arrays. * finfo: array of cached trigger function call information. - * instr: optional array of EXPLAIN ANALYZE instrumentation state. + * instr: optional array of EXPLAIN EXEC instrumentation state. * per_tuple_context: memory context to execute the function in. * * Returns the tuple (or NULL) as returned by the function. @@ -2406,7 +2406,7 @@ ExecCallTriggerFunc(TriggerData *trigdata, Assert(finfo->fn_oid == trigdata->tg_trigger->tgfoid); /* - * If doing EXPLAIN ANALYZE, start charging time to this trigger. + * If doing EXPLAIN EXEC, start charging time to this trigger. */ if (instr) InstrStartNode(instr + tgindx); @@ -2455,7 +2455,7 @@ ExecCallTriggerFunc(TriggerData *trigdata, fcinfo->flinfo->fn_oid))); /* - * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count + * If doing EXPLAIN EXEC, stop charging time to this trigger, and count * one "tuple returned" (really the number of firings). */ if (instr) @@ -4171,7 +4171,7 @@ afterTriggerDeleteHeadEventChunk(AfterTriggersQueryData *qs) * rel: open relation for event. * trigdesc: working copy of rel's trigger info. * finfo: array of fmgr lookup cache entries (one per trigger in trigdesc). - * instr: array of EXPLAIN ANALYZE instrumentation nodes (one per trigger), + * instr: array of EXPLAIN EXEC instrumentation nodes (one per trigger), * or NULL if no instrumentation is wanted. * per_tuple_context: memory context to call trigger function in. * trig_tuple_slot1: scratch slot for tg_trigtuple (foreign tables only) @@ -4216,7 +4216,7 @@ AfterTriggerExecute(EState *estate, elog(ERROR, "could not find trigger %u", tgoid); /* - * If doing EXPLAIN ANALYZE, start charging time to this trigger. We want + * If doing EXPLAIN EXEC, start charging time to this trigger. We want * to include time spent re-fetching tuples in the trigger cost. */ if (instr) @@ -4359,7 +4359,7 @@ AfterTriggerExecute(EState *estate, ExecClearTuple(LocTriggerData.tg_newslot); /* - * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count + * If doing EXPLAIN EXEC, stop charging time to this trigger, and count * one "tuple returned" (really the number of firings). */ if (instr) diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index ed7c0606bf..cbbc7e087b 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -390,7 +390,7 @@ standard_ExecutorRun(QueryDesc *queryDesc, * * This routine must be called after the last ExecutorRun call. * It performs cleanup such as firing AFTER triggers. It is - * separate from ExecutorEnd because EXPLAIN ANALYZE needs to + * separate from ExecutorEnd because EXPLAIN EXEC needs to * include these actions in the total runtime. * * We provide a function hook variable that lets loadable plugins @@ -1365,7 +1365,7 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo, * on other relations, which will be processed in the context of the outer * query. For efficiency's sake, we want to have a ResultRelInfo for those * triggers too; that can avoid repeated re-opening of the relation. (It - * also provides a way for EXPLAIN ANALYZE to report the runtimes of such + * also provides a way for EXPLAIN EXEC to report the runtimes of such * triggers.) So we make additional ResultRelInfo's as needed, and save them * in es_trig_target_relations. */ diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index 3d4b01cb4d..adcccbbdcb 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -273,11 +273,11 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e) e->pcxt); break; case T_HashState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecHashEstimate((HashState *) planstate, e->pcxt); break; case T_SortState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecSortEstimate((SortState *) planstate, e->pcxt); break; @@ -486,11 +486,11 @@ ExecParallelInitializeDSM(PlanState *planstate, d->pcxt); break; case T_HashState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecHashInitializeDSM((HashState *) planstate, d->pcxt); break; case T_SortState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecSortInitializeDSM((SortState *) planstate, d->pcxt); break; @@ -1294,11 +1294,11 @@ ExecParallelInitializeWorker(PlanState *planstate, ParallelWorkerContext *pwcxt) pwcxt); break; case T_HashState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecHashInitializeWorker((HashState *) planstate, pwcxt); break; case T_SortState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecSortInitializeWorker((SortState *) planstate, pwcxt); break; diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index 64eec91f8b..c6a2906db5 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -193,7 +193,7 @@ MultiExecPrivateHash(HashState *node) if (hashtable->nbuckets != hashtable->nbuckets_optimal) ExecHashIncreaseNumBuckets(hashtable); - /* Account for the buckets in spaceUsed (reported in EXPLAIN ANALYZE) */ + /* Account for the buckets in spaceUsed (reported in EXPLAIN EXEC) */ hashtable->spaceUsed += hashtable->nbuckets * sizeof(HashJoinTuple); if (hashtable->spaceUsed > hashtable->spacePeak) hashtable->spacePeak = hashtable->spaceUsed; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 92d0507949..cd5e834ae9 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -3215,19 +3215,19 @@ GetCommandLogLevel(Node *parsetree) case T_ExplainStmt: { ExplainStmt *stmt = (ExplainStmt *) parsetree; - bool analyze = false; + bool exec = false; ListCell *lc; - /* Look through an EXPLAIN ANALYZE to the contained stmt */ + /* Look through an EXPLAIN EXEC to the contained stmt */ foreach(lc, stmt->options) { DefElem *opt = (DefElem *) lfirst(lc); - if (strcmp(opt->defname, "analyze") == 0) - analyze = defGetBoolean(opt); + if (strcmp(opt->defname, "exec") == 0) + exec = defGetBoolean(opt); /* don't "break", as explain.c will use the last value */ } - if (analyze) + if (exec) return GetCommandLogLevel(stmt->query); /* Plain EXPLAIN isn't so interesting */ diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index e4c03de221..ac0673dafc 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -2848,11 +2848,11 @@ psql_completion(const char *text, int start, int end) /* * EXPLAIN [ ( option [, ...] ) ] statement - * EXPLAIN [ ANALYZE ] [ VERBOSE ] statement + * EXPLAIN [ EXEC ] [ VERBOSE ] statement */ else if (Matches("EXPLAIN")) COMPLETE_WITH("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", - "ANALYZE", "VERBOSE"); + "EXEC", "VERBOSE"); else if (HeadMatches("EXPLAIN", "(*") && !HeadMatches("EXPLAIN", "(*)")) { @@ -2862,19 +2862,23 @@ psql_completion(const char *text, int start, int end) * one word, so the above test is correct. */ if (ends_with(prev_wd, '(') || ends_with(prev_wd, ',')) - COMPLETE_WITH("ANALYZE", "VERBOSE", "COSTS", "BUFFERS", + COMPLETE_WITH("EXEC", "VERBOSE", "COSTS", "BUFFERS", "TIMING", "SUMMARY", "FORMAT"); - else if (TailMatches("ANALYZE|VERBOSE|COSTS|BUFFERS|TIMING|SUMMARY")) + else if (TailMatches("EXEC|VERBOSE|COSTS|BUFFERS|TIMING|SUMMARY")) COMPLETE_WITH("ON", "OFF"); else if (TailMatches("FORMAT")) COMPLETE_WITH("TEXT", "XML", "JSON", "YAML"); } - else if (Matches("EXPLAIN", "ANALYZE")) + else if (Matches("EXPLAIN", "EXEC") || + Matches("EXPLAIN", "ANALYZE") || + Matches("EXPLAIN", "ANALYSE")) COMPLETE_WITH("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE"); else if (Matches("EXPLAIN", "(*)") || Matches("EXPLAIN", "VERBOSE") || - Matches("EXPLAIN", "ANALYZE", "VERBOSE")) + Matches("EXPLAIN", "EXEC", "VERBOSE") || + Matches("EXPLAIN", "ANALYZE", "VERBOSE") || + Matches("EXPLAIN", "ANALYSE", "VERBOSE")) COMPLETE_WITH("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE"); /* FETCH && MOVE */ diff --git a/doc/src/sgml/auto-explain.sgml b/doc/src/sgml/auto-explain.sgml index 3d619d4a3d..3025a57232 100644 --- a/doc/src/sgml/auto-explain.sgml +++ b/doc/src/sgml/auto-explain.sgml @@ -65,14 +65,14 @@ LOAD 'auto_explain'; <varlistentry> <term> - <varname>auto_explain.log_analyze</varname> (<type>boolean</type>) + <varname>auto_explain.log_exec</varname> (<type>boolean</type>) <indexterm> - <primary><varname>auto_explain.log_analyze</varname> configuration parameter</primary> + <primary><varname>auto_explain.log_exec</varname> configuration parameter</primary> </indexterm> </term> <listitem> <para> - <varname>auto_explain.log_analyze</varname> causes <command>EXPLAIN ANALYZE</command> + <varname>auto_explain.log_exec</varname> causes <command>EXPLAIN EXEC</command> output, rather than just <command>EXPLAIN</command> output, to be printed when an execution plan is logged. This parameter is off by default. Only superusers can change this setting. @@ -102,7 +102,7 @@ LOAD 'auto_explain'; usage statistics are printed when an execution plan is logged; it's equivalent to the <literal>BUFFERS</literal> option of <command>EXPLAIN</command>. This parameter has no effect - unless <varname>auto_explain.log_analyze</varname> is enabled. + unless <varname>auto_explain.log_exec</varname> is enabled. This parameter is off by default. Only superusers can change this setting. </para> @@ -126,7 +126,7 @@ LOAD 'auto_explain'; parameter to off when only actual row counts, and not exact times, are needed. This parameter has no effect - unless <varname>auto_explain.log_analyze</varname> is enabled. + unless <varname>auto_explain.log_exec</varname> is enabled. This parameter is on by default. Only superusers can change this setting. </para> @@ -145,7 +145,7 @@ LOAD 'auto_explain'; <varname>auto_explain.log_triggers</varname> causes trigger execution statistics to be included when an execution plan is logged. This parameter has no effect - unless <varname>auto_explain.log_analyze</varname> is enabled. + unless <varname>auto_explain.log_exec</varname> is enabled. This parameter is off by default. Only superusers can change this setting. </para> @@ -283,7 +283,7 @@ auto_explain.log_min_duration = '3s' <programlisting> postgres=# LOAD 'auto_explain'; postgres=# SET auto_explain.log_min_duration = 0; -postgres=# SET auto_explain.log_analyze = true; +postgres=# SET auto_explain.log_exec = true; postgres=# SELECT count(*) FROM pg_class, pg_index WHERE oid = indrelid AND indisunique; diff --git a/doc/src/sgml/bloom.sgml b/doc/src/sgml/bloom.sgml index 6eeaddee09..5b4ede2db1 100644 --- a/doc/src/sgml/bloom.sgml +++ b/doc/src/sgml/bloom.sgml @@ -129,7 +129,7 @@ CREATE INDEX <para> A sequential scan over this large table takes a long time: <programlisting> -=# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; +=# EXPLAIN EXEC SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; QUERY PLAN ------------------------------------------------------------------------------------------------------------ Seq Scan on tbloom (cost=0.00..213694.08 rows=1 width=24) (actual time=1445.438..1445.438 rows=0 loops=1) @@ -145,7 +145,7 @@ CREATE INDEX So the planner will usually select an index scan if possible. With a btree index, we get results like this: <programlisting> -=# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; +=# EXPLAIN EXEC SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- Index Only Scan using btreeidx on tbloom (cost=0.56..298311.96 rows=1 width=24) (actual time=445.709..445.709 rows=0 loops=1) @@ -160,7 +160,7 @@ CREATE INDEX <para> Bloom is better than btree in handling this type of search: <programlisting> -=# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; +=# EXPLAIN EXEC SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------- Bitmap Heap Scan on tbloom (cost=178435.39..178439.41 rows=1 width=24) (actual time=76.698..76.698 rows=0 loops=1) @@ -187,7 +187,7 @@ CREATE INDEX A better strategy for btree is to create a separate index on each column. Then the planner will choose something like this: <programlisting> -=# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; +=# EXPLAIN EXEC SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------ Bitmap Heap Scan on tbloom (cost=9.29..13.30 rows=1 width=24) (actual time=0.148..0.148 rows=0 loops=1) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 84341a30e5..41e9a64182 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -6441,7 +6441,7 @@ log_line_prefix = '%m [%p] %q%u@%d/%a ' <command>UPDATE</command>, <command>DELETE</command>, <command>TRUNCATE</command>, and <command>COPY FROM</command>. <command>PREPARE</command>, <command>EXECUTE</command>, and - <command>EXPLAIN ANALYZE</command> statements are also logged if their + <command>EXPLAIN EXEC</command> statements are also logged if their contained command is of an appropriate type. For clients using extended query protocol, logging occurs when an Execute message is received, and values of the Bind parameters are included diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index a0a7435a03..407f94dfbe 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -4498,7 +4498,7 @@ EXPLAIN SELECT count(*) FROM measurement WHERE logdate &gt;= DATE '2008-01-01'; performed here for parameter values which are known during the initialization phase of execution. Partitions which are pruned during this stage will not show up in the query's - <command>EXPLAIN</command> or <command>EXPLAIN ANALYZE</command>. + <command>EXPLAIN</command> or <command>EXPLAIN EXEC</command>. It is possible to determine the number of partitions which were removed during this phase by observing the <quote>Subplans Removed</quote> property in the @@ -4518,7 +4518,7 @@ EXPLAIN SELECT count(*) FROM measurement WHERE logdate &gt;= DATE '2008-01-01'; execution parameters being used by partition pruning changes. Determining if partitions were pruned during this phase requires careful inspection of the <literal>loops</literal> property in - the <command>EXPLAIN ANALYZE</command> output. Subplans + the <command>EXPLAIN EXEC</command> output. Subplans corresponding to different partitions may have different values for it depending on how many times each of them was pruned during execution. Some may be shown as <literal>(never executed)</literal> diff --git a/doc/src/sgml/fdwhandler.sgml b/doc/src/sgml/fdwhandler.sgml index 27b94fb611..0f1e80b3b9 100644 --- a/doc/src/sgml/fdwhandler.sgml +++ b/doc/src/sgml/fdwhandler.sgml @@ -937,7 +937,7 @@ IterateDirectModify(ForeignScanState *node); Whether the query has the clause or not, the query's reported row count must be incremented by the FDW itself. When the query doesn't have the clause, the FDW must also increment the row count for the - <structname>ForeignScanState</structname> node in the <command>EXPLAIN ANALYZE</command> + <structname>ForeignScanState</structname> node in the <command>EXPLAIN EXEC</command> case. </para> @@ -1123,7 +1123,7 @@ ExplainForeignScan(ForeignScanState *node, The flag fields in <literal>es</literal> can be used to determine what to print, and the state of the <structname>ForeignScanState</structname> node can be inspected to provide run-time statistics in the <command>EXPLAIN - ANALYZE</command> case. + EXEC</command> case. </para> <para> @@ -1148,7 +1148,7 @@ ExplainForeignModify(ModifyTableState *mtstate, The flag fields in <literal>es</literal> can be used to determine what to print, and the state of the <structname>ModifyTableState</structname> node can be inspected to provide run-time statistics in the <command>EXPLAIN - ANALYZE</command> case. The first four arguments are the same as for + EXEC</command> case. The first four arguments are the same as for <function>BeginForeignModify</function>. </para> @@ -1172,7 +1172,7 @@ ExplainDirectModify(ForeignScanState *node, The flag fields in <literal>es</literal> can be used to determine what to print, and the state of the <structname>ForeignScanState</structname> node can be inspected to provide run-time statistics in the <command>EXPLAIN - ANALYZE</command> case. + EXEC</command> case. </para> <para> diff --git a/doc/src/sgml/indices.sgml b/doc/src/sgml/indices.sgml index 95c0a1926c..decaaa6209 100644 --- a/doc/src/sgml/indices.sgml +++ b/doc/src/sgml/indices.sgml @@ -1498,7 +1498,7 @@ CREATE INDEX test1c_content_y_index ON test1c (content COLLATE "y"); possibilities: Either the system is right and using the index is indeed not appropriate, or the cost estimates of the query plans are not reflecting reality. So you should time your query with - and without indexes. The <command>EXPLAIN ANALYZE</command> + and without indexes. The <command>EXPLAIN EXEC</command> command can be useful here. </para> </listitem> diff --git a/doc/src/sgml/jit.sgml b/doc/src/sgml/jit.sgml index a21a07ef71..cb288d8b73 100644 --- a/doc/src/sgml/jit.sgml +++ b/doc/src/sgml/jit.sgml @@ -145,7 +145,7 @@ <acronym>JIT</acronym> is used or not. As an example, here is a query that is not using <acronym>JIT</acronym>: <screen> -=# EXPLAIN ANALYZE SELECT SUM(relpages) FROM pg_class; +=# EXPLAIN EXEC SELECT SUM(relpages) FROM pg_class; QUERY PLAN ------------------------------------------------------------------------------------------------------------- Aggregate (cost=16.27..16.29 rows=1 width=8) (actual time=0.303..0.303 rows=1 loops=1) @@ -161,7 +161,7 @@ <screen> =# SET jit_above_cost = 10; SET -=# EXPLAIN ANALYZE SELECT SUM(relpages) FROM pg_class; +=# EXPLAIN EXEC SELECT SUM(relpages) FROM pg_class; QUERY PLAN ------------------------------------------------------------------------------------------------------------- Aggregate (cost=16.27..16.29 rows=1 width=8) (actual time=6.049..6.049 rows=1 loops=1) diff --git a/doc/src/sgml/parallel.sgml b/doc/src/sgml/parallel.sgml index af5d48a5c7..b3e2285f05 100644 --- a/doc/src/sgml/parallel.sgml +++ b/doc/src/sgml/parallel.sgml @@ -442,7 +442,7 @@ EXPLAIN SELECT * FROM pgbench_accounts WHERE filler LIKE '%x%'; </para> <para> - When executing a parallel plan, you can use <literal>EXPLAIN (ANALYZE, + When executing a parallel plan, you can use <literal>EXPLAIN (EXEC, VERBOSE)</literal> to display per-worker statistics for each plan node. This may be useful in determining whether the work is being evenly distributed between all plan nodes and more generally in understanding the diff --git a/doc/src/sgml/perform.sgml b/doc/src/sgml/perform.sgml index a84be85159..3a890c5a71 100644 --- a/doc/src/sgml/perform.sgml +++ b/doc/src/sgml/perform.sgml @@ -533,25 +533,25 @@ WHERE t1.unique1 &lt; 100 AND t1.unique2 = t2.unique2; which shows that the planner thinks that sorting <literal>onek</literal> by index-scanning is about 12% more expensive than sequential-scan-and-sort. Of course, the next question is whether it's right about that. - We can investigate that using <command>EXPLAIN ANALYZE</command>, as discussed + We can investigate that using <command>EXPLAIN EXEC</command>, as discussed below. </para> </sect2> - <sect2 id="using-explain-analyze"> - <title><command>EXPLAIN ANALYZE</command></title> + <sect2 id="using-explain-exec"> + <title><command>EXPLAIN EXEC</command></title> <para> It is possible to check the accuracy of the planner's estimates - by using <command>EXPLAIN</command>'s <literal>ANALYZE</literal> option. With this + by using <command>EXPLAIN</command>'s <literal>EXEC</literal> option. With this option, <command>EXPLAIN</command> actually executes the query, and then displays the true row counts and true run time accumulated within each plan node, along with the same estimates that a plain <command>EXPLAIN</command> shows. For example, we might get a result like this: <screen> -EXPLAIN ANALYZE SELECT * +EXPLAIN EXEC SELECT * FROM tenk1 t1, tenk2 t2 WHERE t1.unique1 &lt; 10 AND t1.unique2 = t2.unique2; @@ -590,12 +590,12 @@ WHERE t1.unique1 &lt; 10 AND t1.unique2 = t2.unique2; </para> <para> - In some cases <command>EXPLAIN ANALYZE</command> shows additional execution + In some cases <command>EXPLAIN EXEC</command> shows additional execution statistics beyond the plan node execution times and row counts. For example, Sort and Hash nodes provide extra information: <screen> -EXPLAIN ANALYZE SELECT * +EXPLAIN EXEC SELECT * FROM tenk1 t1, tenk2 t2 WHERE t1.unique1 &lt; 100 AND t1.unique2 = t2.unique2 ORDER BY t1.fivethous; @@ -630,7 +630,7 @@ WHERE t1.unique1 &lt; 100 AND t1.unique2 = t2.unique2 ORDER BY t1.fivethous; filter condition: <screen> -EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE ten &lt; 7; +EXPLAIN EXEC SELECT * FROM tenk1 WHERE ten &lt; 7; QUERY PLAN --------------------------------------------------------------------------------------------------------- @@ -653,7 +653,7 @@ EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE ten &lt; 7; specific point: <screen> -EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; +EXPLAIN EXEC SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; QUERY PLAN ------------------------------------------------------------------------------------------------------ @@ -672,7 +672,7 @@ EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; <screen> SET enable_seqscan TO off; -EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; +EXPLAIN EXEC SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- @@ -695,7 +695,7 @@ EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; <literal>ANALYZE</literal> to get even more run time statistics: <screen> -EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000; +EXPLAIN (EXEC, BUFFERS) SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- @@ -719,7 +719,7 @@ EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique </para> <para> - Keep in mind that because <command>EXPLAIN ANALYZE</command> actually + Keep in mind that because <command>EXPLAIN EXEC</command> actually runs the query, any side-effects will happen as usual, even though whatever results the query might output are discarded in favor of printing the <command>EXPLAIN</command> data. If you want to analyze a @@ -729,7 +729,7 @@ EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique <screen> BEGIN; -EXPLAIN ANALYZE UPDATE tenk1 SET hundred = hundred + 1 WHERE unique1 &lt; 100; +EXPLAIN EXEC UPDATE tenk1 SET hundred = hundred + 1 WHERE unique1 &lt; 100; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- @@ -795,13 +795,13 @@ EXPLAIN UPDATE parent SET f2 = f2 + 1 WHERE f1 = 101; <para> The <literal>Planning time</literal> shown by <command>EXPLAIN - ANALYZE</command> is the time it took to generate the query plan from the + EXEC</command> is the time it took to generate the query plan from the parsed query and optimize it. It does not include parsing or rewriting. </para> <para> The <literal>Execution time</literal> shown by <command>EXPLAIN - ANALYZE</command> includes executor start-up and shut-down time, as well + EXEC</command> includes executor start-up and shut-down time, as well as the time to run any triggers that are fired, but it does not include parsing, rewriting, or planning time. Time spent executing <literal>BEFORE</literal> triggers, if any, is included in @@ -812,7 +812,7 @@ EXPLAIN UPDATE parent SET f2 = f2 + 1 WHERE f1 = 101; (either <literal>BEFORE</literal> or <literal>AFTER</literal>) is also shown separately. Note that deferred constraint triggers will not be executed until end of transaction and are thus not considered at all by - <command>EXPLAIN ANALYZE</command>. + <command>EXPLAIN EXEC</command>. </para> </sect2> @@ -822,11 +822,11 @@ EXPLAIN UPDATE parent SET f2 = f2 + 1 WHERE f1 = 101; <para> There are two significant ways in which run times measured by - <command>EXPLAIN ANALYZE</command> can deviate from normal execution of + <command>EXPLAIN EXEC</command> can deviate from normal execution of the same query. First, since no output rows are delivered to the client, network transmission costs and I/O conversion costs are not included. Second, the measurement overhead added by <command>EXPLAIN - ANALYZE</command> can be significant, especially on machines with slow + EXEC</command> can be significant, especially on machines with slow <function>gettimeofday()</function> operating-system calls. You can use the <xref linkend="pgtesttiming"/> tool to measure the overhead of timing on your system. @@ -853,7 +853,7 @@ EXPLAIN UPDATE parent SET f2 = f2 + 1 WHERE f1 = 101; effect. For example, in the <literal>LIMIT</literal> query we used before, <screen> -EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000 LIMIT 2; +EXPLAIN EXEC SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000 LIMIT 2; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- @@ -883,7 +883,7 @@ EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000 of one child, with results like those mentioned for <literal>LIMIT</literal>. Also, if the outer (first) child contains rows with duplicate key values, the inner (second) child is backed up and rescanned for the portion of its - rows matching that key value. <command>EXPLAIN ANALYZE</command> counts these + rows matching that key value. <command>EXPLAIN EXEC</command> counts these repeated emissions of the same inner rows as if they were real additional rows. When there are many outer duplicates, the reported actual row count for the inner child plan node can be significantly larger than the number diff --git a/doc/src/sgml/planstats.sgml b/doc/src/sgml/planstats.sgml index 4b1d3f4952..3a4405c850 100644 --- a/doc/src/sgml/planstats.sgml +++ b/doc/src/sgml/planstats.sgml @@ -489,7 +489,7 @@ SELECT relpages, reltuples FROM pg_class WHERE relname = 't'; condition on the <structfield>a</structfield> column: <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a = 1; QUERY PLAN ------------------------------------------------------------------------------- Seq Scan on t (cost=0.00..170.00 rows=100 width=8) (actual rows=100 loops=1) @@ -506,7 +506,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1; condition on both columns, combining them with <literal>AND</literal>: <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; QUERY PLAN ----------------------------------------------------------------------------- Seq Scan on t (cost=0.00..195.00 rows=1 width=8) (actual rows=100 loops=1) @@ -530,7 +530,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; <programlisting> CREATE STATISTICS stts (dependencies) ON a, b FROM t; ANALYZE t; -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; QUERY PLAN ------------------------------------------------------------------------------- Seq Scan on t (cost=0.00..195.00 rows=100 width=8) (actual rows=100 loops=1) @@ -551,7 +551,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; estimated number of rows returned by the HashAggregate node) is very accurate: <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a; +EXPLAIN (EXEC, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a; QUERY PLAN ----------------------------------------------------------------------------------------- HashAggregate (cost=195.00..196.00 rows=100 width=12) (actual rows=100 loops=1) @@ -562,7 +562,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a; groups in a query with two columns in <command>GROUP BY</command>, as in the following example, is off by an order of magnitude: <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; +EXPLAIN (EXEC, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; QUERY PLAN -------------------------------------------------------------------------------------------- HashAggregate (cost=220.00..230.00 rows=1000 width=16) (actual rows=100 loops=1) @@ -575,7 +575,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; DROP STATISTICS stts; CREATE STATISTICS stts (dependencies, ndistinct) ON a, b FROM t; ANALYZE t; -EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; +EXPLAIN (EXEC, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; QUERY PLAN -------------------------------------------------------------------------------------------- HashAggregate (cost=220.00..221.00 rows=100 width=16) (actual rows=100 loops=1) @@ -615,7 +615,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; DROP STATISTICS stts; CREATE STATISTICS stts2 (mcv) ON a, b FROM t; ANALYZE t; -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; QUERY PLAN ------------------------------------------------------------------------------- Seq Scan on t (cost=0.00..195.00 rows=100 width=8) (actual rows=100 loops=1) @@ -672,7 +672,7 @@ SELECT m.* FROM pg_statistic_ext, to decide which combinations are compatible. <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 10; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 10; QUERY PLAN --------------------------------------------------------------------------- Seq Scan on t (cost=0.00..195.00 rows=1 width=8) (actual rows=0 loops=1) @@ -685,7 +685,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 10; example range query, presented earlier: <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a &lt;= 49 AND b &gt; 49; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a &lt;= 49 AND b &gt; 49; QUERY PLAN --------------------------------------------------------------------------- Seq Scan on t (cost=0.00..195.00 rows=1 width=8) (actual rows=0 loops=1) diff --git a/doc/src/sgml/ref/create_statistics.sgml b/doc/src/sgml/ref/create_statistics.sgml index ae1d8024a4..18ca19fa8f 100644 --- a/doc/src/sgml/ref/create_statistics.sgml +++ b/doc/src/sgml/ref/create_statistics.sgml @@ -147,14 +147,14 @@ INSERT INTO t1 SELECT i/100, i/500 ANALYZE t1; -- the number of matching rows will be drastically underestimated: -EXPLAIN ANALYZE SELECT * FROM t1 WHERE (a = 1) AND (b = 0); +EXPLAIN EXEC SELECT * FROM t1 WHERE (a = 1) AND (b = 0); CREATE STATISTICS s1 (dependencies) ON a, b FROM t1; ANALYZE t1; -- now the row count estimate is more accurate: -EXPLAIN ANALYZE SELECT * FROM t1 WHERE (a = 1) AND (b = 0); +EXPLAIN EXEC SELECT * FROM t1 WHERE (a = 1) AND (b = 0); </programlisting> Without functional-dependency statistics, the planner would assume @@ -183,10 +183,10 @@ CREATE STATISTICS s2 (mcv) ON (a, b) FROM t2; ANALYZE t2; -- valid combination (found in MCV) -EXPLAIN ANALYZE SELECT * FROM t2 WHERE (a = 1) AND (b = 1); +EXPLAIN EXEC SELECT * FROM t2 WHERE (a = 1) AND (b = 1); -- invalid combination (not found in MCV) -EXPLAIN ANALYZE SELECT * FROM t2 WHERE (a = 1) AND (b = 2); +EXPLAIN EXEC SELECT * FROM t2 WHERE (a = 1) AND (b = 2); </programlisting> The MCV list gives the planner more detailed information about the diff --git a/doc/src/sgml/ref/pgtesttiming.sgml b/doc/src/sgml/ref/pgtesttiming.sgml index 545a934cf8..4470435dd2 100644 --- a/doc/src/sgml/ref/pgtesttiming.sgml +++ b/doc/src/sgml/ref/pgtesttiming.sgml @@ -30,7 +30,7 @@ <application>pg_test_timing</application> is a tool to measure the timing overhead on your system and confirm that the system time never moves backwards. Systems that are slow to collect timing data can give less accurate - <command>EXPLAIN ANALYZE</command> results. + <command>EXPLAIN EXEC</command> results. </para> </refsect1> @@ -120,7 +120,7 @@ Histogram of timing durations: <para> When the query executor is running a statement using - <command>EXPLAIN ANALYZE</command>, individual operations are timed as well + <command>EXPLAIN EXEC</command>, individual operations are timed as well as showing a summary. The overhead of your system can be checked by counting rows with the <application>psql</application> program: @@ -128,13 +128,13 @@ Histogram of timing durations: CREATE TABLE t AS SELECT * FROM generate_series(1,100000); \timing SELECT COUNT(*) FROM t; -EXPLAIN ANALYZE SELECT COUNT(*) FROM t; +EXPLAIN EXEC SELECT COUNT(*) FROM t; </screen> </para> <para> The i7-860 system measured runs the count query in 9.8 ms while - the <command>EXPLAIN ANALYZE</command> version takes 16.6 ms, each + the <command>EXPLAIN EXEC</command> version takes 16.6 ms, each processing just over 100,000 rows. That 6.8 ms difference means the timing overhead per row is 68 ns, about twice what pg_test_timing estimated it would be. Even that relatively small amount of overhead is making the fully @@ -169,12 +169,12 @@ Histogram of timing durations: </para> <para> - In this configuration, the sample <command>EXPLAIN ANALYZE</command> above + In this configuration, the sample <command>EXPLAIN EXEC</command> above takes 115.9 ms. That's 1061 ns of timing overhead, again a small multiple of what's measured directly by this utility. That much timing overhead means the actual query itself is only taking a tiny fraction of the accounted for time, most of it is being consumed in overhead instead. In - this configuration, any <command>EXPLAIN ANALYZE</command> totals involving + this configuration, any <command>EXPLAIN EXEC</command> totals involving many timed operations would be inflated significantly by timing overhead. </para> diff --git a/doc/src/sgml/ref/set_transaction.sgml b/doc/src/sgml/ref/set_transaction.sgml index 43b1c6c892..cef790ecd7 100644 --- a/doc/src/sgml/ref/set_transaction.sgml +++ b/doc/src/sgml/ref/set_transaction.sgml @@ -133,7 +133,7 @@ SET SESSION CHARACTERISTICS AS TRANSACTION <replaceable class="parameter">transa <literal>CREATE</literal>, <literal>ALTER</literal>, and <literal>DROP</literal> commands; <literal>COMMENT</literal>, <literal>GRANT</literal>, <literal>REVOKE</literal>, - <literal>TRUNCATE</literal>; and <literal>EXPLAIN ANALYZE</literal> + <literal>TRUNCATE</literal>; and <literal>EXPLAIN EXEC</literal> and <literal>EXECUTE</literal> if the command they would execute is among those listed. This is a high-level notion of read-only that does not prevent all writes to disk. diff --git a/doc/src/sgml/rules.sgml b/doc/src/sgml/rules.sgml index 4e20664ea1..499e6fcced 100644 --- a/doc/src/sgml/rules.sgml +++ b/doc/src/sgml/rules.sgml @@ -1030,7 +1030,7 @@ SELECT count(*) FROM words WHERE word = 'caterpiler'; (1 row) </programlisting> - With <command>EXPLAIN ANALYZE</command>, we see: + With <command>EXPLAIN EXEC</command>, we see: <programlisting> Aggregate (cost=21763.99..21764.00 rows=1 width=0) (actual time=188.180..188.181 rows=1 loops=1) diff --git a/src/test/regress/expected/join_hash.out b/src/test/regress/expected/join_hash.out index 9eee39bdd3..89000f9156 100644 --- a/src/test/regress/expected/join_hash.out +++ b/src/test/regress/expected/join_hash.out @@ -4,7 +4,7 @@ begin; set local min_parallel_table_scan_size = 0; set local parallel_setup_cost = 0; --- Extract bucket and batch counts from an explain analyze plan. In +-- Extract bucket and batch counts from an explain exec plan. In -- general we can't make assertions about how many batches (or -- buckets) will be required because it can vary, but we can in some -- special cases and we can check for growth. @@ -39,7 +39,7 @@ declare hash_node json; begin for whole_plan in - execute 'explain (analyze, format ''json'') ' || query + execute 'explain (exec, format ''json'') ' || query loop hash_node := find_hash(json_extract_path(whole_plan, '0', 'Plan')); original := hash_node->>'Original Hash Batches'; @@ -518,7 +518,7 @@ $$); rollback to settings; -- A couple of other hash join tests unrelated to work_mem management. --- Check that EXPLAIN ANALYZE has data even if the leader doesn't participate +-- Check that EXPLAIN EXEC has data even if the leader doesn't participate savepoint settings; set local max_parallel_workers_per_gather = 2; set local work_mem = '4MB'; diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index bd64bed8fc..ad5eeea7b4 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -1623,7 +1623,7 @@ create table ab_a3_b1 partition of ab_a3 for values in (1); create table ab_a3_b2 partition of ab_a3 for values in (2); create table ab_a3_b3 partition of ab_a3 for values in (3); -- Disallow index only scans as concurrent transactions may stop visibility --- bits being set causing "Heap Fetches" to be unstable in the EXPLAIN ANALYZE +-- bits being set causing "Heap Fetches" to be unstable in the EXPLAIN EXEC -- output. set enable_indexonlyscan = off; prepare ab_q1 (int, int, int) as @@ -1655,7 +1655,7 @@ execute ab_q1 (1, 8, 3); ---+--- (0 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2, 3); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 2, 3); QUERY PLAN --------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1668,7 +1668,7 @@ explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2, 3); Filter: ((a >= $1) AND (a <= $2) AND (b <= $3)) (8 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q1 (1, 2, 3); +explain (exec, costs off, summary off, timing off) execute ab_q1 (1, 2, 3); QUERY PLAN --------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1718,7 +1718,7 @@ execute ab_q1 (1, 8); --- (0 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 2); QUERY PLAN ------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1729,7 +1729,7 @@ explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2); Filter: ((a >= $1) AND (a <= $2) AND (b < 3)) (6 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 4); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 4); QUERY PLAN ------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1773,7 +1773,7 @@ execute ab_q2 (1, 8); --- (0 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q2 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q2 (2, 2); QUERY PLAN -------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1816,7 +1816,7 @@ execute ab_q3 (1, 8); --- (0 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q3 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q3 (2, 2); QUERY PLAN -------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1857,7 +1857,7 @@ begin; -- Test run-time pruning using stable functions create function list_part_fn(int) returns int as $$ begin return $1; end;$$ language plpgsql stable; -- Ensure pruning works using a stable function containing no Vars -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1); +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1); QUERY PLAN ------------------------------------------------------ Append (actual rows=1 loops=1) @@ -1867,7 +1867,7 @@ explain (analyze, costs off, summary off, timing off) select * from list_part wh (4 rows) -- Ensure pruning does not take place when the function has a Var parameter -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(a); +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(a); QUERY PLAN ------------------------------------------------------ Append (actual rows=4 loops=1) @@ -1882,7 +1882,7 @@ explain (analyze, costs off, summary off, timing off) select * from list_part wh (9 rows) -- Ensure pruning does not take place when the expression contains a Var. -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1) + a; +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1) + a; QUERY PLAN ------------------------------------------------------ Append (actual rows=0 loops=1) @@ -1913,7 +1913,7 @@ declare ln text; begin for ln in - execute format('explain (analyze, costs off, summary off, timing off) %s', + execute format('explain (exec, costs off, summary off, timing off) %s', $1) loop if ln like '%Parallel%' then @@ -2286,7 +2286,7 @@ reset parallel_tuple_cost; reset min_parallel_table_scan_size; reset max_parallel_workers_per_gather; -- Test run-time partition pruning with an initplan -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from ab where a = (select max(a) from lprt_a) and b = (select max(a)-1 from lprt_a); QUERY PLAN ------------------------------------------------------------------------- @@ -2345,7 +2345,7 @@ select * from ab where a = (select max(a) from lprt_a) and b = (select max(a)-1 (52 rows) -- Test run-time partition pruning with UNION ALL parents -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from (select * from ab where a = 1 union all select * from ab) ab where b = (select 1); QUERY PLAN ------------------------------------------------------------------------------- @@ -2389,7 +2389,7 @@ select * from (select * from ab where a = 1 union all select * from ab) ab where (37 rows) -- A case containing a UNION ALL with a non-partitioned child. -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from (select * from ab where a = 1 union all (values(10,5)) union all select * from ab) ab where b = (select 1); QUERY PLAN ------------------------------------------------------------------------------- @@ -2449,7 +2449,7 @@ union all select tableoid::regclass,a,b from ab ) ab where a = $1 and b = (select -10); -- Ensure the xy_1 subplan is not pruned. -explain (analyze, costs off, summary off, timing off) execute ab_q6(1); +explain (exec, costs off, summary off, timing off) execute ab_q6(1); QUERY PLAN -------------------------------------------------------- Append (actual rows=0 loops=1) @@ -2491,7 +2491,7 @@ deallocate ab_q5; deallocate ab_q6; -- UPDATE on a partition subtree has been seen to have problems. insert into ab values (1,2); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a; QUERY PLAN ------------------------------------------------------------------------------------- @@ -2571,7 +2571,7 @@ table ab; -- Test UPDATE where source relation has run-time pruning enabled truncate ab; insert into ab values (1, 1), (1, 2), (1, 3), (2, 1); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) update ab_a1 set b = 3 from ab_a2 where ab_a2.b = (select 1); QUERY PLAN ---------------------------------------------------------------------- @@ -2643,7 +2643,7 @@ create index tprt6_idx on tprt_6 (col1); insert into tprt values (10), (20), (501), (502), (505), (1001), (4500); set enable_hashjoin = off; set enable_mergejoin = off; -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 > tprt.col1; QUERY PLAN -------------------------------------------------------------------------- @@ -2664,7 +2664,7 @@ select * from tbl1 join tprt on tbl1.col1 > tprt.col1; Index Cond: (col1 < tbl1.col1) (15 rows) -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; QUERY PLAN -------------------------------------------------------------------------- @@ -2709,7 +2709,7 @@ order by tbl1.col1, tprt.col1; -- Multiple partitions insert into tbl1 values (1001), (1010), (1011); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 inner join tprt on tbl1.col1 > tprt.col1; QUERY PLAN -------------------------------------------------------------------------- @@ -2730,7 +2730,7 @@ select * from tbl1 inner join tprt on tbl1.col1 > tprt.col1; Index Cond: (col1 < tbl1.col1) (15 rows) -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 inner join tprt on tbl1.col1 = tprt.col1; QUERY PLAN -------------------------------------------------------------------------- @@ -2794,7 +2794,7 @@ order by tbl1.col1, tprt.col1; -- Last partition delete from tbl1; insert into tbl1 values (4400); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 < tprt.col1; QUERY PLAN -------------------------------------------------------------------------- @@ -2826,7 +2826,7 @@ order by tbl1.col1, tprt.col1; -- No matching partition delete from tbl1; insert into tbl1 values (10000); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; QUERY PLAN ------------------------------------------------------------------- @@ -2893,7 +2893,7 @@ execute part_abc_q1 (1, 2, 3); (0 rows) -- Single partition should be scanned. -explain (analyze, costs off, summary off, timing off) execute part_abc_q1 (1, 2, 3); +explain (exec, costs off, summary off, timing off) execute part_abc_q1 (1, 2, 3); QUERY PLAN ------------------------------------------------- Seq Scan on part_abc_p1 (actual rows=0 loops=1) @@ -2943,7 +2943,7 @@ execute q1 (1,2); ---+--- (0 rows) -explain (analyze, costs off, summary off, timing off) execute q1 (1,1); +explain (exec, costs off, summary off, timing off) execute q1 (1,1); QUERY PLAN ----------------------------------------------------- Append (actual rows=0 loops=1) @@ -2952,7 +2952,7 @@ explain (analyze, costs off, summary off, timing off) execute q1 (1,1); Filter: (b = ANY (ARRAY[$1, $2])) (4 rows) -explain (analyze, costs off, summary off, timing off) execute q1 (2,2); +explain (exec, costs off, summary off, timing off) execute q1 (2,2); QUERY PLAN ----------------------------------------------------- Append (actual rows=0 loops=1) @@ -2963,7 +2963,7 @@ explain (analyze, costs off, summary off, timing off) execute q1 (2,2); -- Try with no matching partitions. One subplan should remain in this case, -- but it shouldn't be executed. -explain (analyze, costs off, summary off, timing off) execute q1 (0,0); +explain (exec, costs off, summary off, timing off) execute q1 (0,0); QUERY PLAN ---------------------------------------------- Append (actual rows=0 loops=1) @@ -3001,7 +3001,7 @@ execute q1 (1,2,3,4); (0 rows) -- Both partitions allowed by IN clause, but one disallowed by <> clause -explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,0); +explain (exec, costs off, summary off, timing off) execute q1 (1,2,2,0); QUERY PLAN ------------------------------------------------------------------------- Append (actual rows=0 loops=1) @@ -3012,7 +3012,7 @@ explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,0); -- Both partitions allowed by IN clause, then both excluded again by <> clauses. -- One subplan will remain in this case, but it should not be executed. -explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,1); +explain (exec, costs off, summary off, timing off) execute q1 (1,2,2,1); QUERY PLAN ------------------------------------------------------------------------- Append (actual rows=0 loops=1) @@ -3022,7 +3022,7 @@ explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,1); (4 rows) -- Ensure Params that evaluate to NULL properly prune away all partitions -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from listp where a = (select null::int); QUERY PLAN ---------------------------------------------- @@ -3042,7 +3042,7 @@ insert into boolvalues values('t'),('f'); create table boolp (a bool) partition by list (a); create table boolp_t partition of boolp for values in('t'); create table boolp_f partition of boolp for values in('f'); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from boolp where a = (select value from boolvalues where value); QUERY PLAN -------------------------------------------------------- @@ -3057,7 +3057,7 @@ select * from boolp where a = (select value from boolvalues where value); Filter: (a = $0) (9 rows) -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from boolp where a = (select value from boolvalues where not value); QUERY PLAN -------------------------------------------------------- @@ -3128,7 +3128,7 @@ execute mt_q1(0); 25 (3 rows) -explain (analyze, costs off, summary off, timing off) execute mt_q1(15); +explain (exec, costs off, summary off, timing off) execute mt_q1(15); QUERY PLAN ------------------------------------------------------------------------------- Merge Append (actual rows=2 loops=1) @@ -3149,7 +3149,7 @@ execute mt_q1(15); 25 (2 rows) -explain (analyze, costs off, summary off, timing off) execute mt_q1(25); +explain (exec, costs off, summary off, timing off) execute mt_q1(25); QUERY PLAN ------------------------------------------------------------------------------- Merge Append (actual rows=1 loops=1) @@ -3167,7 +3167,7 @@ execute mt_q1(25); (1 row) -- Ensure MergeAppend behaves correctly when no subplans match -explain (analyze, costs off, summary off, timing off) execute mt_q1(35); +explain (exec, costs off, summary off, timing off) execute mt_q1(35); QUERY PLAN ------------------------------------------------------------------------ Merge Append (actual rows=0 loops=1) @@ -3184,7 +3184,7 @@ execute mt_q1(35); deallocate mt_q1; -- ensure initplan params properly prune partitions -explain (analyze, costs off, summary off, timing off) select * from ma_test where a >= (select min(b) from ma_test_p2) order by b; +explain (exec, costs off, summary off, timing off) select * from ma_test where a >= (select min(b) from ma_test_p2) order by b; QUERY PLAN ------------------------------------------------------------------------------------------------------------ Merge Append (actual rows=20 loops=1) @@ -3629,7 +3629,7 @@ create table listp (a int, b int) partition by list (a); create table listp1 partition of listp for values in(1); create table listp2 partition of listp for values in(2) partition by list(b); create table listp2_10 partition of listp2 for values in (10); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from listp where a = (select 2) and b <> 10; QUERY PLAN -------------------------------------------- diff --git a/src/test/regress/expected/select.out b/src/test/regress/expected/select.out index c441049f41..16ac7bdf43 100644 --- a/src/test/regress/expected/select.out +++ b/src/test/regress/expected/select.out @@ -753,7 +753,7 @@ select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; (1 row) -- actually run the query with an analyze to use the partial index -explain (costs off, analyze on, timing off, summary off) +explain (costs off, exec on, timing off, summary off) select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; QUERY PLAN ----------------------------------------------------------------- diff --git a/src/test/regress/expected/select_into.out b/src/test/regress/expected/select_into.out index f373fae679..5c0c1d7b88 100644 --- a/src/test/regress/expected/select_into.out +++ b/src/test/regress/expected/select_into.out @@ -112,12 +112,12 @@ SELECT * FROM created_table; 4567890123456789 | -4567890123456789 (5 rows) --- Try EXPLAIN ANALYZE SELECT INTO and EXPLAIN ANALYZE CREATE TABLE AS +-- Try EXPLAIN EXEC SELECT INTO and EXPLAIN EXEC CREATE TABLE AS -- WITH NO DATA, but hide the outputs since they won't be stable. DO $$ BEGIN - EXECUTE 'EXPLAIN ANALYZE SELECT * INTO TABLE easi FROM int8_tbl'; - EXECUTE 'EXPLAIN ANALYZE CREATE TABLE easi2 AS SELECT * FROM int8_tbl WITH NO DATA'; + EXECUTE 'EXPLAIN EXEC SELECT * INTO TABLE easi FROM int8_tbl'; + EXECUTE 'EXPLAIN EXEC CREATE TABLE easi2 AS SELECT * FROM int8_tbl WITH NO DATA'; END$$; DROP TABLE created_table; DROP TABLE easi, easi2; diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out index 0eca76cb41..c4c8f476ff 100644 --- a/src/test/regress/expected/select_parallel.out +++ b/src/test/regress/expected/select_parallel.out @@ -505,7 +505,7 @@ select count(*) from bmscantest where a>1; -- test accumulation of stats for parallel nodes reset enable_seqscan; alter table tenk2 set (parallel_workers = 0); -explain (analyze, timing off, summary off, costs off) +explain (exec, timing off, summary off, costs off) select count(*) from tenk1, tenk2 where tenk1.hundred > 1 and tenk2.thousand=0; QUERY PLAN @@ -531,7 +531,7 @@ $$ declare ln text; begin for ln in - explain (analyze, timing off, summary off, costs off) + explain (exec, timing off, summary off, costs off) select * from (select ten from tenk1 where ten < 100 order by ten) ss right join (values (1),(2),(3)) v(x) on true @@ -1006,7 +1006,7 @@ explain (costs off) -- to increase the parallel query test coverage SAVEPOINT settings; SET LOCAL force_parallel_mode = 1; -EXPLAIN (analyze, timing off, summary off, costs off) SELECT * FROM tenk1; +EXPLAIN (exec, timing off, summary off, costs off) SELECT * FROM tenk1; QUERY PLAN ------------------------------------------------------------- Gather (actual rows=10000 loops=1) diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out index 6dfca7a606..c30447fac2 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -12,7 +12,7 @@ declare first_row bool := true; begin for ln in - execute format('explain analyze %s', $1) + execute format('explain exec %s', $1) loop if first_row then first_row := false; diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out index 2d1963d12a..c1e8bec7a0 100644 --- a/src/test/regress/expected/subselect.out +++ b/src/test/regress/expected/subselect.out @@ -1120,8 +1120,8 @@ drop function tattle(x int, y int); -- -- Test that LIMIT can be pushed to SORT through a subquery that just projects -- columns. We check for that having happened by looking to see if EXPLAIN --- ANALYZE shows that a top-N sort was used. We must suppress or filter away --- all the non-invariant parts of the EXPLAIN ANALYZE output. +-- EXEC shows that a top-N sort was used. We must suppress or filter away +-- all the non-invariant parts of the EXPLAIN EXEC output. -- create table sq_limit (pk int primary key, c1 int, c2 int); insert into sq_limit values @@ -1138,7 +1138,7 @@ $$ declare ln text; begin for ln in - explain (analyze, summary off, timing off, costs off) + explain (exec, summary off, timing off, costs off) select * from (select pk,c2 from sq_limit order by c1,pk) as x limit 3 loop ln := regexp_replace(ln, 'Memory: \S*', 'Memory: xxx'); diff --git a/src/test/regress/expected/tidscan.out b/src/test/regress/expected/tidscan.out index 9b5eb04bfd..8e62c9b28b 100644 --- a/src/test/regress/expected/tidscan.out +++ b/src/test/regress/expected/tidscan.out @@ -189,7 +189,7 @@ FETCH NEXT FROM c; (1 row) -- perform update -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; QUERY PLAN --------------------------------------------------- @@ -205,7 +205,7 @@ FETCH NEXT FROM c; (1 row) -- perform update -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; QUERY PLAN --------------------------------------------------- @@ -229,7 +229,7 @@ FETCH NEXT FROM c; (0 rows) -- should error out -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; ERROR: cursor "c" is not positioned on a row ROLLBACK; diff --git a/src/test/regress/sql/join_hash.sql b/src/test/regress/sql/join_hash.sql index ae352e9b0b..b44d705d57 100644 --- a/src/test/regress/sql/join_hash.sql +++ b/src/test/regress/sql/join_hash.sql @@ -7,7 +7,7 @@ begin; set local min_parallel_table_scan_size = 0; set local parallel_setup_cost = 0; --- Extract bucket and batch counts from an explain analyze plan. In +-- Extract bucket and batch counts from an explain exec plan. In -- general we can't make assertions about how many batches (or -- buckets) will be required because it can vary, but we can in some -- special cases and we can check for growth. @@ -42,7 +42,7 @@ declare hash_node json; begin for whole_plan in - execute 'explain (analyze, format ''json'') ' || query + execute 'explain (exec, format ''json'') ' || query loop hash_node := find_hash(json_extract_path(whole_plan, '0', 'Plan')); original := hash_node->>'Original Hash Batches'; @@ -280,7 +280,7 @@ rollback to settings; -- A couple of other hash join tests unrelated to work_mem management. --- Check that EXPLAIN ANALYZE has data even if the leader doesn't participate +-- Check that EXPLAIN EXEC has data even if the leader doesn't participate savepoint settings; set local max_parallel_workers_per_gather = 2; set local work_mem = '4MB'; diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql index 246c6274af..684aa3c464 100644 --- a/src/test/regress/sql/partition_prune.sql +++ b/src/test/regress/sql/partition_prune.sql @@ -327,7 +327,7 @@ create table ab_a3_b2 partition of ab_a3 for values in (2); create table ab_a3_b3 partition of ab_a3 for values in (3); -- Disallow index only scans as concurrent transactions may stop visibility --- bits being set causing "Heap Fetches" to be unstable in the EXPLAIN ANALYZE +-- bits being set causing "Heap Fetches" to be unstable in the EXPLAIN EXEC -- output. set enable_indexonlyscan = off; @@ -342,8 +342,8 @@ execute ab_q1 (1, 8, 3); execute ab_q1 (1, 8, 3); execute ab_q1 (1, 8, 3); -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2, 3); -explain (analyze, costs off, summary off, timing off) execute ab_q1 (1, 2, 3); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 2, 3); +explain (exec, costs off, summary off, timing off) execute ab_q1 (1, 2, 3); deallocate ab_q1; @@ -359,8 +359,8 @@ execute ab_q1 (1, 8); execute ab_q1 (1, 8); execute ab_q1 (1, 8); -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2); -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 4); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 4); -- Ensure a mix of PARAM_EXTERN and PARAM_EXEC Params work together at -- different levels of partitioning. @@ -373,7 +373,7 @@ execute ab_q2 (1, 8); execute ab_q2 (1, 8); execute ab_q2 (1, 8); -explain (analyze, costs off, summary off, timing off) execute ab_q2 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q2 (2, 2); -- As above, but swap the PARAM_EXEC Param to the first partition level prepare ab_q3 (int, int) as @@ -385,7 +385,7 @@ execute ab_q3 (1, 8); execute ab_q3 (1, 8); execute ab_q3 (1, 8); -explain (analyze, costs off, summary off, timing off) execute ab_q3 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q3 (2, 2); -- Test a backwards Append scan create table list_part (a int) partition by list (a); @@ -416,13 +416,13 @@ begin; create function list_part_fn(int) returns int as $$ begin return $1; end;$$ language plpgsql stable; -- Ensure pruning works using a stable function containing no Vars -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1); +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1); -- Ensure pruning does not take place when the function has a Var parameter -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(a); +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(a); -- Ensure pruning does not take place when the expression contains a Var. -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1) + a; +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1) + a; rollback; @@ -440,7 +440,7 @@ declare ln text; begin for ln in - execute format('explain (analyze, costs off, summary off, timing off) %s', + execute format('explain (exec, costs off, summary off, timing off) %s', $1) loop if ln like '%Parallel%' then @@ -537,15 +537,15 @@ reset min_parallel_table_scan_size; reset max_parallel_workers_per_gather; -- Test run-time partition pruning with an initplan -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from ab where a = (select max(a) from lprt_a) and b = (select max(a)-1 from lprt_a); -- Test run-time partition pruning with UNION ALL parents -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from (select * from ab where a = 1 union all select * from ab) ab where b = (select 1); -- A case containing a UNION ALL with a non-partitioned child. -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from (select * from ab where a = 1 union all (values(10,5)) union all select * from ab) ab where b = (select 1); -- Another UNION ALL test, but containing a mix of exec init and exec run-time pruning. @@ -566,7 +566,7 @@ union all ) ab where a = $1 and b = (select -10); -- Ensure the xy_1 subplan is not pruned. -explain (analyze, costs off, summary off, timing off) execute ab_q6(1); +explain (exec, costs off, summary off, timing off) execute ab_q6(1); -- Ensure we see just the xy_1 row. execute ab_q6(100); @@ -584,14 +584,14 @@ deallocate ab_q6; -- UPDATE on a partition subtree has been seen to have problems. insert into ab values (1,2); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a; table ab; -- Test UPDATE where source relation has run-time pruning enabled truncate ab; insert into ab values (1, 1), (1, 2), (1, 3), (2, 1); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) update ab_a1 set b = 3 from ab_a2 where ab_a2.b = (select 1); select tableoid::regclass, * from ab; @@ -622,10 +622,10 @@ insert into tprt values (10), (20), (501), (502), (505), (1001), (4500); set enable_hashjoin = off; set enable_mergejoin = off; -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 > tprt.col1; -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -638,10 +638,10 @@ order by tbl1.col1, tprt.col1; -- Multiple partitions insert into tbl1 values (1001), (1010), (1011); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 inner join tprt on tbl1.col1 > tprt.col1; -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 inner join tprt on tbl1.col1 = tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -655,7 +655,7 @@ order by tbl1.col1, tprt.col1; -- Last partition delete from tbl1; insert into tbl1 values (4400); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 < tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -665,7 +665,7 @@ order by tbl1.col1, tprt.col1; -- No matching partition delete from tbl1; insert into tbl1 values (10000); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -696,7 +696,7 @@ execute part_abc_q1 (1, 2, 3); execute part_abc_q1 (1, 2, 3); -- Single partition should be scanned. -explain (analyze, costs off, summary off, timing off) execute part_abc_q1 (1, 2, 3); +explain (exec, costs off, summary off, timing off) execute part_abc_q1 (1, 2, 3); deallocate part_abc_q1; @@ -722,13 +722,13 @@ execute q1 (1,2); execute q1 (1,2); execute q1 (1,2); -explain (analyze, costs off, summary off, timing off) execute q1 (1,1); +explain (exec, costs off, summary off, timing off) execute q1 (1,1); -explain (analyze, costs off, summary off, timing off) execute q1 (2,2); +explain (exec, costs off, summary off, timing off) execute q1 (2,2); -- Try with no matching partitions. One subplan should remain in this case, -- but it shouldn't be executed. -explain (analyze, costs off, summary off, timing off) execute q1 (0,0); +explain (exec, costs off, summary off, timing off) execute q1 (0,0); deallocate q1; @@ -742,14 +742,14 @@ execute q1 (1,2,3,4); execute q1 (1,2,3,4); -- Both partitions allowed by IN clause, but one disallowed by <> clause -explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,0); +explain (exec, costs off, summary off, timing off) execute q1 (1,2,2,0); -- Both partitions allowed by IN clause, then both excluded again by <> clauses. -- One subplan will remain in this case, but it should not be executed. -explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,1); +explain (exec, costs off, summary off, timing off) execute q1 (1,2,2,1); -- Ensure Params that evaluate to NULL properly prune away all partitions -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from listp where a = (select null::int); drop table listp; @@ -762,10 +762,10 @@ create table boolp (a bool) partition by list (a); create table boolp_t partition of boolp for values in('t'); create table boolp_f partition of boolp for values in('f'); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from boolp where a = (select value from boolvalues where value); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from boolp where a = (select value from boolvalues where not value); drop table boolp; @@ -793,18 +793,18 @@ execute mt_q1(0); execute mt_q1(0); execute mt_q1(0); -explain (analyze, costs off, summary off, timing off) execute mt_q1(15); +explain (exec, costs off, summary off, timing off) execute mt_q1(15); execute mt_q1(15); -explain (analyze, costs off, summary off, timing off) execute mt_q1(25); +explain (exec, costs off, summary off, timing off) execute mt_q1(25); execute mt_q1(25); -- Ensure MergeAppend behaves correctly when no subplans match -explain (analyze, costs off, summary off, timing off) execute mt_q1(35); +explain (exec, costs off, summary off, timing off) execute mt_q1(35); execute mt_q1(35); deallocate mt_q1; -- ensure initplan params properly prune partitions -explain (analyze, costs off, summary off, timing off) select * from ma_test where a >= (select min(b) from ma_test_p2) order by b; +explain (exec, costs off, summary off, timing off) select * from ma_test where a >= (select min(b) from ma_test_p2) order by b; reset enable_seqscan; reset enable_sort; @@ -987,7 +987,7 @@ create table listp1 partition of listp for values in(1); create table listp2 partition of listp for values in(2) partition by list(b); create table listp2_10 partition of listp2 for values in (10); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from listp where a = (select 2) and b <> 10; -- diff --git a/src/test/regress/sql/select.sql b/src/test/regress/sql/select.sql index b5929b2eca..f573dfa921 100644 --- a/src/test/regress/sql/select.sql +++ b/src/test/regress/sql/select.sql @@ -196,7 +196,7 @@ explain (costs off) select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; -- actually run the query with an analyze to use the partial index -explain (costs off, analyze on, timing off, summary off) +explain (costs off, exec on, timing off, summary off) select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; explain (costs off) select unique2 from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; diff --git a/src/test/regress/sql/select_into.sql b/src/test/regress/sql/select_into.sql index a708fef0ea..bd2f918294 100644 --- a/src/test/regress/sql/select_into.sql +++ b/src/test/regress/sql/select_into.sql @@ -85,12 +85,12 @@ SELECT make_table(); SELECT * FROM created_table; --- Try EXPLAIN ANALYZE SELECT INTO and EXPLAIN ANALYZE CREATE TABLE AS +-- Try EXPLAIN EXEC SELECT INTO and EXPLAIN EXEC CREATE TABLE AS -- WITH NO DATA, but hide the outputs since they won't be stable. DO $$ BEGIN - EXECUTE 'EXPLAIN ANALYZE SELECT * INTO TABLE easi FROM int8_tbl'; - EXECUTE 'EXPLAIN ANALYZE CREATE TABLE easi2 AS SELECT * FROM int8_tbl WITH NO DATA'; + EXECUTE 'EXPLAIN EXEC SELECT * INTO TABLE easi FROM int8_tbl'; + EXECUTE 'EXPLAIN EXEC CREATE TABLE easi2 AS SELECT * FROM int8_tbl WITH NO DATA'; END$$; DROP TABLE created_table; diff --git a/src/test/regress/sql/select_parallel.sql b/src/test/regress/sql/select_parallel.sql index 03c056b8b7..de8ef80ecf 100644 --- a/src/test/regress/sql/select_parallel.sql +++ b/src/test/regress/sql/select_parallel.sql @@ -197,7 +197,7 @@ select count(*) from bmscantest where a>1; -- test accumulation of stats for parallel nodes reset enable_seqscan; alter table tenk2 set (parallel_workers = 0); -explain (analyze, timing off, summary off, costs off) +explain (exec, timing off, summary off, costs off) select count(*) from tenk1, tenk2 where tenk1.hundred > 1 and tenk2.thousand=0; alter table tenk2 reset (parallel_workers); @@ -209,7 +209,7 @@ $$ declare ln text; begin for ln in - explain (analyze, timing off, summary off, costs off) + explain (exec, timing off, summary off, costs off) select * from (select ten from tenk1 where ten < 100 order by ten) ss right join (values (1),(2),(3)) v(x) on true @@ -376,7 +376,7 @@ explain (costs off) -- to increase the parallel query test coverage SAVEPOINT settings; SET LOCAL force_parallel_mode = 1; -EXPLAIN (analyze, timing off, summary off, costs off) SELECT * FROM tenk1; +EXPLAIN (exec, timing off, summary off, costs off) SELECT * FROM tenk1; ROLLBACK TO SAVEPOINT settings; -- provoke error in worker diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql index c6a5776120..6492cd7c37 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -14,7 +14,7 @@ declare first_row bool := true; begin for ln in - execute format('explain analyze %s', $1) + execute format('explain exec %s', $1) loop if first_row then first_row := false; diff --git a/src/test/regress/sql/subselect.sql b/src/test/regress/sql/subselect.sql index 99ca69791e..b1d89228d2 100644 --- a/src/test/regress/sql/subselect.sql +++ b/src/test/regress/sql/subselect.sql @@ -598,8 +598,8 @@ drop function tattle(x int, y int); -- -- Test that LIMIT can be pushed to SORT through a subquery that just projects -- columns. We check for that having happened by looking to see if EXPLAIN --- ANALYZE shows that a top-N sort was used. We must suppress or filter away --- all the non-invariant parts of the EXPLAIN ANALYZE output. +-- EXEC shows that a top-N sort was used. We must suppress or filter away +-- all the non-invariant parts of the EXPLAIN EXEC output. -- create table sq_limit (pk int primary key, c1 int, c2 int); insert into sq_limit values @@ -617,7 +617,7 @@ $$ declare ln text; begin for ln in - explain (analyze, summary off, timing off, costs off) + explain (exec, summary off, timing off, costs off) select * from (select pk,c2 from sq_limit order by c1,pk) as x limit 3 loop ln := regexp_replace(ln, 'Memory: \S*', 'Memory: xxx'); diff --git a/src/test/regress/sql/tidscan.sql b/src/test/regress/sql/tidscan.sql index ef05c09842..65e222681e 100644 --- a/src/test/regress/sql/tidscan.sql +++ b/src/test/regress/sql/tidscan.sql @@ -68,17 +68,17 @@ DECLARE c CURSOR FOR SELECT ctid, * FROM tidscan; FETCH NEXT FROM c; -- skip one row FETCH NEXT FROM c; -- perform update -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; FETCH NEXT FROM c; -- perform update -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; SELECT * FROM tidscan; -- position cursor past any rows FETCH NEXT FROM c; -- should error out -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; ROLLBACK; --------------2.21.0--
^ permalink raw reply [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-15 06:02  David Fetter <david@fetter.org>
  parent: David Fetter <david@fetter.org>
  1 sibling, 1 reply; 49+ messages in thread

From: David Fetter @ 2019-05-15 06:02 UTC (permalink / raw)
  To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Stephen Frost <sfrost@snowman.net>; Andres Freund <andres@anarazel.de>; pgsql-hackers

On Mon, May 13, 2019 at 07:51:12AM +0200, David Fetter wrote:
> On Tue, May 07, 2019 at 06:25:12PM -0400, Tom Lane wrote:
> > Stephen Frost <sfrost@snowman.net> writes:
> > > I'm generally in favor of doing something like what Tom is suggesting
> > > with VERBOSE, but I also feel like it should be the default for formats
> > > like JSON.  If you're asking for the output in JSON, then we really
> > > should include everything that a flag like VERBOSE would contain because
> > > you're pretty clearly planning to copy/paste that output into something
> > > else to read it anyway.
> > 
> > Meh --- I don't especially care for non-orthogonal behaviors like that.
> > If you wanted JSON but *not* all of the additional info, how would you
> > specify that?  (The implementation I had in mind would make VERBOSE OFF
> > more or less a no-op, so that wouldn't get you there.)
> > 
> > >> I do feel that it's a good idea to keep ANALYZE separate. "Execute
> > >> the query or not" is a mighty fundamental thing.  I've never liked
> > >> that name for the option though --- maybe we could deprecate it
> > >> in favor of EXECUTE?
> > 
> > > Let's not fool ourselves by saying we'd 'deprecate' it because that
> > > implies, at least to me, that there's some intention of later on
> > > removing it
> > 
> > True, the odds of ever actually removing it are small :-(.  I meant
> > mostly changing all of our docs to use the other spelling, except
> > for some footnote.  Maybe we could call ANALYZE a "legacy spelling"
> > of EXECUTE.
> 
> I tried changing it to EXEC (EXPLAIN EXECUTE is already a thing), but
> got a giant flock of reduce-reduce conflicts along with a few
> shift-reduce conflicts.
> 
> How do I fix this?

Fixed it.

I hope the patch is a little easier to digest as now attached.

Best,
David.
-- 
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate

Attachments: download all (8 files, .tar.gz)

v4-0001-Changed-EXPLAIN-ANALYZE-to-EXPLAIN-EXEC.patch (text/x-diff, 12.2K) download From 92cb3f5da4157085933ea5c6dcb6f560fad66626 Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Tue, 14 May 2019 22:46:44 -0700 Subject: [PATCH v4 1/8] Changed EXPLAIN ANALYZE to EXPLAIN EXEC To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit - In passing, made some of the defaults for EXPLAIN more helpful diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index a6c6de78f1..95e8f20e5d 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -147,6 +147,7 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, TupOutputState *tstate; List *rewritten; ListCell *lc; + bool buffers_set = false; bool timing_set = false; bool summary_set = false; @@ -155,14 +156,17 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, { DefElem *opt = (DefElem *) lfirst(lc); - if (strcmp(opt->defname, "analyze") == 0) - es->analyze = defGetBoolean(opt); + if (strcmp(opt->defname, "exec") == 0) + es->exec = defGetBoolean(opt); else if (strcmp(opt->defname, "verbose") == 0) es->verbose = defGetBoolean(opt); else if (strcmp(opt->defname, "costs") == 0) es->costs = defGetBoolean(opt); else if (strcmp(opt->defname, "buffers") == 0) + { + buffers_set = true; es->buffers = defGetBoolean(opt); + } else if (strcmp(opt->defname, "settings") == 0) es->settings = defGetBoolean(opt); else if (strcmp(opt->defname, "timing") == 0) @@ -202,22 +206,21 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, parser_errposition(pstate, opt->location))); } - if (es->buffers && !es->analyze) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("EXPLAIN option BUFFERS requires ANALYZE"))); + /* Turn buffers off automatically when exec isn't set */ + if (!es->exec) + es->buffers = false; /* if the timing was not set explicitly, set default value */ - es->timing = (timing_set) ? es->timing : es->analyze; + es->timing = (timing_set) ? es->timing : es->exec; - /* check that timing is used with EXPLAIN ANALYZE */ - if (es->timing && !es->analyze) + /* check that timing is used with EXPLAIN EXEC */ + if (es->timing && !es->exec) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("EXPLAIN option TIMING requires ANALYZE"))); + errmsg("EXPLAIN option TIMING requires EXEC"))); /* if the summary was not set explicitly, set default value */ - es->summary = (summary_set) ? es->summary : es->analyze; + es->summary = (summary_set) ? es->summary : es->exec; /* * Parse analysis was done already, but we still have to run the rule @@ -286,8 +289,11 @@ NewExplainState(void) { ExplainState *es = (ExplainState *) palloc0(sizeof(ExplainState)); - /* Set default options (most fields can be left as zeroes). */ + /* Set default options (fields can be left as zeroes). */ es->costs = true; + es->buffers = true; + es->settings = true; + es->timing = true; /* Prepare output buffer. */ es->str = makeStringInfo(); @@ -415,7 +421,7 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, /* * Likewise for DECLARE CURSOR. * - * Notice that if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll + * Notice that if you say EXPLAIN EXEC DECLARE CURSOR then we'll * actually run the query. This is different from pre-8.3 behavior * but seems more useful than not running the query. No cursor will * be created, however. @@ -475,9 +481,9 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, Assert(plannedstmt->commandType != CMD_UTILITY); - if (es->analyze && es->timing) + if (es->exec && es->timing) instrument_option |= INSTRUMENT_TIMER; - else if (es->analyze) + else if (es->exec) instrument_option |= INSTRUMENT_ROWS; if (es->buffers) @@ -512,7 +518,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, dest, params, queryEnv, instrument_option); /* Select execution options */ - if (es->analyze) + if (es->exec) eflags = 0; /* default run-to-completion flags */ else eflags = EXEC_FLAG_EXPLAIN_ONLY; @@ -523,11 +529,11 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, ExecutorStart(queryDesc, eflags); /* Execute the plan for statistics if asked for */ - if (es->analyze) + if (es->exec) { ScanDirection dir; - /* EXPLAIN ANALYZE CREATE TABLE AS WITH NO DATA is weird */ + /* EXPLAIN EXEC CREATE TABLE AS WITH NO DATA is weird */ if (into && into->skipData) dir = NoMovementScanDirection; else @@ -556,7 +562,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, } /* Print info about runtime of triggers */ - if (es->analyze) + if (es->exec) ExplainPrintTriggers(es, queryDesc); /* @@ -581,7 +587,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, PopActiveSnapshot(); /* We need a CCI just in case query expanded to multiple plans */ - if (es->analyze) + if (es->exec) CommandCounterIncrement(); totaltime += elapsed_time(&starttime); @@ -592,7 +598,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, * user can set SUMMARY OFF to not have the timing information included in * the output). By default, ANALYZE sets SUMMARY to true. */ - if (es->summary && es->analyze) + if (es->summary && es->exec) ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3, es); @@ -834,7 +840,7 @@ ExplainPrintJIT(ExplainState *es, int jit_flags, "Expressions", jit_flags & PGJIT_EXPR ? "true" : "false", "Deforming", jit_flags & PGJIT_DEFORM ? "true" : "false"); - if (es->analyze && es->timing) + if (es->exec && es->timing) { appendStringInfoSpaces(es->str, es->indent * 2); appendStringInfo(es->str, @@ -860,7 +866,7 @@ ExplainPrintJIT(ExplainState *es, int jit_flags, ExplainPropertyBool("Deforming", jit_flags & PGJIT_DEFORM, es); ExplainCloseGroup("Options", "Options", true, es); - if (es->analyze && es->timing) + if (es->exec && es->timing) { ExplainOpenGroup("Timing", "Timing", true, es); @@ -1505,7 +1511,7 @@ ExplainNode(PlanState *planstate, List *ancestors, if (planstate->instrument) InstrEndLoop(planstate->instrument); - if (es->analyze && + if (es->exec && planstate->instrument && planstate->instrument->nloops > 0) { double nloops = planstate->instrument->nloops; @@ -1537,7 +1543,7 @@ ExplainNode(PlanState *planstate, List *ancestors, ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es); } } - else if (es->analyze) + else if (es->exec) { if (es->format == EXPLAIN_FORMAT_TEXT) appendStringInfoString(es->str, " (never executed)"); @@ -1606,7 +1612,7 @@ ExplainNode(PlanState *planstate, List *ancestors, if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); - if (es->analyze) + if (es->exec) ExplainPropertyFloat("Heap Fetches", NULL, planstate->instrument->ntuples2, 0, es); break; @@ -1624,7 +1630,7 @@ ExplainNode(PlanState *planstate, List *ancestors, if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); - if (es->analyze) + if (es->exec) show_tidbitmap_info((BitmapHeapScanState *) planstate, es); break; case T_SampleScan: @@ -1658,7 +1664,7 @@ ExplainNode(PlanState *planstate, List *ancestors, if (gather->initParam) show_eval_params(gather->initParam, es); - if (es->analyze) + if (es->exec) { int nworkers; @@ -1704,7 +1710,7 @@ ExplainNode(PlanState *planstate, List *ancestors, if (gm->initParam) show_eval_params(gm->initParam, es); - if (es->analyze) + if (es->exec) { int nworkers; @@ -1869,7 +1875,7 @@ ExplainNode(PlanState *planstate, List *ancestors, show_buffer_usage(es, &planstate->instrument->bufusage); /* Show worker detail */ - if (es->analyze && es->verbose && planstate->worker_instrument) + if (es->exec && es->verbose && planstate->worker_instrument) { WorkerInstrumentation *w = planstate->worker_instrument; bool opened_group = false; @@ -2531,12 +2537,12 @@ show_tablesample(TableSampleClause *tsc, PlanState *planstate, } /* - * If it's EXPLAIN ANALYZE, show tuplesort stats for a sort node + * If it's EXPLAIN EXEC, show tuplesort stats for a sort node */ static void show_sort_info(SortState *sortstate, ExplainState *es) { - if (!es->analyze) + if (!es->exec) return; if (sortstate->sort_Done && sortstate->tuplesortstate != NULL) @@ -2716,7 +2722,7 @@ show_hash_info(HashState *hashstate, ExplainState *es) } /* - * If it's EXPLAIN ANALYZE, show exact/lossy pages for a BitmapHeapScan node + * If it's EXPLAIN EXEC, show exact/lossy pages for a BitmapHeapScan node */ static void show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es) @@ -2744,7 +2750,7 @@ show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es) } /* - * If it's EXPLAIN ANALYZE, show instrumentation information for a plan node + * If it's EXPLAIN EXEC, show instrumentation information for a plan node * * "which" identifies which instrumentation counter to print */ @@ -2755,7 +2761,7 @@ show_instrumentation_count(const char *qlabel, int which, double nfiltered; double nloops; - if (!es->analyze || !planstate->instrument) + if (!es->exec || !planstate->instrument) return; if (which == 2) @@ -3283,8 +3289,8 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors, show_instrumentation_count("Rows Removed by Conflict Filter", 1, &mtstate->ps, es); } - /* EXPLAIN ANALYZE display of actual outcome for each tuple proposed */ - if (es->analyze && mtstate->ps.instrument) + /* EXPLAIN EXEC display of actual outcome for each tuple proposed */ + if (es->exec && mtstate->ps.instrument) { double total; double insert_path; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 3dc0e8a4fb..3a7d33502c 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10632,7 +10632,7 @@ opt_vacuum_relation_list: /***************************************************************************** * * QUERY: - * EXPLAIN [ANALYZE] [VERBOSE] query + * EXPLAIN [EXEC] [VERBOSE] query * EXPLAIN ( options ) query * *****************************************************************************/ @@ -10645,11 +10645,11 @@ ExplainStmt: n->options = NIL; $$ = (Node *) n; } - | EXPLAIN analyze_keyword opt_verbose ExplainableStmt + | EXPLAIN exec_keyword opt_verbose ExplainableStmt { ExplainStmt *n = makeNode(ExplainStmt); n->query = $4; - n->options = list_make1(makeDefElem("analyze", NULL, @2)); + n->options = list_make1(makeDefElem("exec", NULL, @2)); if ($3) n->options = lappend(n->options, makeDefElem("verbose", NULL, @3)); @@ -10703,7 +10703,7 @@ explain_option_elem: explain_option_name: NonReservedWord { $$ = $1; } - | analyze_keyword { $$ = "analyze"; } + | exec_keyword { $$ = "exec"; } ; explain_option_arg: @@ -10712,6 +10712,11 @@ explain_option_arg: | /* EMPTY */ { $$ = NULL; } ; +exec_keyword: + ANALYZE /* Legacy */ {} + | ANALYSE /* British and legacy */ {} + ; + /***************************************************************************** * * QUERY: diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h index db48f29501..09cc806d7e 100644 --- a/src/include/commands/explain.h +++ b/src/include/commands/explain.h @@ -30,8 +30,8 @@ typedef struct ExplainState StringInfo str; /* output buffer */ /* options */ bool verbose; /* be verbose */ - bool analyze; /* print actual times */ bool costs; /* print estimated costs */ + bool exec; /* actually execute the query, measure it */ bool buffers; /* print buffer usage */ bool timing; /* print detailed node timing */ bool summary; /* print total planning and execution timing */ --------------2.21.0--
v4-0002-Documentation.patch (text/x-diff, 6.6K) download From d4ee9af44e6f17e1ea505db78019a0280d655546 Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Tue, 14 May 2019 22:50:12 -0700 Subject: [PATCH v4 2/8] Documentation To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit diff --git a/doc/src/sgml/ref/explain.sgml b/doc/src/sgml/ref/explain.sgml index 385d10411f..63a3faede8 100644 --- a/doc/src/sgml/ref/explain.sgml +++ b/doc/src/sgml/ref/explain.sgml @@ -32,11 +32,11 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> EXPLAIN [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] <replaceable class="parameter">statement</replaceable> -EXPLAIN [ ANALYZE ] [ VERBOSE ] <replaceable class="parameter">statement</replaceable> +EXPLAIN [ EXEC ] [ VERBOSE ] <replaceable class="parameter">statement</replaceable> <phrase>where <replaceable class="parameter">option</replaceable> can be one of:</phrase> - ANALYZE [ <replaceable class="parameter">boolean</replaceable> ] + EXEC [ <replaceable class="parameter">boolean</replaceable> ] VERBOSE [ <replaceable class="parameter">boolean</replaceable> ] COSTS [ <replaceable class="parameter">boolean</replaceable> ] SETTINGS [ <replaceable class="parameter">boolean</replaceable> ] @@ -76,36 +76,37 @@ EXPLAIN [ ANALYZE ] [ VERBOSE ] <replaceable class="parameter">statement</replac </para> <para> - The <literal>ANALYZE</literal> option causes the statement to be actually + The <literal>EXEC</literal> option causes the statement to be actually executed, not only planned. Then actual run time statistics are added to the display, including the total elapsed time expended within each plan node (in milliseconds) and the total number of rows it actually returned. This is useful for seeing whether the planner's estimates - are close to reality. + are close to reality. For historical reasons, ANALYZE and ANALYSE can be + used instead of EXEC. </para> <important> <para> Keep in mind that the statement is actually executed when - the <literal>ANALYZE</literal> option is used. Although + the <literal>EXEC</literal> option is used. Although <command>EXPLAIN</command> will discard any output that a <command>SELECT</command> would return, other side effects of the statement will happen as usual. If you wish to use - <command>EXPLAIN ANALYZE</command> on an + <command>EXPLAIN EXEC</command> on an <command>INSERT</command>, <command>UPDATE</command>, <command>DELETE</command>, <command>CREATE TABLE AS</command>, or <command>EXECUTE</command> statement without letting the command affect your data, use this approach: <programlisting> BEGIN; -EXPLAIN ANALYZE ...; +EXPLAIN EXEC ...; ROLLBACK; </programlisting> </para> </important> <para> - Only the <literal>ANALYZE</literal> and <literal>VERBOSE</literal> options + Only the <literal>EXEC</literal> and <literal>VERBOSE</literal> options can be specified, and only in that order, without surrounding the option list in parentheses. Prior to <productname>PostgreSQL</productname> 9.0, the unparenthesized syntax was the only one supported. It is expected that @@ -118,7 +119,7 @@ ROLLBACK; <variablelist> <varlistentry> - <term><literal>ANALYZE</literal></term> + <term><literal>EXEC</literal></term> <listitem> <para> Carry out the command and show actual run times and other statistics. @@ -159,7 +160,7 @@ ROLLBACK; <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>. + default value. This parameter defaults to <literal>TRUE</literal>. </para> </listitem> </varlistentry> @@ -186,8 +187,8 @@ ROLLBACK; The number of blocks shown for an upper-level node includes those used by all its child nodes. In text format, only non-zero values are printed. This parameter may only be - used when <literal>ANALYZE</literal> is also enabled. It defaults to - <literal>FALSE</literal>. + used when <literal>EXEC</literal> is also enabled. It defaults to + <literal>TRUE</literal>. </para> </listitem> </varlistentry> @@ -203,7 +204,7 @@ ROLLBACK; not exact times, are needed. Run time of the entire statement is always measured, even when node-level timing is turned off with this option. - This parameter may only be used when <literal>ANALYZE</literal> is also + This parameter may only be used when <literal>EXEC</literal> is also enabled. It defaults to <literal>TRUE</literal>. </para> </listitem> @@ -215,9 +216,9 @@ ROLLBACK; <para> Include summary information (e.g., totaled timing information) after the query plan. Summary information is included by default when - <literal>ANALYZE</literal> is used but otherwise is not included by + <literal>EXEC</literal> is used but otherwise is not included by default, but can be enabled using this option. Planning time in - <command>EXPLAIN EXECUTE</command> includes the time required to fetch + <command>EXPLAIN EXEC</command> includes the time required to fetch the plan from the cache and the time required for re-planning, if necessary. </para> @@ -295,8 +296,8 @@ ROLLBACK; <para> In order to measure the run-time cost of each node in the execution plan, the current implementation of <command>EXPLAIN - ANALYZE</command> adds profiling overhead to query execution. - As a result, running <command>EXPLAIN ANALYZE</command> + EXEC</command> adds profiling overhead to query execution. + As a result, running <command>EXPLAIN EXEC</command> on a query can sometimes take significantly longer than executing the query normally. The amount of overhead depends on the nature of the query, as well as the platform being used. The worst case occurs @@ -423,7 +424,7 @@ PREPARE query(int, int) AS SELECT sum(bar) FROM test WHERE id &gt; $1 AND id &lt; $2 GROUP BY foo; -EXPLAIN ANALYZE EXECUTE query(100, 200); +EXPLAIN EXEC EXECUTE query(100, 200); QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ --------------2.21.0--
v4-0003-psql-support.patch (text/x-diff, 2.3K) download From a53669452bca9099407c034b2e86151f9233993f Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Tue, 14 May 2019 22:50:46 -0700 Subject: [PATCH v4 3/8] psql support To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index e4c03de221..ac0673dafc 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -2848,11 +2848,11 @@ psql_completion(const char *text, int start, int end) /* * EXPLAIN [ ( option [, ...] ) ] statement - * EXPLAIN [ ANALYZE ] [ VERBOSE ] statement + * EXPLAIN [ EXEC ] [ VERBOSE ] statement */ else if (Matches("EXPLAIN")) COMPLETE_WITH("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", - "ANALYZE", "VERBOSE"); + "EXEC", "VERBOSE"); else if (HeadMatches("EXPLAIN", "(*") && !HeadMatches("EXPLAIN", "(*)")) { @@ -2862,19 +2862,23 @@ psql_completion(const char *text, int start, int end) * one word, so the above test is correct. */ if (ends_with(prev_wd, '(') || ends_with(prev_wd, ',')) - COMPLETE_WITH("ANALYZE", "VERBOSE", "COSTS", "BUFFERS", + COMPLETE_WITH("EXEC", "VERBOSE", "COSTS", "BUFFERS", "TIMING", "SUMMARY", "FORMAT"); - else if (TailMatches("ANALYZE|VERBOSE|COSTS|BUFFERS|TIMING|SUMMARY")) + else if (TailMatches("EXEC|VERBOSE|COSTS|BUFFERS|TIMING|SUMMARY")) COMPLETE_WITH("ON", "OFF"); else if (TailMatches("FORMAT")) COMPLETE_WITH("TEXT", "XML", "JSON", "YAML"); } - else if (Matches("EXPLAIN", "ANALYZE")) + else if (Matches("EXPLAIN", "EXEC") || + Matches("EXPLAIN", "ANALYZE") || + Matches("EXPLAIN", "ANALYSE")) COMPLETE_WITH("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE"); else if (Matches("EXPLAIN", "(*)") || Matches("EXPLAIN", "VERBOSE") || - Matches("EXPLAIN", "ANALYZE", "VERBOSE")) + Matches("EXPLAIN", "EXEC", "VERBOSE") || + Matches("EXPLAIN", "ANALYZE", "VERBOSE") || + Matches("EXPLAIN", "ANALYSE", "VERBOSE")) COMPLETE_WITH("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE"); /* FETCH && MOVE */ --------------2.21.0--
v4-0004-Changed-examples-in-the-documentation-to-use-EXEC.patch (text/x-diff, 30.3K) download From e9b4f35e0512129582b157ff5c94833519de120a Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Tue, 14 May 2019 22:51:24 -0700 Subject: [PATCH v4 4/8] Changed examples in the documentation to use EXEC To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit diff --git a/doc/src/sgml/auto-explain.sgml b/doc/src/sgml/auto-explain.sgml index 3d619d4a3d..3025a57232 100644 --- a/doc/src/sgml/auto-explain.sgml +++ b/doc/src/sgml/auto-explain.sgml @@ -65,14 +65,14 @@ LOAD 'auto_explain'; <varlistentry> <term> - <varname>auto_explain.log_analyze</varname> (<type>boolean</type>) + <varname>auto_explain.log_exec</varname> (<type>boolean</type>) <indexterm> - <primary><varname>auto_explain.log_analyze</varname> configuration parameter</primary> + <primary><varname>auto_explain.log_exec</varname> configuration parameter</primary> </indexterm> </term> <listitem> <para> - <varname>auto_explain.log_analyze</varname> causes <command>EXPLAIN ANALYZE</command> + <varname>auto_explain.log_exec</varname> causes <command>EXPLAIN EXEC</command> output, rather than just <command>EXPLAIN</command> output, to be printed when an execution plan is logged. This parameter is off by default. Only superusers can change this setting. @@ -102,7 +102,7 @@ LOAD 'auto_explain'; usage statistics are printed when an execution plan is logged; it's equivalent to the <literal>BUFFERS</literal> option of <command>EXPLAIN</command>. This parameter has no effect - unless <varname>auto_explain.log_analyze</varname> is enabled. + unless <varname>auto_explain.log_exec</varname> is enabled. This parameter is off by default. Only superusers can change this setting. </para> @@ -126,7 +126,7 @@ LOAD 'auto_explain'; parameter to off when only actual row counts, and not exact times, are needed. This parameter has no effect - unless <varname>auto_explain.log_analyze</varname> is enabled. + unless <varname>auto_explain.log_exec</varname> is enabled. This parameter is on by default. Only superusers can change this setting. </para> @@ -145,7 +145,7 @@ LOAD 'auto_explain'; <varname>auto_explain.log_triggers</varname> causes trigger execution statistics to be included when an execution plan is logged. This parameter has no effect - unless <varname>auto_explain.log_analyze</varname> is enabled. + unless <varname>auto_explain.log_exec</varname> is enabled. This parameter is off by default. Only superusers can change this setting. </para> @@ -283,7 +283,7 @@ auto_explain.log_min_duration = '3s' <programlisting> postgres=# LOAD 'auto_explain'; postgres=# SET auto_explain.log_min_duration = 0; -postgres=# SET auto_explain.log_analyze = true; +postgres=# SET auto_explain.log_exec = true; postgres=# SELECT count(*) FROM pg_class, pg_index WHERE oid = indrelid AND indisunique; diff --git a/doc/src/sgml/bloom.sgml b/doc/src/sgml/bloom.sgml index 6eeaddee09..5b4ede2db1 100644 --- a/doc/src/sgml/bloom.sgml +++ b/doc/src/sgml/bloom.sgml @@ -129,7 +129,7 @@ CREATE INDEX <para> A sequential scan over this large table takes a long time: <programlisting> -=# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; +=# EXPLAIN EXEC SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; QUERY PLAN ------------------------------------------------------------------------------------------------------------ Seq Scan on tbloom (cost=0.00..213694.08 rows=1 width=24) (actual time=1445.438..1445.438 rows=0 loops=1) @@ -145,7 +145,7 @@ CREATE INDEX So the planner will usually select an index scan if possible. With a btree index, we get results like this: <programlisting> -=# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; +=# EXPLAIN EXEC SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- Index Only Scan using btreeidx on tbloom (cost=0.56..298311.96 rows=1 width=24) (actual time=445.709..445.709 rows=0 loops=1) @@ -160,7 +160,7 @@ CREATE INDEX <para> Bloom is better than btree in handling this type of search: <programlisting> -=# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; +=# EXPLAIN EXEC SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------- Bitmap Heap Scan on tbloom (cost=178435.39..178439.41 rows=1 width=24) (actual time=76.698..76.698 rows=0 loops=1) @@ -187,7 +187,7 @@ CREATE INDEX A better strategy for btree is to create a separate index on each column. Then the planner will choose something like this: <programlisting> -=# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; +=# EXPLAIN EXEC SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------ Bitmap Heap Scan on tbloom (cost=9.29..13.30 rows=1 width=24) (actual time=0.148..0.148 rows=0 loops=1) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 84341a30e5..41e9a64182 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -6441,7 +6441,7 @@ log_line_prefix = '%m [%p] %q%u@%d/%a ' <command>UPDATE</command>, <command>DELETE</command>, <command>TRUNCATE</command>, and <command>COPY FROM</command>. <command>PREPARE</command>, <command>EXECUTE</command>, and - <command>EXPLAIN ANALYZE</command> statements are also logged if their + <command>EXPLAIN EXEC</command> statements are also logged if their contained command is of an appropriate type. For clients using extended query protocol, logging occurs when an Execute message is received, and values of the Bind parameters are included diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index a0a7435a03..407f94dfbe 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -4498,7 +4498,7 @@ EXPLAIN SELECT count(*) FROM measurement WHERE logdate &gt;= DATE '2008-01-01'; performed here for parameter values which are known during the initialization phase of execution. Partitions which are pruned during this stage will not show up in the query's - <command>EXPLAIN</command> or <command>EXPLAIN ANALYZE</command>. + <command>EXPLAIN</command> or <command>EXPLAIN EXEC</command>. It is possible to determine the number of partitions which were removed during this phase by observing the <quote>Subplans Removed</quote> property in the @@ -4518,7 +4518,7 @@ EXPLAIN SELECT count(*) FROM measurement WHERE logdate &gt;= DATE '2008-01-01'; execution parameters being used by partition pruning changes. Determining if partitions were pruned during this phase requires careful inspection of the <literal>loops</literal> property in - the <command>EXPLAIN ANALYZE</command> output. Subplans + the <command>EXPLAIN EXEC</command> output. Subplans corresponding to different partitions may have different values for it depending on how many times each of them was pruned during execution. Some may be shown as <literal>(never executed)</literal> diff --git a/doc/src/sgml/fdwhandler.sgml b/doc/src/sgml/fdwhandler.sgml index 27b94fb611..0f1e80b3b9 100644 --- a/doc/src/sgml/fdwhandler.sgml +++ b/doc/src/sgml/fdwhandler.sgml @@ -937,7 +937,7 @@ IterateDirectModify(ForeignScanState *node); Whether the query has the clause or not, the query's reported row count must be incremented by the FDW itself. When the query doesn't have the clause, the FDW must also increment the row count for the - <structname>ForeignScanState</structname> node in the <command>EXPLAIN ANALYZE</command> + <structname>ForeignScanState</structname> node in the <command>EXPLAIN EXEC</command> case. </para> @@ -1123,7 +1123,7 @@ ExplainForeignScan(ForeignScanState *node, The flag fields in <literal>es</literal> can be used to determine what to print, and the state of the <structname>ForeignScanState</structname> node can be inspected to provide run-time statistics in the <command>EXPLAIN - ANALYZE</command> case. + EXEC</command> case. </para> <para> @@ -1148,7 +1148,7 @@ ExplainForeignModify(ModifyTableState *mtstate, The flag fields in <literal>es</literal> can be used to determine what to print, and the state of the <structname>ModifyTableState</structname> node can be inspected to provide run-time statistics in the <command>EXPLAIN - ANALYZE</command> case. The first four arguments are the same as for + EXEC</command> case. The first four arguments are the same as for <function>BeginForeignModify</function>. </para> @@ -1172,7 +1172,7 @@ ExplainDirectModify(ForeignScanState *node, The flag fields in <literal>es</literal> can be used to determine what to print, and the state of the <structname>ForeignScanState</structname> node can be inspected to provide run-time statistics in the <command>EXPLAIN - ANALYZE</command> case. + EXEC</command> case. </para> <para> diff --git a/doc/src/sgml/indices.sgml b/doc/src/sgml/indices.sgml index 95c0a1926c..decaaa6209 100644 --- a/doc/src/sgml/indices.sgml +++ b/doc/src/sgml/indices.sgml @@ -1498,7 +1498,7 @@ CREATE INDEX test1c_content_y_index ON test1c (content COLLATE "y"); possibilities: Either the system is right and using the index is indeed not appropriate, or the cost estimates of the query plans are not reflecting reality. So you should time your query with - and without indexes. The <command>EXPLAIN ANALYZE</command> + and without indexes. The <command>EXPLAIN EXEC</command> command can be useful here. </para> </listitem> diff --git a/doc/src/sgml/jit.sgml b/doc/src/sgml/jit.sgml index a21a07ef71..cb288d8b73 100644 --- a/doc/src/sgml/jit.sgml +++ b/doc/src/sgml/jit.sgml @@ -145,7 +145,7 @@ <acronym>JIT</acronym> is used or not. As an example, here is a query that is not using <acronym>JIT</acronym>: <screen> -=# EXPLAIN ANALYZE SELECT SUM(relpages) FROM pg_class; +=# EXPLAIN EXEC SELECT SUM(relpages) FROM pg_class; QUERY PLAN ------------------------------------------------------------------------------------------------------------- Aggregate (cost=16.27..16.29 rows=1 width=8) (actual time=0.303..0.303 rows=1 loops=1) @@ -161,7 +161,7 @@ <screen> =# SET jit_above_cost = 10; SET -=# EXPLAIN ANALYZE SELECT SUM(relpages) FROM pg_class; +=# EXPLAIN EXEC SELECT SUM(relpages) FROM pg_class; QUERY PLAN ------------------------------------------------------------------------------------------------------------- Aggregate (cost=16.27..16.29 rows=1 width=8) (actual time=6.049..6.049 rows=1 loops=1) diff --git a/doc/src/sgml/parallel.sgml b/doc/src/sgml/parallel.sgml index af5d48a5c7..b3e2285f05 100644 --- a/doc/src/sgml/parallel.sgml +++ b/doc/src/sgml/parallel.sgml @@ -442,7 +442,7 @@ EXPLAIN SELECT * FROM pgbench_accounts WHERE filler LIKE '%x%'; </para> <para> - When executing a parallel plan, you can use <literal>EXPLAIN (ANALYZE, + When executing a parallel plan, you can use <literal>EXPLAIN (EXEC, VERBOSE)</literal> to display per-worker statistics for each plan node. This may be useful in determining whether the work is being evenly distributed between all plan nodes and more generally in understanding the diff --git a/doc/src/sgml/perform.sgml b/doc/src/sgml/perform.sgml index a84be85159..3a890c5a71 100644 --- a/doc/src/sgml/perform.sgml +++ b/doc/src/sgml/perform.sgml @@ -533,25 +533,25 @@ WHERE t1.unique1 &lt; 100 AND t1.unique2 = t2.unique2; which shows that the planner thinks that sorting <literal>onek</literal> by index-scanning is about 12% more expensive than sequential-scan-and-sort. Of course, the next question is whether it's right about that. - We can investigate that using <command>EXPLAIN ANALYZE</command>, as discussed + We can investigate that using <command>EXPLAIN EXEC</command>, as discussed below. </para> </sect2> - <sect2 id="using-explain-analyze"> - <title><command>EXPLAIN ANALYZE</command></title> + <sect2 id="using-explain-exec"> + <title><command>EXPLAIN EXEC</command></title> <para> It is possible to check the accuracy of the planner's estimates - by using <command>EXPLAIN</command>'s <literal>ANALYZE</literal> option. With this + by using <command>EXPLAIN</command>'s <literal>EXEC</literal> option. With this option, <command>EXPLAIN</command> actually executes the query, and then displays the true row counts and true run time accumulated within each plan node, along with the same estimates that a plain <command>EXPLAIN</command> shows. For example, we might get a result like this: <screen> -EXPLAIN ANALYZE SELECT * +EXPLAIN EXEC SELECT * FROM tenk1 t1, tenk2 t2 WHERE t1.unique1 &lt; 10 AND t1.unique2 = t2.unique2; @@ -590,12 +590,12 @@ WHERE t1.unique1 &lt; 10 AND t1.unique2 = t2.unique2; </para> <para> - In some cases <command>EXPLAIN ANALYZE</command> shows additional execution + In some cases <command>EXPLAIN EXEC</command> shows additional execution statistics beyond the plan node execution times and row counts. For example, Sort and Hash nodes provide extra information: <screen> -EXPLAIN ANALYZE SELECT * +EXPLAIN EXEC SELECT * FROM tenk1 t1, tenk2 t2 WHERE t1.unique1 &lt; 100 AND t1.unique2 = t2.unique2 ORDER BY t1.fivethous; @@ -630,7 +630,7 @@ WHERE t1.unique1 &lt; 100 AND t1.unique2 = t2.unique2 ORDER BY t1.fivethous; filter condition: <screen> -EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE ten &lt; 7; +EXPLAIN EXEC SELECT * FROM tenk1 WHERE ten &lt; 7; QUERY PLAN --------------------------------------------------------------------------------------------------------- @@ -653,7 +653,7 @@ EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE ten &lt; 7; specific point: <screen> -EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; +EXPLAIN EXEC SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; QUERY PLAN ------------------------------------------------------------------------------------------------------ @@ -672,7 +672,7 @@ EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; <screen> SET enable_seqscan TO off; -EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; +EXPLAIN EXEC SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- @@ -695,7 +695,7 @@ EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; <literal>ANALYZE</literal> to get even more run time statistics: <screen> -EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000; +EXPLAIN (EXEC, BUFFERS) SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- @@ -719,7 +719,7 @@ EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique </para> <para> - Keep in mind that because <command>EXPLAIN ANALYZE</command> actually + Keep in mind that because <command>EXPLAIN EXEC</command> actually runs the query, any side-effects will happen as usual, even though whatever results the query might output are discarded in favor of printing the <command>EXPLAIN</command> data. If you want to analyze a @@ -729,7 +729,7 @@ EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique <screen> BEGIN; -EXPLAIN ANALYZE UPDATE tenk1 SET hundred = hundred + 1 WHERE unique1 &lt; 100; +EXPLAIN EXEC UPDATE tenk1 SET hundred = hundred + 1 WHERE unique1 &lt; 100; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- @@ -795,13 +795,13 @@ EXPLAIN UPDATE parent SET f2 = f2 + 1 WHERE f1 = 101; <para> The <literal>Planning time</literal> shown by <command>EXPLAIN - ANALYZE</command> is the time it took to generate the query plan from the + EXEC</command> is the time it took to generate the query plan from the parsed query and optimize it. It does not include parsing or rewriting. </para> <para> The <literal>Execution time</literal> shown by <command>EXPLAIN - ANALYZE</command> includes executor start-up and shut-down time, as well + EXEC</command> includes executor start-up and shut-down time, as well as the time to run any triggers that are fired, but it does not include parsing, rewriting, or planning time. Time spent executing <literal>BEFORE</literal> triggers, if any, is included in @@ -812,7 +812,7 @@ EXPLAIN UPDATE parent SET f2 = f2 + 1 WHERE f1 = 101; (either <literal>BEFORE</literal> or <literal>AFTER</literal>) is also shown separately. Note that deferred constraint triggers will not be executed until end of transaction and are thus not considered at all by - <command>EXPLAIN ANALYZE</command>. + <command>EXPLAIN EXEC</command>. </para> </sect2> @@ -822,11 +822,11 @@ EXPLAIN UPDATE parent SET f2 = f2 + 1 WHERE f1 = 101; <para> There are two significant ways in which run times measured by - <command>EXPLAIN ANALYZE</command> can deviate from normal execution of + <command>EXPLAIN EXEC</command> can deviate from normal execution of the same query. First, since no output rows are delivered to the client, network transmission costs and I/O conversion costs are not included. Second, the measurement overhead added by <command>EXPLAIN - ANALYZE</command> can be significant, especially on machines with slow + EXEC</command> can be significant, especially on machines with slow <function>gettimeofday()</function> operating-system calls. You can use the <xref linkend="pgtesttiming"/> tool to measure the overhead of timing on your system. @@ -853,7 +853,7 @@ EXPLAIN UPDATE parent SET f2 = f2 + 1 WHERE f1 = 101; effect. For example, in the <literal>LIMIT</literal> query we used before, <screen> -EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000 LIMIT 2; +EXPLAIN EXEC SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000 LIMIT 2; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- @@ -883,7 +883,7 @@ EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000 of one child, with results like those mentioned for <literal>LIMIT</literal>. Also, if the outer (first) child contains rows with duplicate key values, the inner (second) child is backed up and rescanned for the portion of its - rows matching that key value. <command>EXPLAIN ANALYZE</command> counts these + rows matching that key value. <command>EXPLAIN EXEC</command> counts these repeated emissions of the same inner rows as if they were real additional rows. When there are many outer duplicates, the reported actual row count for the inner child plan node can be significantly larger than the number diff --git a/doc/src/sgml/planstats.sgml b/doc/src/sgml/planstats.sgml index 4b1d3f4952..3a4405c850 100644 --- a/doc/src/sgml/planstats.sgml +++ b/doc/src/sgml/planstats.sgml @@ -489,7 +489,7 @@ SELECT relpages, reltuples FROM pg_class WHERE relname = 't'; condition on the <structfield>a</structfield> column: <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a = 1; QUERY PLAN ------------------------------------------------------------------------------- Seq Scan on t (cost=0.00..170.00 rows=100 width=8) (actual rows=100 loops=1) @@ -506,7 +506,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1; condition on both columns, combining them with <literal>AND</literal>: <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; QUERY PLAN ----------------------------------------------------------------------------- Seq Scan on t (cost=0.00..195.00 rows=1 width=8) (actual rows=100 loops=1) @@ -530,7 +530,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; <programlisting> CREATE STATISTICS stts (dependencies) ON a, b FROM t; ANALYZE t; -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; QUERY PLAN ------------------------------------------------------------------------------- Seq Scan on t (cost=0.00..195.00 rows=100 width=8) (actual rows=100 loops=1) @@ -551,7 +551,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; estimated number of rows returned by the HashAggregate node) is very accurate: <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a; +EXPLAIN (EXEC, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a; QUERY PLAN ----------------------------------------------------------------------------------------- HashAggregate (cost=195.00..196.00 rows=100 width=12) (actual rows=100 loops=1) @@ -562,7 +562,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a; groups in a query with two columns in <command>GROUP BY</command>, as in the following example, is off by an order of magnitude: <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; +EXPLAIN (EXEC, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; QUERY PLAN -------------------------------------------------------------------------------------------- HashAggregate (cost=220.00..230.00 rows=1000 width=16) (actual rows=100 loops=1) @@ -575,7 +575,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; DROP STATISTICS stts; CREATE STATISTICS stts (dependencies, ndistinct) ON a, b FROM t; ANALYZE t; -EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; +EXPLAIN (EXEC, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; QUERY PLAN -------------------------------------------------------------------------------------------- HashAggregate (cost=220.00..221.00 rows=100 width=16) (actual rows=100 loops=1) @@ -615,7 +615,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; DROP STATISTICS stts; CREATE STATISTICS stts2 (mcv) ON a, b FROM t; ANALYZE t; -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; QUERY PLAN ------------------------------------------------------------------------------- Seq Scan on t (cost=0.00..195.00 rows=100 width=8) (actual rows=100 loops=1) @@ -672,7 +672,7 @@ SELECT m.* FROM pg_statistic_ext, to decide which combinations are compatible. <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 10; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 10; QUERY PLAN --------------------------------------------------------------------------- Seq Scan on t (cost=0.00..195.00 rows=1 width=8) (actual rows=0 loops=1) @@ -685,7 +685,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 10; example range query, presented earlier: <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a &lt;= 49 AND b &gt; 49; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a &lt;= 49 AND b &gt; 49; QUERY PLAN --------------------------------------------------------------------------- Seq Scan on t (cost=0.00..195.00 rows=1 width=8) (actual rows=0 loops=1) diff --git a/doc/src/sgml/ref/create_statistics.sgml b/doc/src/sgml/ref/create_statistics.sgml index ae1d8024a4..18ca19fa8f 100644 --- a/doc/src/sgml/ref/create_statistics.sgml +++ b/doc/src/sgml/ref/create_statistics.sgml @@ -147,14 +147,14 @@ INSERT INTO t1 SELECT i/100, i/500 ANALYZE t1; -- the number of matching rows will be drastically underestimated: -EXPLAIN ANALYZE SELECT * FROM t1 WHERE (a = 1) AND (b = 0); +EXPLAIN EXEC SELECT * FROM t1 WHERE (a = 1) AND (b = 0); CREATE STATISTICS s1 (dependencies) ON a, b FROM t1; ANALYZE t1; -- now the row count estimate is more accurate: -EXPLAIN ANALYZE SELECT * FROM t1 WHERE (a = 1) AND (b = 0); +EXPLAIN EXEC SELECT * FROM t1 WHERE (a = 1) AND (b = 0); </programlisting> Without functional-dependency statistics, the planner would assume @@ -183,10 +183,10 @@ CREATE STATISTICS s2 (mcv) ON (a, b) FROM t2; ANALYZE t2; -- valid combination (found in MCV) -EXPLAIN ANALYZE SELECT * FROM t2 WHERE (a = 1) AND (b = 1); +EXPLAIN EXEC SELECT * FROM t2 WHERE (a = 1) AND (b = 1); -- invalid combination (not found in MCV) -EXPLAIN ANALYZE SELECT * FROM t2 WHERE (a = 1) AND (b = 2); +EXPLAIN EXEC SELECT * FROM t2 WHERE (a = 1) AND (b = 2); </programlisting> The MCV list gives the planner more detailed information about the diff --git a/doc/src/sgml/ref/pgtesttiming.sgml b/doc/src/sgml/ref/pgtesttiming.sgml index 545a934cf8..4470435dd2 100644 --- a/doc/src/sgml/ref/pgtesttiming.sgml +++ b/doc/src/sgml/ref/pgtesttiming.sgml @@ -30,7 +30,7 @@ <application>pg_test_timing</application> is a tool to measure the timing overhead on your system and confirm that the system time never moves backwards. Systems that are slow to collect timing data can give less accurate - <command>EXPLAIN ANALYZE</command> results. + <command>EXPLAIN EXEC</command> results. </para> </refsect1> @@ -120,7 +120,7 @@ Histogram of timing durations: <para> When the query executor is running a statement using - <command>EXPLAIN ANALYZE</command>, individual operations are timed as well + <command>EXPLAIN EXEC</command>, individual operations are timed as well as showing a summary. The overhead of your system can be checked by counting rows with the <application>psql</application> program: @@ -128,13 +128,13 @@ Histogram of timing durations: CREATE TABLE t AS SELECT * FROM generate_series(1,100000); \timing SELECT COUNT(*) FROM t; -EXPLAIN ANALYZE SELECT COUNT(*) FROM t; +EXPLAIN EXEC SELECT COUNT(*) FROM t; </screen> </para> <para> The i7-860 system measured runs the count query in 9.8 ms while - the <command>EXPLAIN ANALYZE</command> version takes 16.6 ms, each + the <command>EXPLAIN EXEC</command> version takes 16.6 ms, each processing just over 100,000 rows. That 6.8 ms difference means the timing overhead per row is 68 ns, about twice what pg_test_timing estimated it would be. Even that relatively small amount of overhead is making the fully @@ -169,12 +169,12 @@ Histogram of timing durations: </para> <para> - In this configuration, the sample <command>EXPLAIN ANALYZE</command> above + In this configuration, the sample <command>EXPLAIN EXEC</command> above takes 115.9 ms. That's 1061 ns of timing overhead, again a small multiple of what's measured directly by this utility. That much timing overhead means the actual query itself is only taking a tiny fraction of the accounted for time, most of it is being consumed in overhead instead. In - this configuration, any <command>EXPLAIN ANALYZE</command> totals involving + this configuration, any <command>EXPLAIN EXEC</command> totals involving many timed operations would be inflated significantly by timing overhead. </para> diff --git a/doc/src/sgml/ref/set_transaction.sgml b/doc/src/sgml/ref/set_transaction.sgml index 43b1c6c892..cef790ecd7 100644 --- a/doc/src/sgml/ref/set_transaction.sgml +++ b/doc/src/sgml/ref/set_transaction.sgml @@ -133,7 +133,7 @@ SET SESSION CHARACTERISTICS AS TRANSACTION <replaceable class="parameter">transa <literal>CREATE</literal>, <literal>ALTER</literal>, and <literal>DROP</literal> commands; <literal>COMMENT</literal>, <literal>GRANT</literal>, <literal>REVOKE</literal>, - <literal>TRUNCATE</literal>; and <literal>EXPLAIN ANALYZE</literal> + <literal>TRUNCATE</literal>; and <literal>EXPLAIN EXEC</literal> and <literal>EXECUTE</literal> if the command they would execute is among those listed. This is a high-level notion of read-only that does not prevent all writes to disk. diff --git a/doc/src/sgml/rules.sgml b/doc/src/sgml/rules.sgml index 4e20664ea1..499e6fcced 100644 --- a/doc/src/sgml/rules.sgml +++ b/doc/src/sgml/rules.sgml @@ -1030,7 +1030,7 @@ SELECT count(*) FROM words WHERE word = 'caterpiler'; (1 row) </programlisting> - With <command>EXPLAIN ANALYZE</command>, we see: + With <command>EXPLAIN EXEC</command>, we see: <programlisting> Aggregate (cost=21763.99..21764.00 rows=1 width=0) (actual time=188.180..188.181 rows=1 loops=1) --------------2.21.0--
v4-0005-Changed-code-comments-to-reflect-the-new-default-.patch (text/x-diff, 8.7K) download From c808fa83c4682f1c352d7d96e3fb712f8a82fe41 Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Tue, 14 May 2019 22:53:19 -0700 Subject: [PATCH v4 5/8] Changed code comments to reflect the new default spelling To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 2beb378145..8c4320df58 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -2365,7 +2365,7 @@ FindTriggerIncompatibleWithInheritance(TriggerDesc *trigdesc) * trigdata: trigger descriptor. * tgindx: trigger's index in finfo and instr arrays. * finfo: array of cached trigger function call information. - * instr: optional array of EXPLAIN ANALYZE instrumentation state. + * instr: optional array of EXPLAIN EXEC instrumentation state. * per_tuple_context: memory context to execute the function in. * * Returns the tuple (or NULL) as returned by the function. @@ -2406,7 +2406,7 @@ ExecCallTriggerFunc(TriggerData *trigdata, Assert(finfo->fn_oid == trigdata->tg_trigger->tgfoid); /* - * If doing EXPLAIN ANALYZE, start charging time to this trigger. + * If doing EXPLAIN EXEC, start charging time to this trigger. */ if (instr) InstrStartNode(instr + tgindx); @@ -2455,7 +2455,7 @@ ExecCallTriggerFunc(TriggerData *trigdata, fcinfo->flinfo->fn_oid))); /* - * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count + * If doing EXPLAIN EXEC, stop charging time to this trigger, and count * one "tuple returned" (really the number of firings). */ if (instr) @@ -4171,7 +4171,7 @@ afterTriggerDeleteHeadEventChunk(AfterTriggersQueryData *qs) * rel: open relation for event. * trigdesc: working copy of rel's trigger info. * finfo: array of fmgr lookup cache entries (one per trigger in trigdesc). - * instr: array of EXPLAIN ANALYZE instrumentation nodes (one per trigger), + * instr: array of EXPLAIN EXEC instrumentation nodes (one per trigger), * or NULL if no instrumentation is wanted. * per_tuple_context: memory context to call trigger function in. * trig_tuple_slot1: scratch slot for tg_trigtuple (foreign tables only) @@ -4216,7 +4216,7 @@ AfterTriggerExecute(EState *estate, elog(ERROR, "could not find trigger %u", tgoid); /* - * If doing EXPLAIN ANALYZE, start charging time to this trigger. We want + * If doing EXPLAIN EXEC, start charging time to this trigger. We want * to include time spent re-fetching tuples in the trigger cost. */ if (instr) @@ -4359,7 +4359,7 @@ AfterTriggerExecute(EState *estate, ExecClearTuple(LocTriggerData.tg_newslot); /* - * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count + * If doing EXPLAIN EXEC, stop charging time to this trigger, and count * one "tuple returned" (really the number of firings). */ if (instr) diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index ed7c0606bf..cbbc7e087b 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -390,7 +390,7 @@ standard_ExecutorRun(QueryDesc *queryDesc, * * This routine must be called after the last ExecutorRun call. * It performs cleanup such as firing AFTER triggers. It is - * separate from ExecutorEnd because EXPLAIN ANALYZE needs to + * separate from ExecutorEnd because EXPLAIN EXEC needs to * include these actions in the total runtime. * * We provide a function hook variable that lets loadable plugins @@ -1365,7 +1365,7 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo, * on other relations, which will be processed in the context of the outer * query. For efficiency's sake, we want to have a ResultRelInfo for those * triggers too; that can avoid repeated re-opening of the relation. (It - * also provides a way for EXPLAIN ANALYZE to report the runtimes of such + * also provides a way for EXPLAIN EXEC to report the runtimes of such * triggers.) So we make additional ResultRelInfo's as needed, and save them * in es_trig_target_relations. */ diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index 3d4b01cb4d..adcccbbdcb 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -273,11 +273,11 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e) e->pcxt); break; case T_HashState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecHashEstimate((HashState *) planstate, e->pcxt); break; case T_SortState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecSortEstimate((SortState *) planstate, e->pcxt); break; @@ -486,11 +486,11 @@ ExecParallelInitializeDSM(PlanState *planstate, d->pcxt); break; case T_HashState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecHashInitializeDSM((HashState *) planstate, d->pcxt); break; case T_SortState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecSortInitializeDSM((SortState *) planstate, d->pcxt); break; @@ -1294,11 +1294,11 @@ ExecParallelInitializeWorker(PlanState *planstate, ParallelWorkerContext *pwcxt) pwcxt); break; case T_HashState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecHashInitializeWorker((HashState *) planstate, pwcxt); break; case T_SortState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecSortInitializeWorker((SortState *) planstate, pwcxt); break; diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index 64eec91f8b..c6a2906db5 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -193,7 +193,7 @@ MultiExecPrivateHash(HashState *node) if (hashtable->nbuckets != hashtable->nbuckets_optimal) ExecHashIncreaseNumBuckets(hashtable); - /* Account for the buckets in spaceUsed (reported in EXPLAIN ANALYZE) */ + /* Account for the buckets in spaceUsed (reported in EXPLAIN EXEC) */ hashtable->spaceUsed += hashtable->nbuckets * sizeof(HashJoinTuple); if (hashtable->spaceUsed > hashtable->spacePeak) hashtable->spacePeak = hashtable->spaceUsed; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 92d0507949..cd5e834ae9 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -3215,19 +3215,19 @@ GetCommandLogLevel(Node *parsetree) case T_ExplainStmt: { ExplainStmt *stmt = (ExplainStmt *) parsetree; - bool analyze = false; + bool exec = false; ListCell *lc; - /* Look through an EXPLAIN ANALYZE to the contained stmt */ + /* Look through an EXPLAIN EXEC to the contained stmt */ foreach(lc, stmt->options) { DefElem *opt = (DefElem *) lfirst(lc); - if (strcmp(opt->defname, "analyze") == 0) - analyze = defGetBoolean(opt); + if (strcmp(opt->defname, "exec") == 0) + exec = defGetBoolean(opt); /* don't "break", as explain.c will use the last value */ } - if (analyze) + if (exec) return GetCommandLogLevel(stmt->query); /* Plain EXPLAIN isn't so interesting */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index eb4c8b5e79..72730fcfaf 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -52,7 +52,7 @@ * mean that the plan can't queue any AFTER triggers; just that the caller * is responsible for there being a trigger context for them to be queued in. */ -#define EXEC_FLAG_EXPLAIN_ONLY 0x0001 /* EXPLAIN, no ANALYZE */ +#define EXEC_FLAG_EXPLAIN_ONLY 0x0001 /* EXPLAIN, no EXEC */ #define EXEC_FLAG_REWIND 0x0002 /* need efficient rescan */ #define EXEC_FLAG_BACKWARD 0x0004 /* need backward scan */ #define EXEC_FLAG_MARK 0x0008 /* need mark/restore */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 4b1635eb8b..6a92fb1d6f 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -2189,7 +2189,7 @@ typedef struct GatherMergeState } GatherMergeState; /* ---------------- - * Values displayed by EXPLAIN ANALYZE + * Values displayed by EXPLAIN EXEC * ---------------- */ typedef struct HashInstrumentation --------------2.21.0--
v4-0006-Mechanical-changes-to-regression-tests-and-their-.patch (text/x-diff, 450.6K) download From b04ca32d79ca18a7b68e04c12e2ae053351a2bbb Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Tue, 14 May 2019 22:54:15 -0700 Subject: [PATCH v4 6/8] Mechanical changes to regression tests and their output To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out index 129c1e5075..4c06b8b507 100644 --- a/src/test/regress/expected/aggregates.out +++ b/src/test/regress/expected/aggregates.out @@ -795,7 +795,8 @@ explain (costs off) -> Limit -> Index Only Scan Backward using tenk1_unique1 on tenk1 Index Cond: ((unique1 IS NOT NULL) AND (unique1 > 42000)) -(5 rows) + Settings: max_parallel_workers_per_gather = '0' +(6 rows) select max(unique1) from tenk1 where unique1 > 42000; max @@ -2179,14 +2180,15 @@ ALTER TABLE tenk1 set (parallel_workers = 4); SET LOCAL parallel_setup_cost=0; SET LOCAL max_parallel_workers_per_gather=4; EXPLAIN (COSTS OFF) SELECT balk(hundred) FROM tenk1; - QUERY PLAN -------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 4 -> Partial Aggregate -> Parallel Index Only Scan using tenk1_hundred on tenk1 -(5 rows) + Settings: max_parallel_workers_per_gather = '4', parallel_setup_cost = '0' +(6 rows) SELECT balk(hundred) FROM tenk1; balk @@ -2206,14 +2208,15 @@ SET enable_indexonlyscan = off; -- sum(int8) covers int8_avg_combine EXPLAIN (COSTS OFF) SELECT variance(unique1::int4), sum(unique1::int8) FROM tenk1; - QUERY PLAN ----------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 4 -> Partial Aggregate -> Parallel Seq Scan on tenk1 -(5 rows) + Settings: enable_indexonlyscan = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(6 rows) SELECT variance(unique1::int4), sum(unique1::int8) FROM tenk1; variance | sum diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out index 998b52223c..b3ee86063f 100644 --- a/src/test/regress/expected/box.out +++ b/src/test/regress/expected/box.out @@ -270,7 +270,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 << '(10,20),(30,40)'; ---------------------------------------------- Index Only Scan using box_spgist on box_temp Index Cond: (f1 << '(30,40),(10,20)'::box) -(2 rows) + Settings: enable_seqscan = 'off' +(3 rows) SELECT * FROM box_temp WHERE f1 &< '(10,4.333334),(5,100)'; f1 @@ -290,7 +291,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 &< '(10,4.333334),(5,100)'; ---------------------------------------------------- Index Only Scan using box_spgist on box_temp Index Cond: (f1 &< '(10,100),(5,4.333334)'::box) -(2 rows) + Settings: enable_seqscan = 'off' +(3 rows) SELECT * FROM box_temp WHERE f1 && '(15,20),(25,30)'; f1 @@ -319,7 +321,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 && '(15,20),(25,30)'; ---------------------------------------------- Index Only Scan using box_spgist on box_temp Index Cond: (f1 && '(25,30),(15,20)'::box) -(2 rows) + Settings: enable_seqscan = 'off' +(3 rows) SELECT * FROM box_temp WHERE f1 &> '(40,30),(45,50)'; f1 @@ -342,7 +345,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 &> '(40,30),(45,50)'; ---------------------------------------------- Index Only Scan using box_spgist on box_temp Index Cond: (f1 &> '(45,50),(40,30)'::box) -(2 rows) + Settings: enable_seqscan = 'off' +(3 rows) SELECT * FROM box_temp WHERE f1 >> '(30,40),(40,30)'; f1 @@ -364,7 +368,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 >> '(30,40),(40,30)'; ---------------------------------------------- Index Only Scan using box_spgist on box_temp Index Cond: (f1 >> '(40,40),(30,30)'::box) -(2 rows) + Settings: enable_seqscan = 'off' +(3 rows) SELECT * FROM box_temp WHERE f1 <<| '(10,4.33334),(5,100)'; f1 @@ -379,7 +384,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 <<| '(10,4.33334),(5,100)'; ---------------------------------------------------- Index Only Scan using box_spgist on box_temp Index Cond: (f1 <<| '(10,100),(5,4.33334)'::box) -(2 rows) + Settings: enable_seqscan = 'off' +(3 rows) SELECT * FROM box_temp WHERE f1 &<| '(10,4.3333334),(5,1)'; f1 @@ -394,7 +400,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 &<| '(10,4.3333334),(5,1)'; ---------------------------------------------------- Index Only Scan using box_spgist on box_temp Index Cond: (f1 &<| '(10,4.3333334),(5,1)'::box) -(2 rows) + Settings: enable_seqscan = 'off' +(3 rows) SELECT * FROM box_temp WHERE f1 |&> '(49.99,49.99),(49.99,49.99)'; f1 @@ -408,7 +415,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 |&> '(49.99,49.99),(49.99,49 ----------------------------------------------------------- Index Only Scan using box_spgist on box_temp Index Cond: (f1 |&> '(49.99,49.99),(49.99,49.99)'::box) -(2 rows) + Settings: enable_seqscan = 'off' +(3 rows) SELECT * FROM box_temp WHERE f1 |>> '(37,38),(39,40)'; f1 @@ -431,7 +439,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 |>> '(37,38),(39,40)'; ----------------------------------------------- Index Only Scan using box_spgist on box_temp Index Cond: (f1 |>> '(39,40),(37,38)'::box) -(2 rows) + Settings: enable_seqscan = 'off' +(3 rows) SELECT * FROM box_temp WHERE f1 @> '(10,11),(15,16)'; f1 @@ -447,7 +456,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 @> '(10,11),(15,15)'; ---------------------------------------------- Index Only Scan using box_spgist on box_temp Index Cond: (f1 @> '(15,15),(10,11)'::box) -(2 rows) + Settings: enable_seqscan = 'off' +(3 rows) SELECT * FROM box_temp WHERE f1 <@ '(10,15),(30,35)'; f1 @@ -460,7 +470,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 <@ '(10,15),(30,35)'; ---------------------------------------------- Index Only Scan using box_spgist on box_temp Index Cond: (f1 <@ '(30,35),(10,15)'::box) -(2 rows) + Settings: enable_seqscan = 'off' +(3 rows) SELECT * FROM box_temp WHERE f1 ~= '(20,20),(40,40)'; f1 @@ -473,7 +484,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 ~= '(20,20),(40,40)'; ---------------------------------------------- Index Only Scan using box_spgist on box_temp Index Cond: (f1 ~= '(40,40),(20,20)'::box) -(2 rows) + Settings: enable_seqscan = 'off' +(3 rows) RESET enable_seqscan; DROP INDEX box_spgist; diff --git a/src/test/regress/expected/btree_index.out b/src/test/regress/expected/btree_index.out index acab8e0b11..e7121823a2 100644 --- a/src/test/regress/expected/btree_index.out +++ b/src/test/regress/expected/btree_index.out @@ -112,7 +112,8 @@ select proname from pg_proc where proname like E'RI\\_FKey%del' order by 1; Index Only Scan using pg_proc_proname_args_nsp_index on pg_proc Index Cond: ((proname >= 'RI_FKey'::text) AND (proname < 'RI_FKez'::text)) Filter: (proname ~~ 'RI\_FKey%del'::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) select proname from pg_proc where proname like E'RI\\_FKey%del' order by 1; proname @@ -131,7 +132,8 @@ select proname from pg_proc where proname ilike '00%foo' order by 1; Index Only Scan using pg_proc_proname_args_nsp_index on pg_proc Index Cond: ((proname >= '00'::text) AND (proname < '01'::text)) Filter: (proname ~~* '00%foo'::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) select proname from pg_proc where proname ilike '00%foo' order by 1; proname @@ -144,7 +146,8 @@ select proname from pg_proc where proname ilike 'ri%foo' order by 1; ----------------------------------------------------------------- Index Only Scan using pg_proc_proname_args_nsp_index on pg_proc Filter: (proname ~~* 'ri%foo'::text) -(2 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(3 rows) set enable_indexscan to false; set enable_bitmapscan to true; @@ -158,7 +161,8 @@ select proname from pg_proc where proname like E'RI\\_FKey%del' order by 1; Filter: (proname ~~ 'RI\_FKey%del'::text) -> Bitmap Index Scan on pg_proc_proname_args_nsp_index Index Cond: ((proname >= 'RI_FKey'::text) AND (proname < 'RI_FKez'::text)) -(6 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(7 rows) select proname from pg_proc where proname like E'RI\\_FKey%del' order by 1; proname @@ -180,7 +184,8 @@ select proname from pg_proc where proname ilike '00%foo' order by 1; Filter: (proname ~~* '00%foo'::text) -> Bitmap Index Scan on pg_proc_proname_args_nsp_index Index Cond: ((proname >= '00'::text) AND (proname < '01'::text)) -(6 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(7 rows) select proname from pg_proc where proname ilike '00%foo' order by 1; proname @@ -193,7 +198,8 @@ select proname from pg_proc where proname ilike 'ri%foo' order by 1; ----------------------------------------------------------------- Index Only Scan using pg_proc_proname_args_nsp_index on pg_proc Filter: (proname ~~* 'ri%foo'::text) -(2 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(3 rows) reset enable_seqscan; reset enable_indexscan; diff --git a/src/test/regress/expected/collate.out b/src/test/regress/expected/collate.out index 0dee7d783a..c3a390850b 100644 --- a/src/test/regress/expected/collate.out +++ b/src/test/regress/expected/collate.out @@ -626,7 +626,8 @@ EXPLAIN (COSTS OFF) Sort Sort Key: x COLLATE "C", y COLLATE "POSIX" -> Seq Scan on collate_test10 -(3 rows) + Settings: search_path = 'collate_tests' +(4 rows) EXPLAIN (COSTS OFF) SELECT * FROM collate_test10 ORDER BY x DESC, y COLLATE "C" ASC NULLS FIRST; @@ -635,7 +636,8 @@ EXPLAIN (COSTS OFF) Sort Sort Key: x COLLATE "C" DESC, y COLLATE "C" NULLS FIRST -> Seq Scan on collate_test10 -(3 rows) + Settings: search_path = 'collate_tests' +(4 rows) -- CREATE/DROP COLLATION CREATE COLLATION mycoll1 FROM "C"; diff --git a/src/test/regress/expected/create_am.out b/src/test/regress/expected/create_am.out index 352959b751..763ab8b2b6 100644 --- a/src/test/regress/expected/create_am.out +++ b/src/test/regress/expected/create_am.out @@ -54,7 +54,8 @@ SELECT * FROM fast_emp4000 Sort Key: ((home_base[0])[0]) -> Index Only Scan using grect2ind2 on fast_emp4000 Index Cond: (home_base @ '(2000,1000),(200,200)'::box) -(4 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(5 rows) SELECT * FROM fast_emp4000 WHERE home_base @ '(200,200),(2000,1000)'::box @@ -72,7 +73,8 @@ SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box; Aggregate -> Index Only Scan using grect2ind2 on fast_emp4000 Index Cond: (home_base && '(1000,1000),(0,0)'::box) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box; count @@ -82,12 +84,13 @@ SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box; EXPLAIN (COSTS OFF) SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL; - QUERY PLAN --------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using grect2ind2 on fast_emp4000 Index Cond: (home_base IS NULL) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL; count diff --git a/src/test/regress/expected/create_function_3.out b/src/test/regress/expected/create_function_3.out index ba260df996..55832d399c 100644 --- a/src/test/regress/expected/create_function_3.out +++ b/src/test/regress/expected/create_function_3.out @@ -303,11 +303,12 @@ SELECT voidtest2(11,22); -- currently, we can inline voidtest2 but not voidtest1 EXPLAIN (verbose, costs off) SELECT voidtest2(11,22); - QUERY PLAN -------------------------- + QUERY PLAN +-------------------------------------------------- Result Output: voidtest1(33) -(2 rows) + Settings: search_path = 'temp_func_test, public' +(3 rows) CREATE TEMP TABLE sometable(f1 int); CREATE FUNCTION voidtest3(a int) RETURNS VOID LANGUAGE SQL AS diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index c8bc6be061..e853c4ff82 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -267,7 +267,8 @@ SELECT * FROM fast_emp4000 Sort Key: ((home_base[0])[0]) -> Index Only Scan using grect2ind on fast_emp4000 Index Cond: (home_base @ '(2000,1000),(200,200)'::box) -(4 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(5 rows) SELECT * FROM fast_emp4000 WHERE home_base @ '(200,200),(2000,1000)'::box @@ -285,7 +286,8 @@ SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box; Aggregate -> Index Only Scan using grect2ind on fast_emp4000 Index Cond: (home_base && '(1000,1000),(0,0)'::box) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box; count @@ -295,12 +297,13 @@ SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box; EXPLAIN (COSTS OFF) SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using grect2ind on fast_emp4000 Index Cond: (home_base IS NULL) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL; count @@ -311,13 +314,14 @@ SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL; EXPLAIN (COSTS OFF) SELECT * FROM polygon_tbl WHERE f1 ~ '((1,1),(2,2),(2,1))'::polygon ORDER BY (poly_center(f1))[0]; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Sort Sort Key: ((poly_center(f1))[0]) -> Index Scan using gpolygonind on polygon_tbl Index Cond: (f1 ~ '((1,1),(2,2),(2,1))'::polygon) -(4 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(5 rows) SELECT * FROM polygon_tbl WHERE f1 ~ '((1,1),(2,2),(2,1))'::polygon ORDER BY (poly_center(f1))[0]; @@ -329,13 +333,14 @@ SELECT * FROM polygon_tbl WHERE f1 ~ '((1,1),(2,2),(2,1))'::polygon EXPLAIN (COSTS OFF) SELECT * FROM circle_tbl WHERE f1 && circle(point(1,-2), 1) ORDER BY area(f1); - QUERY PLAN --------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Sort Sort Key: (area(f1)) -> Index Scan using gcircleind on circle_tbl Index Cond: (f1 && '<(1,-2),1>'::circle) -(4 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(5 rows) SELECT * FROM circle_tbl WHERE f1 && circle(point(1,-2), 1) ORDER BY area(f1); @@ -349,12 +354,13 @@ SELECT * FROM circle_tbl WHERE f1 && circle(point(1,-2), 1) EXPLAIN (COSTS OFF) SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon; - QUERY PLAN ------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Scan using ggpolygonind on gpolygon_tbl Index Cond: (f1 && '((1000,1000),(0,0))'::polygon) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon; count @@ -364,12 +370,13 @@ SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon; EXPLAIN (COSTS OFF) SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Scan using ggcircleind on gcircle_tbl Index Cond: (f1 && '<(500,500),500>'::circle) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle; count @@ -379,12 +386,13 @@ SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle; EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)'; - QUERY PLAN ----------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using gpointind on point_tbl Index Cond: (f1 <@ '(100,100),(0,0)'::box) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)'; count @@ -394,12 +402,13 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1; - QUERY PLAN ----------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using gpointind on point_tbl Index Cond: (f1 <@ '(100,100),(0,0)'::box) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1; count @@ -414,7 +423,8 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50, Aggregate -> Index Only Scan using gpointind on point_tbl Index Cond: (f1 <@ '((0,0),(0,100),(100,100),(50,50),(100,0),(0,0))'::polygon) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)'; count @@ -424,12 +434,13 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50, EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>'; - QUERY PLAN ----------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using gpointind on point_tbl Index Cond: (f1 <@ '<(50,50),50>'::circle) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>'; count @@ -439,12 +450,13 @@ SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>'; EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)'; - QUERY PLAN ------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using gpointind on point_tbl p Index Cond: (f1 << '(0,0)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)'; count @@ -454,12 +466,13 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)'; - QUERY PLAN ------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using gpointind on point_tbl p Index Cond: (f1 >> '(0,0)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)'; count @@ -469,12 +482,13 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)'; - QUERY PLAN ------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using gpointind on point_tbl p Index Cond: (f1 <^ '(0,0)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)'; count @@ -484,12 +498,13 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)'; - QUERY PLAN ------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using gpointind on point_tbl p Index Cond: (f1 >^ '(0,0)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)'; count @@ -499,12 +514,13 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)'; - QUERY PLAN ------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using gpointind on point_tbl p Index Cond: (f1 ~= '(-5,-12)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)'; count @@ -514,11 +530,12 @@ SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)'; EXPLAIN (COSTS OFF) SELECT * FROM point_tbl ORDER BY f1 <-> '0,1'; - QUERY PLAN ----------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Index Only Scan using gpointind on point_tbl Order By: (f1 <-> '(0,1)'::point) -(2 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(3 rows) SELECT * FROM point_tbl ORDER BY f1 <-> '0,1'; f1 @@ -537,11 +554,12 @@ SELECT * FROM point_tbl ORDER BY f1 <-> '0,1'; EXPLAIN (COSTS OFF) SELECT * FROM point_tbl WHERE f1 IS NULL; - QUERY PLAN ----------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Index Only Scan using gpointind on point_tbl Index Cond: (f1 IS NULL) -(2 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(3 rows) SELECT * FROM point_tbl WHERE f1 IS NULL; f1 @@ -551,12 +569,13 @@ SELECT * FROM point_tbl WHERE f1 IS NULL; EXPLAIN (COSTS OFF) SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1'; - QUERY PLAN ----------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Index Only Scan using gpointind on point_tbl Index Cond: (f1 IS NOT NULL) Order By: (f1 <-> '(0,1)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1'; f1 @@ -574,12 +593,13 @@ SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1'; EXPLAIN (COSTS OFF) SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1'; - QUERY PLAN ------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Index Only Scan using gpointind on point_tbl Index Cond: (f1 <@ '(10,10),(-10,-10)'::box) Order By: (f1 <-> '(0,1)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1'; f1 @@ -593,12 +613,13 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0 EXPLAIN (COSTS OFF) SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10; - QUERY PLAN ------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Limit -> Index Scan using ggpolygonind on gpolygon_tbl Order By: (f1 <-> '(0,0)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10; f1 @@ -617,12 +638,13 @@ SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10; EXPLAIN (COSTS OFF) SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDER BY f1 <-> '(200,300)'::point LIMIT 10; - QUERY PLAN ---------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Limit -> Index Scan using ggcircleind on gcircle_tbl Order By: (f1 <-> '(200,300)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDER BY f1 <-> '(200,300)'::point LIMIT 10; circle_center | radius @@ -653,7 +675,8 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0 Recheck Cond: (f1 <@ '(10,10),(-10,-10)'::box) -> Bitmap Index Scan on gpointind Index Cond: (f1 <@ '(10,10),(-10,-10)'::box) -(6 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(7 rows) SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1'; f1 @@ -679,15 +702,16 @@ SET enable_bitmapscan = ON; CREATE INDEX intarrayidx ON array_index_op_test USING gin (i); explain (costs off) SELECT * FROM array_index_op_test WHERE i @> '{32}' ORDER BY seqno; - QUERY PLAN ----------------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Sort Sort Key: seqno -> Bitmap Heap Scan on array_index_op_test Recheck Cond: (i @> '{32}'::integer[]) -> Bitmap Index Scan on intarrayidx Index Cond: (i @> '{32}'::integer[]) -(6 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(7 rows) SELECT * FROM array_index_op_test WHERE i @> '{32}' ORDER BY seqno; seqno | i | t @@ -933,7 +957,8 @@ SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAAA72908}' ORDER BY seqno; Recheck Cond: (t @> '{AAAAAAAA72908}'::text[]) -> Bitmap Index Scan on textarrayidx Index Cond: (t @> '{AAAAAAAA72908}'::text[]) -(6 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(7 rows) SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAAA72908}' ORDER BY seqno; seqno | i | t @@ -1849,7 +1874,8 @@ ORDER BY thousand; Sort Key: thousand -> Index Scan using tenk1_thous_tenthous on tenk1 Index Cond: ((thousand < 2) AND (tenthous = ANY ('{1001,3000}'::integer[]))) -(4 rows) + Settings: enable_indexonlyscan = 'off' +(5 rows) SELECT thousand, tenthous FROM tenk1 WHERE thousand < 2 AND tenthous IN (1001,3000) diff --git a/src/test/regress/expected/create_index_spgist.out b/src/test/regress/expected/create_index_spgist.out index 81b4a67c39..21246bcc42 100644 --- a/src/test/regress/expected/create_index_spgist.out +++ b/src/test/regress/expected/create_index_spgist.out @@ -179,12 +179,13 @@ SET enable_indexscan = ON; SET enable_bitmapscan = OFF; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE p IS NULL; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_quad_ind on quad_point_tbl Index Cond: (p IS NULL) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM quad_point_tbl WHERE p IS NULL; count @@ -194,12 +195,13 @@ SELECT count(*) FROM quad_point_tbl WHERE p IS NULL; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_quad_ind on quad_point_tbl Index Cond: (p IS NOT NULL) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL; count @@ -209,11 +211,12 @@ SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_quad_ind on quad_point_tbl -(2 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(3 rows) SELECT count(*) FROM quad_point_tbl; count @@ -223,12 +226,13 @@ SELECT count(*) FROM quad_point_tbl; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)'; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_quad_ind on quad_point_tbl Index Cond: (p <@ '(1000,1000),(200,200)'::box) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)'; count @@ -238,12 +242,13 @@ SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_quad_ind on quad_point_tbl Index Cond: (p <@ '(1000,1000),(200,200)'::box) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p; count @@ -253,12 +258,13 @@ SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)'; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_quad_ind on quad_point_tbl Index Cond: (p << '(5000,4000)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)'; count @@ -268,12 +274,13 @@ SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)'; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_quad_ind on quad_point_tbl Index Cond: (p >> '(5000,4000)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)'; count @@ -283,12 +290,13 @@ SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)'; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_quad_ind on quad_point_tbl Index Cond: (p <^ '(5000,4000)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)'; count @@ -298,12 +306,13 @@ SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)'; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_quad_ind on quad_point_tbl Index Cond: (p >^ '(5000,4000)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)'; count @@ -313,12 +322,13 @@ SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)'; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_quad_ind on quad_point_tbl Index Cond: (p ~= '(4585,365)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)'; count @@ -329,12 +339,13 @@ SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)'; EXPLAIN (COSTS OFF) SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p FROM quad_point_tbl; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- WindowAgg -> Index Only Scan using sp_quad_ind on quad_point_tbl Order By: (p <-> '(0,0)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) CREATE TEMP TABLE quad_point_tbl_ord_idx1 AS SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p @@ -349,13 +360,14 @@ WHERE seq.dist IS DISTINCT FROM idx.dist; EXPLAIN (COSTS OFF) SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)'; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- WindowAgg -> Index Only Scan using sp_quad_ind on quad_point_tbl Index Cond: (p <@ '(1000,1000),(200,200)'::box) Order By: (p <-> '(0,0)'::point) -(4 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(5 rows) CREATE TEMP TABLE quad_point_tbl_ord_idx2 AS SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p @@ -370,13 +382,14 @@ WHERE seq.dist IS DISTINCT FROM idx.dist; EXPLAIN (COSTS OFF) SELECT row_number() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p FROM quad_point_tbl WHERE p IS NOT NULL; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- WindowAgg -> Index Only Scan using sp_quad_ind on quad_point_tbl Index Cond: (p IS NOT NULL) Order By: (p <-> '(333,400)'::point) -(4 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(5 rows) CREATE TEMP TABLE quad_point_tbl_ord_idx3 AS SELECT row_number() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p @@ -390,12 +403,13 @@ WHERE seq.dist IS DISTINCT FROM idx.dist; EXPLAIN (COSTS OFF) SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)'; - QUERY PLAN ---------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_kd_ind on kd_point_tbl Index Cond: (p <@ '(1000,1000),(200,200)'::box) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)'; count @@ -405,12 +419,13 @@ SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p; - QUERY PLAN ---------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_kd_ind on kd_point_tbl Index Cond: (p <@ '(1000,1000),(200,200)'::box) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p; count @@ -420,12 +435,13 @@ SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p; EXPLAIN (COSTS OFF) SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)'; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_kd_ind on kd_point_tbl Index Cond: (p << '(5000,4000)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)'; count @@ -435,12 +451,13 @@ SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)'; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_kd_ind on kd_point_tbl Index Cond: (p >> '(5000,4000)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)'; count @@ -450,12 +467,13 @@ SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)'; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_kd_ind on kd_point_tbl Index Cond: (p <^ '(5000,4000)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)'; count @@ -465,12 +483,13 @@ SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)'; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_kd_ind on kd_point_tbl Index Cond: (p >^ '(5000,4000)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)'; count @@ -480,12 +499,13 @@ SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)'; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_kd_ind on kd_point_tbl Index Cond: (p ~= '(4585,365)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)'; count @@ -496,12 +516,13 @@ SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)'; EXPLAIN (COSTS OFF) SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p FROM kd_point_tbl; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- WindowAgg -> Index Only Scan using sp_kd_ind on kd_point_tbl Order By: (p <-> '(0,0)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) CREATE TEMP TABLE kd_point_tbl_ord_idx1 AS SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p @@ -516,13 +537,14 @@ WHERE seq.dist IS DISTINCT FROM idx.dist; EXPLAIN (COSTS OFF) SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)'; - QUERY PLAN ---------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- WindowAgg -> Index Only Scan using sp_kd_ind on kd_point_tbl Index Cond: (p <@ '(1000,1000),(200,200)'::box) Order By: (p <-> '(0,0)'::point) -(4 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(5 rows) CREATE TEMP TABLE kd_point_tbl_ord_idx2 AS SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p @@ -537,13 +559,14 @@ WHERE seq.dist IS DISTINCT FROM idx.dist; EXPLAIN (COSTS OFF) SELECT row_number() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p FROM kd_point_tbl WHERE p IS NOT NULL; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- WindowAgg -> Index Only Scan using sp_kd_ind on kd_point_tbl Index Cond: (p IS NOT NULL) Order By: (p <-> '(333,400)'::point) -(4 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(5 rows) CREATE TEMP TABLE kd_point_tbl_ord_idx3 AS SELECT row_number() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p @@ -557,12 +580,13 @@ WHERE seq.dist IS DISTINCT FROM idx.dist; EXPLAIN (COSTS OFF) SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef'; - QUERY PLAN ------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_radix_ind on radix_text_tbl Index Cond: (t = 'P0123456789abcdef'::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef'; count @@ -572,12 +596,13 @@ SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef'; EXPLAIN (COSTS OFF) SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde'; - QUERY PLAN ------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_radix_ind on radix_text_tbl Index Cond: (t = 'P0123456789abcde'::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde'; count @@ -587,12 +612,13 @@ SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde'; EXPLAIN (COSTS OFF) SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF'; - QUERY PLAN ------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_radix_ind on radix_text_tbl Index Cond: (t = 'P0123456789abcdefF'::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF'; count @@ -607,7 +633,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Aggregate -> Index Only Scan using sp_radix_ind on radix_text_tbl Index Cond: (t < 'Aztec Ct '::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct '; count @@ -622,7 +649,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Aggregate -> Index Only Scan using sp_radix_ind on radix_text_tbl Index Cond: (t ~<~ 'Aztec Ct '::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct '; count @@ -637,7 +665,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Aggregate -> Index Only Scan using sp_radix_ind on radix_text_tbl Index Cond: (t <= 'Aztec Ct '::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct '; count @@ -652,7 +681,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Aggregate -> Index Only Scan using sp_radix_ind on radix_text_tbl Index Cond: (t ~<=~ 'Aztec Ct '::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct '; count @@ -667,7 +697,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Aggregate -> Index Only Scan using sp_radix_ind on radix_text_tbl Index Cond: (t = 'Aztec Ct '::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct '; count @@ -682,7 +713,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth Aggregate -> Index Only Scan using sp_radix_ind on radix_text_tbl Index Cond: (t = 'Worth St '::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St '; count @@ -697,7 +729,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth Aggregate -> Index Only Scan using sp_radix_ind on radix_text_tbl Index Cond: (t >= 'Worth St '::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St '; count @@ -712,7 +745,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth Aggregate -> Index Only Scan using sp_radix_ind on radix_text_tbl Index Cond: (t ~>=~ 'Worth St '::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St '; count @@ -727,7 +761,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth Aggregate -> Index Only Scan using sp_radix_ind on radix_text_tbl Index Cond: (t > 'Worth St '::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St '; count @@ -742,7 +777,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth Aggregate -> Index Only Scan using sp_radix_ind on radix_text_tbl Index Cond: (t ~>~ 'Worth St '::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St '; count @@ -752,12 +788,13 @@ SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth EXPLAIN (COSTS OFF) SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth'; - QUERY PLAN ------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Only Scan using sp_radix_ind on radix_text_tbl Index Cond: (t ^@ 'Worth'::text) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth'; count @@ -771,14 +808,15 @@ SET enable_indexscan = OFF; SET enable_bitmapscan = ON; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE p IS NULL; - QUERY PLAN ----------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on quad_point_tbl Recheck Cond: (p IS NULL) -> Bitmap Index Scan on sp_quad_ind Index Cond: (p IS NULL) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_point_tbl WHERE p IS NULL; count @@ -788,14 +826,15 @@ SELECT count(*) FROM quad_point_tbl WHERE p IS NULL; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL; - QUERY PLAN ----------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on quad_point_tbl Recheck Cond: (p IS NOT NULL) -> Bitmap Index Scan on sp_quad_ind Index Cond: (p IS NOT NULL) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL; count @@ -805,12 +844,13 @@ SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl; - QUERY PLAN ----------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on quad_point_tbl -> Bitmap Index Scan on sp_quad_ind -(3 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM quad_point_tbl; count @@ -827,7 +867,8 @@ SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)'; Recheck Cond: (p <@ '(1000,1000),(200,200)'::box) -> Bitmap Index Scan on sp_quad_ind Index Cond: (p <@ '(1000,1000),(200,200)'::box) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)'; count @@ -844,7 +885,8 @@ SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p; Recheck Cond: ('(1000,1000),(200,200)'::box @> p) -> Bitmap Index Scan on sp_quad_ind Index Cond: (p <@ '(1000,1000),(200,200)'::box) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p; count @@ -854,14 +896,15 @@ SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)'; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on quad_point_tbl Recheck Cond: (p << '(5000,4000)'::point) -> Bitmap Index Scan on sp_quad_ind Index Cond: (p << '(5000,4000)'::point) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)'; count @@ -871,14 +914,15 @@ SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)'; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on quad_point_tbl Recheck Cond: (p >> '(5000,4000)'::point) -> Bitmap Index Scan on sp_quad_ind Index Cond: (p >> '(5000,4000)'::point) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)'; count @@ -888,14 +932,15 @@ SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)'; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on quad_point_tbl Recheck Cond: (p <^ '(5000,4000)'::point) -> Bitmap Index Scan on sp_quad_ind Index Cond: (p <^ '(5000,4000)'::point) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)'; count @@ -905,14 +950,15 @@ SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)'; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on quad_point_tbl Recheck Cond: (p >^ '(5000,4000)'::point) -> Bitmap Index Scan on sp_quad_ind Index Cond: (p >^ '(5000,4000)'::point) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)'; count @@ -922,14 +968,15 @@ SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)'; - QUERY PLAN ------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on quad_point_tbl Recheck Cond: (p ~= '(4585,365)'::point) -> Bitmap Index Scan on sp_quad_ind Index Cond: (p ~= '(4585,365)'::point) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)'; count @@ -946,7 +993,8 @@ SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)'; Recheck Cond: (p <@ '(1000,1000),(200,200)'::box) -> Bitmap Index Scan on sp_kd_ind Index Cond: (p <@ '(1000,1000),(200,200)'::box) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)'; count @@ -963,7 +1011,8 @@ SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p; Recheck Cond: ('(1000,1000),(200,200)'::box @> p) -> Bitmap Index Scan on sp_kd_ind Index Cond: (p <@ '(1000,1000),(200,200)'::box) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p; count @@ -973,14 +1022,15 @@ SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p; EXPLAIN (COSTS OFF) SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)'; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on kd_point_tbl Recheck Cond: (p << '(5000,4000)'::point) -> Bitmap Index Scan on sp_kd_ind Index Cond: (p << '(5000,4000)'::point) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)'; count @@ -990,14 +1040,15 @@ SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)'; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on kd_point_tbl Recheck Cond: (p >> '(5000,4000)'::point) -> Bitmap Index Scan on sp_kd_ind Index Cond: (p >> '(5000,4000)'::point) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)'; count @@ -1007,14 +1058,15 @@ SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)'; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on kd_point_tbl Recheck Cond: (p <^ '(5000,4000)'::point) -> Bitmap Index Scan on sp_kd_ind Index Cond: (p <^ '(5000,4000)'::point) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)'; count @@ -1024,14 +1076,15 @@ SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)'; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on kd_point_tbl Recheck Cond: (p >^ '(5000,4000)'::point) -> Bitmap Index Scan on sp_kd_ind Index Cond: (p >^ '(5000,4000)'::point) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)'; count @@ -1041,14 +1094,15 @@ SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)'; - QUERY PLAN ------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on kd_point_tbl Recheck Cond: (p ~= '(4585,365)'::point) -> Bitmap Index Scan on sp_kd_ind Index Cond: (p ~= '(4585,365)'::point) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)'; count @@ -1058,14 +1112,15 @@ SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)'; EXPLAIN (COSTS OFF) SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef'; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on radix_text_tbl Recheck Cond: (t = 'P0123456789abcdef'::text) -> Bitmap Index Scan on sp_radix_ind Index Cond: (t = 'P0123456789abcdef'::text) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef'; count @@ -1075,14 +1130,15 @@ SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef'; EXPLAIN (COSTS OFF) SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde'; - QUERY PLAN ----------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on radix_text_tbl Recheck Cond: (t = 'P0123456789abcde'::text) -> Bitmap Index Scan on sp_radix_ind Index Cond: (t = 'P0123456789abcde'::text) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde'; count @@ -1099,7 +1155,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF'; Recheck Cond: (t = 'P0123456789abcdefF'::text) -> Bitmap Index Scan on sp_radix_ind Index Cond: (t = 'P0123456789abcdefF'::text) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF'; count @@ -1116,7 +1173,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Recheck Cond: (t < 'Aztec Ct '::text) -> Bitmap Index Scan on sp_radix_ind Index Cond: (t < 'Aztec Ct '::text) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct '; count @@ -1133,7 +1191,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Recheck Cond: (t ~<~ 'Aztec Ct '::text) -> Bitmap Index Scan on sp_radix_ind Index Cond: (t ~<~ 'Aztec Ct '::text) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct '; count @@ -1150,7 +1209,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Recheck Cond: (t <= 'Aztec Ct '::text) -> Bitmap Index Scan on sp_radix_ind Index Cond: (t <= 'Aztec Ct '::text) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct '; count @@ -1167,7 +1227,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Recheck Cond: (t ~<=~ 'Aztec Ct '::text) -> Bitmap Index Scan on sp_radix_ind Index Cond: (t ~<=~ 'Aztec Ct '::text) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct '; count @@ -1184,7 +1245,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Recheck Cond: (t = 'Aztec Ct '::text) -> Bitmap Index Scan on sp_radix_ind Index Cond: (t = 'Aztec Ct '::text) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct '; count @@ -1201,7 +1263,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth Recheck Cond: (t = 'Worth St '::text) -> Bitmap Index Scan on sp_radix_ind Index Cond: (t = 'Worth St '::text) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St '; count @@ -1218,7 +1281,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth Recheck Cond: (t >= 'Worth St '::text) -> Bitmap Index Scan on sp_radix_ind Index Cond: (t >= 'Worth St '::text) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St '; count @@ -1235,7 +1299,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth Recheck Cond: (t ~>=~ 'Worth St '::text) -> Bitmap Index Scan on sp_radix_ind Index Cond: (t ~>=~ 'Worth St '::text) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St '; count @@ -1252,7 +1317,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth Recheck Cond: (t > 'Worth St '::text) -> Bitmap Index Scan on sp_radix_ind Index Cond: (t > 'Worth St '::text) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St '; count @@ -1269,7 +1335,8 @@ SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth Recheck Cond: (t ~>~ 'Worth St '::text) -> Bitmap Index Scan on sp_radix_ind Index Cond: (t ~>~ 'Worth St '::text) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St '; count @@ -1279,14 +1346,15 @@ SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth EXPLAIN (COSTS OFF) SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth'; - QUERY PLAN ------------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Aggregate -> Bitmap Heap Scan on radix_text_tbl Recheck Cond: (t ^@ 'Worth'::text) -> Bitmap Index Scan on sp_radix_ind Index Cond: (t ^@ 'Worth'::text) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth'; count diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out index e367ea2571..1ac8427c04 100644 --- a/src/test/regress/expected/create_view.out +++ b/src/test/regress/expected/create_view.out @@ -1602,7 +1602,8 @@ explain (costs off) select * from tt18v; Append -> Seq Scan on int8_tbl xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -> Seq Scan on int8_tbl xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_1 -(3 rows) + Settings: search_path = 'testviewschm2, public' +(4 rows) -- check display of ScalarArrayOp with a sub-select select 'foo'::text = any(array['abc','def','foo']::text[]); diff --git a/src/test/regress/expected/equivclass.out b/src/test/regress/expected/equivclass.out index c448d85dec..e15374d72b 100644 --- a/src/test/regress/expected/equivclass.out +++ b/src/test/regress/expected/equivclass.out @@ -104,38 +104,42 @@ set enable_mergejoin = off; -- explain (costs off) select * from ec0 where ff = f1 and f1 = '42'::int8; - QUERY PLAN ------------------------------------ + QUERY PLAN +------------------------------------------------------------- Index Scan using ec0_pkey on ec0 Index Cond: (ff = '42'::bigint) Filter: (f1 = '42'::bigint) -(3 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(4 rows) explain (costs off) select * from ec0 where ff = f1 and f1 = '42'::int8alias1; - QUERY PLAN ---------------------------------------- + QUERY PLAN +------------------------------------------------------------- Index Scan using ec0_pkey on ec0 Index Cond: (ff = '42'::int8alias1) Filter: (f1 = '42'::int8alias1) -(3 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(4 rows) explain (costs off) select * from ec1 where ff = f1 and f1 = '42'::int8alias1; - QUERY PLAN ---------------------------------------- + QUERY PLAN +------------------------------------------------------------- Index Scan using ec1_pkey on ec1 Index Cond: (ff = '42'::int8alias1) Filter: (f1 = '42'::int8alias1) -(3 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(4 rows) explain (costs off) select * from ec1 where ff = f1 and f1 = '42'::int8alias2; - QUERY PLAN ---------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Seq Scan on ec1 Filter: ((ff = f1) AND (f1 = '42'::int8alias2)) -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(3 rows) explain (costs off) select * from ec1, ec2 where ff = x1 and ff = '42'::int8; @@ -146,52 +150,57 @@ explain (costs off) -> Index Scan using ec1_pkey on ec1 Index Cond: ((ff = '42'::bigint) AND (ff = '42'::bigint)) -> Seq Scan on ec2 -(5 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(6 rows) explain (costs off) select * from ec1, ec2 where ff = x1 and ff = '42'::int8alias1; - QUERY PLAN ---------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Nested Loop -> Index Scan using ec1_pkey on ec1 Index Cond: (ff = '42'::int8alias1) -> Seq Scan on ec2 Filter: (x1 = '42'::int8alias1) -(5 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(6 rows) explain (costs off) select * from ec1, ec2 where ff = x1 and '42'::int8 = x1; - QUERY PLAN ------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Nested Loop Join Filter: (ec1.ff = ec2.x1) -> Index Scan using ec1_pkey on ec1 Index Cond: (ff = '42'::bigint) -> Seq Scan on ec2 Filter: ('42'::bigint = x1) -(6 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(7 rows) explain (costs off) select * from ec1, ec2 where ff = x1 and x1 = '42'::int8alias1; - QUERY PLAN ---------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Nested Loop -> Index Scan using ec1_pkey on ec1 Index Cond: (ff = '42'::int8alias1) -> Seq Scan on ec2 Filter: (x1 = '42'::int8alias1) -(5 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(6 rows) explain (costs off) select * from ec1, ec2 where ff = x1 and x1 = '42'::int8alias2; - QUERY PLAN ------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Nested Loop -> Seq Scan on ec2 Filter: (x1 = '42'::int8alias2) -> Index Scan using ec1_pkey on ec1 Index Cond: (ff = ec2.x1) -(5 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(6 rows) create unique index ec1_expr1 on ec1((ff + 1)); create unique index ec1_expr2 on ec1((ff + 2 + 1)); @@ -206,8 +215,8 @@ explain (costs off) union all select ff + 4 as x from ec1) as ss1 where ss1.x = ec1.f1 and ec1.ff = 42::int8; - QUERY PLAN ------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Nested Loop -> Index Scan using ec1_pkey on ec1 Index Cond: (ff = '42'::bigint) @@ -218,7 +227,8 @@ explain (costs off) Index Cond: (((ff + 3) + 1) = ec1.f1) -> Index Scan using ec1_expr4 on ec1 ec1_3 Index Cond: ((ff + 4) = ec1.f1) -(10 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(11 rows) explain (costs off) select * from ec1, @@ -243,7 +253,8 @@ explain (costs off) Index Cond: (((ff + 3) + 1) = '42'::bigint) -> Index Scan using ec1_expr4 on ec1 ec1_3 Index Cond: ((ff + 4) = '42'::bigint) -(12 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(13 rows) explain (costs off) select * from ec1, @@ -280,7 +291,8 @@ explain (costs off) Index Cond: (((ff + 3) + 1) = (((ec1_1.ff + 2) + 1))) -> Index Scan using ec1_expr4 on ec1 ec1_6 Index Cond: ((ff + 4) = (((ec1_1.ff + 2) + 1))) -(18 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(19 rows) -- let's try that as a mergejoin set enable_mergejoin = on; @@ -321,7 +333,8 @@ explain (costs off) Sort Key: ec1.f1 USING < -> Index Scan using ec1_pkey on ec1 Index Cond: (ff = '42'::bigint) -(19 rows) + Settings: enable_hashjoin = 'off', enable_nestloop = 'off' +(20 rows) -- check partially indexed scan set enable_nestloop = on; @@ -336,8 +349,8 @@ explain (costs off) union all select ff + 4 as x from ec1) as ss1 where ss1.x = ec1.f1 and ec1.ff = 42::int8; - QUERY PLAN ------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------- Nested Loop -> Index Scan using ec1_pkey on ec1 Index Cond: (ff = '42'::bigint) @@ -348,7 +361,8 @@ explain (costs off) Filter: (((ff + 3) + 1) = ec1.f1) -> Index Scan using ec1_expr4 on ec1 ec1_3 Index Cond: ((ff + 4) = ec1.f1) -(10 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(11 rows) -- let's try that as a mergejoin set enable_mergejoin = on; @@ -362,8 +376,8 @@ explain (costs off) union all select ff + 4 as x from ec1) as ss1 where ss1.x = ec1.f1 and ec1.ff = 42::int8; - QUERY PLAN ------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------ Merge Join Merge Cond: ((((ec1_1.ff + 2) + 1)) = ec1.f1) -> Merge Append @@ -377,7 +391,8 @@ explain (costs off) Sort Key: ec1.f1 USING < -> Index Scan using ec1_pkey on ec1 Index Cond: (ff = '42'::bigint) -(13 rows) + Settings: enable_hashjoin = 'off', enable_nestloop = 'off' +(14 rows) -- check effects of row-level security set enable_nestloop = on; @@ -391,14 +406,15 @@ grant select on ec1 to regress_user_ectest; explain (costs off) select * from ec0 a, ec1 b where a.ff = b.ff and a.ff = 43::bigint::int8alias1; - QUERY PLAN ---------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Nested Loop -> Index Scan using ec0_pkey on ec0 a Index Cond: (ff = '43'::int8alias1) -> Index Scan using ec1_pkey on ec1 b Index Cond: (ff = '43'::int8alias1) -(5 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(6 rows) set session authorization regress_user_ectest; -- with RLS active, the non-leakproof a.ff = 43 clause is not treated @@ -407,15 +423,16 @@ set session authorization regress_user_ectest; explain (costs off) select * from ec0 a, ec1 b where a.ff = b.ff and a.ff = 43::bigint::int8alias1; - QUERY PLAN ---------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Nested Loop -> Index Scan using ec0_pkey on ec0 a Index Cond: (ff = '43'::int8alias1) -> Index Scan using ec1_pkey on ec1 b Index Cond: (ff = a.ff) Filter: (f1 < '5'::int8alias1) -(6 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(7 rows) reset session authorization; revoke select on ec0 from regress_user_ectest; @@ -428,14 +445,16 @@ explain (costs off) ------------------------------------------------------------- Seq Scan on tenk1 Filter: ((unique1 IS NOT NULL) AND (unique2 IS NOT NULL)) -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(3 rows) -- this could be converted, but isn't at present explain (costs off) select * from tenk1 where unique1 = unique1 or unique2 = unique2; - QUERY PLAN --------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Seq Scan on tenk1 Filter: ((unique1 = unique1) OR (unique2 = unique2)) -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(3 rows) diff --git a/src/test/regress/expected/fast_default.out b/src/test/regress/expected/fast_default.out index 10bc5ff757..261bd47805 100644 --- a/src/test/regress/expected/fast_default.out +++ b/src/test/regress/expected/fast_default.out @@ -302,7 +302,8 @@ SELECT c_bigint, c_text FROM T WHERE c_bigint = -1 LIMIT 1; -> Seq Scan on fast_default.t Output: c_bigint, c_text Filter: (t.c_bigint = '-1'::integer) -(5 rows) + Settings: search_path = 'fast_default' +(6 rows) SELECT c_bigint, c_text FROM T WHERE c_text = 'hello' LIMIT 1; c_bigint | c_text @@ -318,7 +319,8 @@ EXPLAIN (VERBOSE TRUE, COSTS FALSE) SELECT c_bigint, c_text FROM T WHERE c_text -> Seq Scan on fast_default.t Output: c_bigint, c_text Filter: (t.c_text = 'hello'::text) -(5 rows) + Settings: search_path = 'fast_default' +(6 rows) -- COALESCE SELECT COALESCE(c_bigint, pk), COALESCE(c_text, pk::text) @@ -372,7 +374,8 @@ SELECT * FROM T ORDER BY c_bigint, c_text, pk LIMIT 10; Sort Key: t.c_bigint, t.c_text, t.pk -> Seq Scan on fast_default.t Output: pk, c_bigint, c_text -(7 rows) + Settings: search_path = 'fast_default' +(8 rows) -- LIMIT SELECT * FROM T WHERE c_bigint > -1 ORDER BY c_bigint, c_text, pk LIMIT 10; @@ -402,7 +405,8 @@ SELECT * FROM T WHERE c_bigint > -1 ORDER BY c_bigint, c_text, pk LIMIT 10; -> Seq Scan on fast_default.t Output: pk, c_bigint, c_text Filter: (t.c_bigint > '-1'::integer) -(8 rows) + Settings: search_path = 'fast_default' +(9 rows) -- DELETE with RETURNING DELETE FROM T WHERE pk BETWEEN 10 AND 20 RETURNING *; @@ -432,7 +436,8 @@ DELETE FROM T WHERE pk BETWEEN 10 AND 20 RETURNING *; Recheck Cond: ((t.pk >= 10) AND (t.pk <= 20)) -> Bitmap Index Scan on t_pkey Index Cond: ((t.pk >= 10) AND (t.pk <= 20)) -(7 rows) + Settings: search_path = 'fast_default' +(8 rows) -- UPDATE UPDATE T SET c_text = '"' || c_text || '"' WHERE pk < 10; diff --git a/src/test/regress/expected/generated.out b/src/test/regress/expected/generated.out index d4ed3f7ae1..bb14be3b14 100644 --- a/src/test/regress/expected/generated.out +++ b/src/test/regress/expected/generated.out @@ -436,11 +436,12 @@ INSERT INTO gtest22c VALUES (1), (2), (3); SET enable_seqscan TO off; SET enable_bitmapscan TO off; EXPLAIN (COSTS OFF) SELECT * FROM gtest22c WHERE b = 4; - QUERY PLAN ---------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Index Scan using gtest22c_b_idx on gtest22c Index Cond: (b = 4) -(2 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(3 rows) SELECT * FROM gtest22c WHERE b = 4; a | b @@ -449,11 +450,12 @@ SELECT * FROM gtest22c WHERE b = 4; (1 row) EXPLAIN (COSTS OFF) SELECT * FROM gtest22c WHERE b * 3 = 6; - QUERY PLAN ------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Index Scan using gtest22c_expr_idx on gtest22c Index Cond: ((b * 3) = 6) -(2 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(3 rows) SELECT * FROM gtest22c WHERE b * 3 = 6; a | b @@ -462,11 +464,12 @@ SELECT * FROM gtest22c WHERE b * 3 = 6; (1 row) EXPLAIN (COSTS OFF) SELECT * FROM gtest22c WHERE a = 1 AND b > 0; - QUERY PLAN ------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Index Scan using gtest22c_pred_idx on gtest22c Index Cond: (a = 1) -(2 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(3 rows) SELECT * FROM gtest22c WHERE a = 1 AND b > 0; a | b diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index 0a43449f00..f716b4825e 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -51,11 +51,12 @@ create index gist_tbl_point_index on gist_tbl using gist (p); -- check that the planner chooses an index-only scan explain (costs off) select p from gist_tbl where p <@ box(point(0,0), point(0.5, 0.5)); - QUERY PLAN --------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Index Only Scan using gist_tbl_point_index on gist_tbl Index Cond: (p <@ '(0.5,0.5),(0,0)'::box) -(2 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(3 rows) -- execute the same select p from gist_tbl where p <@ box(point(0,0), point(0.5, 0.5)); @@ -78,12 +79,13 @@ select p from gist_tbl where p <@ box(point(0,0), point(0.5, 0.5)); explain (costs off) select p from gist_tbl where p <@ box(point(0,0), point(0.5, 0.5)) order by p <-> point(0.201, 0.201); - QUERY PLAN --------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Index Only Scan using gist_tbl_point_index on gist_tbl Index Cond: (p <@ '(0.5,0.5),(0,0)'::box) Order By: (p <-> '(0.201,0.201)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) select p from gist_tbl where p <@ box(point(0,0), point(0.5, 0.5)) order by p <-> point(0.201, 0.201); @@ -106,12 +108,13 @@ order by p <-> point(0.201, 0.201); explain (costs off) select p from gist_tbl where p <@ box(point(0,0), point(0.5, 0.5)) order by point(0.101, 0.101) <-> p; - QUERY PLAN --------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Index Only Scan using gist_tbl_point_index on gist_tbl Index Cond: (p <@ '(0.5,0.5),(0,0)'::box) Order By: (p <-> '(0.101,0.101)'::point) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) select p from gist_tbl where p <@ box(point(0,0), point(0.5, 0.5)) order by point(0.101, 0.101) <-> p; @@ -146,7 +149,8 @@ cross join lateral -> Index Only Scan using gist_tbl_point_index on gist_tbl Index Cond: (p <@ "*VALUES*".column1) Order By: (p <-> ("*VALUES*".column1)[0]) -(6 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(7 rows) select p from (values (box(point(0,0), point(0.5,0.5))), @@ -170,11 +174,12 @@ create index gist_tbl_box_index on gist_tbl using gist (b); -- check that the planner chooses an index-only scan explain (costs off) select b from gist_tbl where b <@ box(point(5,5), point(6,6)); - QUERY PLAN ------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Index Only Scan using gist_tbl_box_index on gist_tbl Index Cond: (b <@ '(6,6),(5,5)'::box) -(2 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(3 rows) -- execute the same select b from gist_tbl where b <@ box(point(5,5), point(6,6)); @@ -210,11 +215,12 @@ create index gist_tbl_multi_index on gist_tbl using gist (p, c); explain (costs off) select p, c from gist_tbl where p <@ box(point(5,5), point(6, 6)); - QUERY PLAN ---------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Index Scan using gist_tbl_multi_index on gist_tbl Index Cond: (p <@ '(6,6),(5,5)'::box) -(2 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(3 rows) -- execute the same select b, p from gist_tbl diff --git a/src/test/regress/expected/groupingsets.out b/src/test/regress/expected/groupingsets.out index 381ebce8a1..792ca82443 100644 --- a/src/test/regress/expected/groupingsets.out +++ b/src/test/regress/expected/groupingsets.out @@ -374,7 +374,8 @@ select g as alias1, g as alias2 -> Sort Sort Key: g -> Function Scan on generate_series g -(6 rows) + Settings: enable_hashagg = 'off' +(7 rows) select g as alias1, g as alias2 from generate_series(1,3) g @@ -467,7 +468,8 @@ explain (costs off) -> Limit -> Index Only Scan using tenk1_unique1 on tenk1 Index Cond: (unique1 IS NOT NULL) -(5 rows) + Settings: enable_hashagg = 'off' +(6 rows) -- Views with GROUPING SET queries CREATE VIEW gstest_view AS select a, b, grouping(a,b), sum(c), count(*), max(c) @@ -716,7 +718,8 @@ explain (costs off) -> Sort Sort Key: a -> Seq Scan on gstest2 -(7 rows) + Settings: enable_hashagg = 'off' +(8 rows) select v.c, (select count(*) from gstest2 group by () having v.c) from (values (false),(true)) v(c) order by v.c; @@ -741,7 +744,8 @@ explain (costs off) -> Result One-Time Filter: "*VALUES*".column1 -> Seq Scan on gstest2 -(10 rows) + Settings: enable_hashagg = 'off' +(11 rows) -- HAVING with GROUPING queries select ten, grouping(ten) from onek @@ -1481,8 +1485,8 @@ explain (costs off) count(hundred), count(thousand), count(twothousand), count(*) from tenk1 group by grouping sets (unique1,twothousand,thousand,hundred,ten,four,two); - QUERY PLAN -------------------------------- + QUERY PLAN +------------------------------------------------------- MixedAggregate Hash Key: two Hash Key: four @@ -1496,7 +1500,8 @@ explain (costs off) -> Sort Sort Key: unique1 -> Seq Scan on tenk1 -(13 rows) + Settings: enable_indexscan = 'off', work_mem = '64kB' +(14 rows) explain (costs off) select unique1, @@ -1504,8 +1509,8 @@ explain (costs off) count(hundred), count(thousand), count(twothousand), count(*) from tenk1 group by grouping sets (unique1,hundred,ten,four,two); - QUERY PLAN -------------------------------- + QUERY PLAN +------------------------------------------------------- MixedAggregate Hash Key: two Hash Key: four @@ -1515,7 +1520,8 @@ explain (costs off) -> Sort Sort Key: unique1 -> Seq Scan on tenk1 -(9 rows) + Settings: enable_indexscan = 'off', work_mem = '64kB' +(10 rows) set work_mem = '384kB'; explain (costs off) @@ -1524,8 +1530,8 @@ explain (costs off) count(hundred), count(thousand), count(twothousand), count(*) from tenk1 group by grouping sets (unique1,twothousand,thousand,hundred,ten,four,two); - QUERY PLAN -------------------------------- + QUERY PLAN +-------------------------------------------------------- MixedAggregate Hash Key: two Hash Key: four @@ -1538,7 +1544,8 @@ explain (costs off) -> Sort Sort Key: unique1 -> Seq Scan on tenk1 -(12 rows) + Settings: enable_indexscan = 'off', work_mem = '384kB' +(13 rows) -- check collation-sensitive matching between grouping expressions -- (similar to a check for aggregates, but there are additional code diff --git a/src/test/regress/expected/index_including.out b/src/test/regress/expected/index_including.out index 2405709f40..0b712c289c 100644 --- a/src/test/regress/expected/index_including.out +++ b/src/test/regress/expected/index_including.out @@ -154,7 +154,8 @@ select * from tbl where (c1,c2,c3) < (262,1,1) limit 1; -> Index Only Scan using covering on tbl Index Cond: (ROW(c1, c2) <= ROW(262, 1)) Filter: (ROW(c1, c2, c3) < ROW(262, 1, 1)) -(4 rows) + Settings: enable_seqscan = 'off' +(5 rows) select * from tbl where (c1,c2,c3) < (262,1,1) limit 1; c1 | c2 | c3 | c4 diff --git a/src/test/regress/expected/index_including_gist.out b/src/test/regress/expected/index_including_gist.out index ed9906da66..f013380ce9 100644 --- a/src/test/regress/expected/index_including_gist.out +++ b/src/test/regress/expected/index_including_gist.out @@ -29,7 +29,8 @@ EXPLAIN (costs off) SELECT * FROM tbl_gist where c4 <@ box(point(1,1),point(10, ------------------------------------------------ Index Only Scan using tbl_gist_idx on tbl_gist Index Cond: (c4 <@ '(10,10),(1,1)'::box) -(2 rows) + Settings: enable_bitmapscan = 'off' +(3 rows) SET enable_bitmapscan TO default; DROP TABLE tbl_gist; @@ -64,7 +65,8 @@ EXPLAIN (costs off) SELECT * FROM tbl_gist where c4 <@ box(point(1,1),point(10, ------------------------------------------------ Index Only Scan using tbl_gist_idx on tbl_gist Index Cond: (c4 <@ '(10,10),(1,1)'::box) -(2 rows) + Settings: enable_bitmapscan = 'off' +(3 rows) SET enable_bitmapscan TO default; DROP TABLE tbl_gist; diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out index 24202376f1..58af8d5564 100644 --- a/src/test/regress/expected/inet.out +++ b/src/test/regress/expected/inet.out @@ -249,7 +249,8 @@ SELECT * FROM inet_tbl WHERE i<<'192.168.1.0/24'::cidr; Index Scan using inet_idx1 on inet_tbl Index Cond: ((i > '192.168.1.0/24'::inet) AND (i <= '192.168.1.255'::inet)) Filter: (i << '192.168.1.0/24'::inet) -(3 rows) + Settings: enable_seqscan = 'off' +(4 rows) SELECT * FROM inet_tbl WHERE i<<'192.168.1.0/24'::cidr; c | i @@ -266,7 +267,8 @@ SELECT * FROM inet_tbl WHERE i<<='192.168.1.0/24'::cidr; Index Scan using inet_idx1 on inet_tbl Index Cond: ((i >= '192.168.1.0/24'::inet) AND (i <= '192.168.1.255'::inet)) Filter: (i <<= '192.168.1.0/24'::inet) -(3 rows) + Settings: enable_seqscan = 'off' +(4 rows) SELECT * FROM inet_tbl WHERE i<<='192.168.1.0/24'::cidr; c | i @@ -286,7 +288,8 @@ SELECT * FROM inet_tbl WHERE '192.168.1.0/24'::cidr >>= i; Index Scan using inet_idx1 on inet_tbl Index Cond: ((i >= '192.168.1.0/24'::inet) AND (i <= '192.168.1.255'::inet)) Filter: ('192.168.1.0/24'::inet >>= i) -(3 rows) + Settings: enable_seqscan = 'off' +(4 rows) SELECT * FROM inet_tbl WHERE '192.168.1.0/24'::cidr >>= i; c | i @@ -306,7 +309,8 @@ SELECT * FROM inet_tbl WHERE '192.168.1.0/24'::cidr >> i; Index Scan using inet_idx1 on inet_tbl Index Cond: ((i > '192.168.1.0/24'::inet) AND (i <= '192.168.1.255'::inet)) Filter: ('192.168.1.0/24'::inet >> i) -(3 rows) + Settings: enable_seqscan = 'off' +(4 rows) SELECT * FROM inet_tbl WHERE '192.168.1.0/24'::cidr >> i; c | i @@ -454,7 +458,8 @@ SELECT i FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i; Sort Key: i -> Index Only Scan using inet_idx2 on inet_tbl Index Cond: (i << '192.168.1.0/24'::inet) -(4 rows) + Settings: enable_seqscan = 'off' +(5 rows) SELECT i FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i; i @@ -602,7 +607,8 @@ SELECT i FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i; Sort Key: i -> Index Only Scan using inet_idx3 on inet_tbl Index Cond: (i << '192.168.1.0/24'::inet) -(4 rows) + Settings: enable_seqscan = 'off' +(5 rows) SELECT i FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i; i diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index c6abcfc3cb..a30ff26734 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -1411,7 +1411,8 @@ explain (verbose, costs off) select * from matest0 order by 1-id; Output: matest2.id, matest2.name -> Seq Scan on public.matest3 Output: matest3.id, matest3.name -(14 rows) + Settings: enable_indexscan = 'off' +(15 rows) select * from matest0 order by 1-id; id | name @@ -1438,7 +1439,8 @@ explain (verbose, costs off) select min(1-id) from matest0; Output: matest2.id -> Seq Scan on public.matest3 Output: matest3.id -(11 rows) + Settings: enable_indexscan = 'off' +(12 rows) select min(1-id) from matest0; min @@ -1465,7 +1467,8 @@ explain (verbose, costs off) select * from matest0 order by 1-id; Output: matest2.id, matest2.name, (1 - matest2.id) -> Index Scan using matest3i on public.matest3 Output: matest3.id, matest3.name, (1 - matest3.id) -(13 rows) + Settings: enable_parallel_append = 'off', enable_seqscan = 'off' +(14 rows) select * from matest0 order by 1-id; id | name @@ -1506,7 +1509,8 @@ explain (verbose, costs off) select min(1-id) from matest0; -> Index Scan using matest3i on public.matest3 Output: matest3.id, (1 - matest3.id) Index Cond: ((1 - matest3.id) IS NOT NULL) -(25 rows) + Settings: enable_parallel_append = 'off', enable_seqscan = 'off' +(26 rows) select min(1-id) from matest0; min @@ -1550,7 +1554,8 @@ order by t1.b limit 10; Filter: (c = d) -> Index Scan using matest1i on matest1 t2_1 Filter: (c = d) -(14 rows) + Settings: enable_nestloop = 'off' +(15 rows) reset enable_nestloop; drop table matest0 cascade; @@ -1575,7 +1580,8 @@ ORDER BY thousand, tenthous; -> Sort Sort Key: tenk1_1.thousand, tenk1_1.thousand -> Index Only Scan using tenk1_thous_tenthous on tenk1 tenk1_1 -(6 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(7 rows) explain (costs off) SELECT thousand, tenthous, thousand+tenthous AS x FROM tenk1 @@ -1590,7 +1596,8 @@ ORDER BY thousand, tenthous; -> Sort Sort Key: 42, 42 -> Index Only Scan using tenk1_hundred on tenk1 tenk1_1 -(6 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(7 rows) explain (costs off) SELECT thousand, tenthous FROM tenk1 @@ -1605,7 +1612,8 @@ ORDER BY thousand, tenthous; -> Sort Sort Key: tenk1_1.thousand, ((random())::integer) -> Index Only Scan using tenk1_thous_tenthous on tenk1 tenk1_1 -(6 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(7 rows) -- Check min/max aggregate optimization explain (costs off) @@ -1624,7 +1632,8 @@ SELECT min(x) FROM Index Cond: (unique1 IS NOT NULL) -> Index Only Scan using tenk1_unique2 on tenk1 b Index Cond: (unique2 IS NOT NULL) -(9 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(10 rows) explain (costs off) SELECT min(y) FROM @@ -1642,7 +1651,8 @@ SELECT min(y) FROM Index Cond: (unique1 IS NOT NULL) -> Index Only Scan using tenk1_unique2 on tenk1 b Index Cond: (unique2 IS NOT NULL) -(9 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(10 rows) -- XXX planner doesn't recognize that index on unique2 is sufficiently sorted explain (costs off) @@ -1659,7 +1669,8 @@ ORDER BY x, y; -> Sort Sort Key: b.unique2, b.unique2 -> Index Only Scan using tenk1_unique2 on tenk1 b -(6 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(7 rows) -- exercise rescan code path via a repeatedly-evaluated subquery explain (costs off) @@ -1684,7 +1695,8 @@ FROM generate_series(1, 3) g(i); -> Sort Sort Key: ((d_1.d + g.i)) -> Function Scan on generate_series d_1 -(11 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(12 rows) SELECT ARRAY(SELECT f.i FROM ( @@ -2236,7 +2248,8 @@ explain (costs off) select * from mcrparted where a = 10 order by a, abs(b), c; Index Cond: (a = 10) -> Index Scan using mcrparted2_a_abs_c_idx on mcrparted2 Index Cond: (a = 10) -(5 rows) + Settings: enable_bitmapscan = 'off' +(6 rows) reset enable_bitmapscan; drop table mcrparted; diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out index f88f34550a..3f7b3fd441 100644 --- a/src/test/regress/expected/interval.out +++ b/src/test/regress/expected/interval.out @@ -257,7 +257,8 @@ SELECT f1 FROM INTERVAL_TBL_OF r1 ORDER BY f1; QUERY PLAN -------------------------------------------------------------------- Index Only Scan using interval_tbl_of_f1_idx on interval_tbl_of r1 -(1 row) + Settings: enable_seqscan = 'off' +(2 rows) SELECT f1 FROM INTERVAL_TBL_OF r1 ORDER BY f1; f1 diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index 07e631d45e..a0b8181889 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -2496,7 +2496,8 @@ select count(*) from tenk1 a, tenk1 b -> Hash -> Seq Scan on tenk1 b Filter: ((fivethous % 10) < 10) -(7 rows) + Settings: enable_mergejoin = 'off', work_mem = '64kB' +(8 rows) select count(*) from tenk1 a, tenk1 b where a.hundred = b.thousand and (b.fivethous % 10) < 10; @@ -2715,7 +2716,8 @@ select a.idv, b.idv from tidv a, tidv b where a.idv = b.idv; -> Seq Scan on tidv a -> Index Only Scan using tidv_idv_idx on tidv b Index Cond: (idv = a.idv) -(4 rows) + Settings: enable_mergejoin = 'off' +(5 rows) rollback; -- @@ -4119,8 +4121,8 @@ explain (verbose, costs off) select a.q2, b.q1 from int8_tbl a left join int8_tbl b on a.q2 = coalesce(b.q1, 1) where coalesce(b.q1, 1) > 0; - QUERY PLAN ---------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------ Merge Left Join Output: a.q2, b.q1 Merge Cond: (a.q2 = (COALESCE(b.q1, '1'::bigint))) @@ -4135,7 +4137,8 @@ explain (verbose, costs off) Sort Key: (COALESCE(b.q1, '1'::bigint)) -> Seq Scan on public.int8_tbl b Output: b.q1, COALESCE(b.q1, '1'::bigint) -(14 rows) + Settings: enable_hashjoin = 'off', enable_nestloop = 'off' +(15 rows) select a.q2, b.q1 from int8_tbl a left join int8_tbl b on a.q2 = coalesce(b.q1, 1) @@ -5970,14 +5973,15 @@ analyze j2; explain (costs off) select * from j1 inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2 where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1; - QUERY PLAN ------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------- Merge Join Merge Cond: (j1.id1 = j2.id1) Join Filter: (j1.id2 = j2.id2) -> Index Scan using j1_id1_idx on j1 -> Index Scan using j2_id1_idx on j2 -(5 rows) + Settings: enable_hashjoin = 'off', enable_nestloop = 'off', enable_sort = 'off' +(6 rows) select * from j1 inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2 diff --git a/src/test/regress/expected/join_hash.out b/src/test/regress/expected/join_hash.out index 9eee39bdd3..9b1de7274f 100644 --- a/src/test/regress/expected/join_hash.out +++ b/src/test/regress/expected/join_hash.out @@ -4,7 +4,7 @@ begin; set local min_parallel_table_scan_size = 0; set local parallel_setup_cost = 0; --- Extract bucket and batch counts from an explain analyze plan. In +-- Extract bucket and batch counts from an explain exec plan. In -- general we can't make assertions about how many batches (or -- buckets) will be required because it can vary, but we can in some -- special cases and we can check for growth. @@ -39,7 +39,7 @@ declare hash_node json; begin for whole_plan in - execute 'explain (analyze, format ''json'') ' || query + execute 'explain (exec, format ''json'') ' || query loop hash_node := find_hash(json_extract_path(whole_plan, '0', 'Plan')); original := hash_node->>'Original Hash Batches'; @@ -87,15 +87,16 @@ set local max_parallel_workers_per_gather = 0; set local work_mem = '4MB'; explain (costs off) select count(*) from simple r join simple s using (id); - QUERY PLAN ----------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------- Aggregate -> Hash Join Hash Cond: (r.id = s.id) -> Seq Scan on simple r -> Hash -> Seq Scan on simple s -(6 rows) + Settings: max_parallel_workers_per_gather = '0', min_parallel_table_scan_size = '0', parallel_setup_cost = '0' +(7 rows) select count(*) from simple r join simple s using (id); count @@ -121,8 +122,8 @@ set local work_mem = '4MB'; set local enable_parallel_hash = off; explain (costs off) select count(*) from simple r join simple s using (id); - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 2 @@ -132,7 +133,8 @@ explain (costs off) -> Parallel Seq Scan on simple r -> Hash -> Seq Scan on simple s -(9 rows) + Settings: enable_parallel_hash = 'off', min_parallel_table_scan_size = '0', parallel_setup_cost = '0' +(10 rows) select count(*) from simple r join simple s using (id); count @@ -158,8 +160,8 @@ set local work_mem = '4MB'; set local enable_parallel_hash = on; explain (costs off) select count(*) from simple r join simple s using (id); - QUERY PLAN -------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 2 @@ -169,7 +171,8 @@ explain (costs off) -> Parallel Seq Scan on simple r -> Parallel Hash -> Parallel Seq Scan on simple s -(9 rows) + Settings: min_parallel_table_scan_size = '0', parallel_setup_cost = '0' +(10 rows) select count(*) from simple r join simple s using (id); count @@ -197,15 +200,16 @@ set local max_parallel_workers_per_gather = 0; set local work_mem = '128kB'; explain (costs off) select count(*) from simple r join simple s using (id); - QUERY PLAN ----------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------ Aggregate -> Hash Join Hash Cond: (r.id = s.id) -> Seq Scan on simple r -> Hash -> Seq Scan on simple s -(6 rows) + Settings: max_parallel_workers_per_gather = '0', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', work_mem = '128kB' +(7 rows) select count(*) from simple r join simple s using (id); count @@ -231,8 +235,8 @@ set local work_mem = '128kB'; set local enable_parallel_hash = off; explain (costs off) select count(*) from simple r join simple s using (id); - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 2 @@ -242,7 +246,8 @@ explain (costs off) -> Parallel Seq Scan on simple r -> Hash -> Seq Scan on simple s -(9 rows) + Settings: enable_parallel_hash = 'off', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', work_mem = '128kB' +(10 rows) select count(*) from simple r join simple s using (id); count @@ -268,8 +273,8 @@ set local work_mem = '192kB'; set local enable_parallel_hash = on; explain (costs off) select count(*) from simple r join simple s using (id); - QUERY PLAN -------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 2 @@ -279,7 +284,8 @@ explain (costs off) -> Parallel Seq Scan on simple r -> Parallel Hash -> Parallel Seq Scan on simple s -(9 rows) + Settings: min_parallel_table_scan_size = '0', parallel_setup_cost = '0', work_mem = '192kB' +(10 rows) select count(*) from simple r join simple s using (id); count @@ -308,15 +314,16 @@ set local max_parallel_workers_per_gather = 0; set local work_mem = '128kB'; explain (costs off) select count(*) FROM simple r JOIN bigger_than_it_looks s USING (id); - QUERY PLAN ------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------ Aggregate -> Hash Join Hash Cond: (r.id = s.id) -> Seq Scan on simple r -> Hash -> Seq Scan on bigger_than_it_looks s -(6 rows) + Settings: max_parallel_workers_per_gather = '0', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', work_mem = '128kB' +(7 rows) select count(*) FROM simple r JOIN bigger_than_it_looks s USING (id); count @@ -342,8 +349,8 @@ set local work_mem = '128kB'; set local enable_parallel_hash = off; explain (costs off) select count(*) from simple r join bigger_than_it_looks s using (id); - QUERY PLAN ------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 2 @@ -353,7 +360,8 @@ explain (costs off) -> Parallel Seq Scan on simple r -> Hash -> Seq Scan on bigger_than_it_looks s -(9 rows) + Settings: enable_parallel_hash = 'off', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', work_mem = '128kB' +(10 rows) select count(*) from simple r join bigger_than_it_looks s using (id); count @@ -379,8 +387,8 @@ set local work_mem = '192kB'; set local enable_parallel_hash = on; explain (costs off) select count(*) from simple r join bigger_than_it_looks s using (id); - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------ Finalize Aggregate -> Gather Workers Planned: 1 @@ -390,7 +398,8 @@ explain (costs off) -> Parallel Seq Scan on simple r -> Parallel Hash -> Parallel Seq Scan on bigger_than_it_looks s -(9 rows) + Settings: max_parallel_workers_per_gather = '1', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', work_mem = '192kB' +(10 rows) select count(*) from simple r join bigger_than_it_looks s using (id); count @@ -420,15 +429,16 @@ set local max_parallel_workers_per_gather = 0; set local work_mem = '128kB'; explain (costs off) select count(*) from simple r join extremely_skewed s using (id); - QUERY PLAN --------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------ Aggregate -> Hash Join Hash Cond: (r.id = s.id) -> Seq Scan on simple r -> Hash -> Seq Scan on extremely_skewed s -(6 rows) + Settings: max_parallel_workers_per_gather = '0', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', work_mem = '128kB' +(7 rows) select count(*) from simple r join extremely_skewed s using (id); count @@ -453,8 +463,8 @@ set local work_mem = '128kB'; set local enable_parallel_hash = off; explain (costs off) select count(*) from simple r join extremely_skewed s using (id); - QUERY PLAN --------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------- Aggregate -> Gather Workers Planned: 2 @@ -463,7 +473,8 @@ explain (costs off) -> Parallel Seq Scan on simple r -> Hash -> Seq Scan on extremely_skewed s -(8 rows) + Settings: enable_parallel_hash = 'off', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', work_mem = '128kB' +(9 rows) select count(*) from simple r join extremely_skewed s using (id); count @@ -488,8 +499,8 @@ set local work_mem = '128kB'; set local enable_parallel_hash = on; explain (costs off) select count(*) from simple r join extremely_skewed s using (id); - QUERY PLAN ------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------ Finalize Aggregate -> Gather Workers Planned: 1 @@ -499,7 +510,8 @@ explain (costs off) -> Parallel Seq Scan on simple r -> Parallel Hash -> Parallel Seq Scan on extremely_skewed s -(9 rows) + Settings: max_parallel_workers_per_gather = '1', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', work_mem = '128kB' +(10 rows) select count(*) from simple r join extremely_skewed s using (id); count @@ -518,7 +530,7 @@ $$); rollback to settings; -- A couple of other hash join tests unrelated to work_mem management. --- Check that EXPLAIN ANALYZE has data even if the leader doesn't participate +-- Check that EXPLAIN EXEC has data even if the leader doesn't participate savepoint settings; set local max_parallel_workers_per_gather = 2; set local work_mem = '4MB'; @@ -554,8 +566,8 @@ explain (costs off) select count(*) from join_foo left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1; - QUERY PLAN ------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Aggregate -> Nested Loop Left Join Join Filter: ((join_foo.id < (b1.id + 1)) AND (join_foo.id > (b1.id - 1))) @@ -567,7 +579,8 @@ explain (costs off) -> Parallel Seq Scan on join_bar b1 -> Hash -> Seq Scan on join_bar b2 -(11 rows) + Settings: enable_material = 'off', enable_mergejoin = 'off', enable_parallel_hash = 'off', min_parallel_table_scan_size = '0', parallel_leader_participation = 'off', parallel_setup_cost = '0', parallel_tuple_cost = '0', work_mem = '64kB' +(12 rows) select count(*) from join_foo left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss @@ -605,8 +618,8 @@ explain (costs off) select count(*) from join_foo left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1; - QUERY PLAN ------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Aggregate -> Nested Loop Left Join Join Filter: ((join_foo.id < (b1.id + 1)) AND (join_foo.id > (b1.id - 1))) @@ -618,7 +631,8 @@ explain (costs off) -> Parallel Seq Scan on join_bar b1 -> Hash -> Seq Scan on join_bar b2 -(11 rows) + Settings: enable_material = 'off', enable_mergejoin = 'off', enable_parallel_hash = 'off', min_parallel_table_scan_size = '0', parallel_leader_participation = 'off', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(12 rows) select count(*) from join_foo left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss @@ -656,8 +670,8 @@ explain (costs off) select count(*) from join_foo left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1; - QUERY PLAN ------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Aggregate -> Nested Loop Left Join Join Filter: ((join_foo.id < (b1.id + 1)) AND (join_foo.id > (b1.id - 1))) @@ -669,7 +683,8 @@ explain (costs off) -> Parallel Seq Scan on join_bar b1 -> Parallel Hash -> Parallel Seq Scan on join_bar b2 -(11 rows) + Settings: enable_material = 'off', enable_mergejoin = 'off', min_parallel_table_scan_size = '0', parallel_leader_participation = 'off', parallel_setup_cost = '0', parallel_tuple_cost = '0', work_mem = '64kB' +(12 rows) select count(*) from join_foo left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss @@ -707,8 +722,8 @@ explain (costs off) select count(*) from join_foo left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1; - QUERY PLAN ------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Aggregate -> Nested Loop Left Join Join Filter: ((join_foo.id < (b1.id + 1)) AND (join_foo.id > (b1.id - 1))) @@ -720,7 +735,8 @@ explain (costs off) -> Parallel Seq Scan on join_bar b1 -> Parallel Hash -> Parallel Seq Scan on join_bar b2 -(11 rows) + Settings: enable_material = 'off', enable_mergejoin = 'off', min_parallel_table_scan_size = '0', parallel_leader_participation = 'off', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(12 rows) select count(*) from join_foo left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss @@ -749,15 +765,16 @@ savepoint settings; set local max_parallel_workers_per_gather = 0; explain (costs off) select count(*) from simple r full outer join simple s using (id); - QUERY PLAN ----------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------- Aggregate -> Hash Full Join Hash Cond: (r.id = s.id) -> Seq Scan on simple r -> Hash -> Seq Scan on simple s -(6 rows) + Settings: max_parallel_workers_per_gather = '0', min_parallel_table_scan_size = '0', parallel_setup_cost = '0' +(7 rows) select count(*) from simple r full outer join simple s using (id); count @@ -771,15 +788,16 @@ savepoint settings; set local max_parallel_workers_per_gather = 2; explain (costs off) select count(*) from simple r full outer join simple s using (id); - QUERY PLAN ----------------------------------------- + QUERY PLAN +------------------------------------------------------------------------- Aggregate -> Hash Full Join Hash Cond: (r.id = s.id) -> Seq Scan on simple r -> Hash -> Seq Scan on simple s -(6 rows) + Settings: min_parallel_table_scan_size = '0', parallel_setup_cost = '0' +(7 rows) select count(*) from simple r full outer join simple s using (id); count @@ -794,15 +812,16 @@ savepoint settings; set local max_parallel_workers_per_gather = 0; explain (costs off) select count(*) from simple r full outer join simple s on (r.id = 0 - s.id); - QUERY PLAN ----------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------- Aggregate -> Hash Full Join Hash Cond: ((0 - s.id) = r.id) -> Seq Scan on simple s -> Hash -> Seq Scan on simple r -(6 rows) + Settings: max_parallel_workers_per_gather = '0', min_parallel_table_scan_size = '0', parallel_setup_cost = '0' +(7 rows) select count(*) from simple r full outer join simple s on (r.id = 0 - s.id); count @@ -816,15 +835,16 @@ savepoint settings; set local max_parallel_workers_per_gather = 2; explain (costs off) select count(*) from simple r full outer join simple s on (r.id = 0 - s.id); - QUERY PLAN ----------------------------------------- + QUERY PLAN +------------------------------------------------------------------------- Aggregate -> Hash Full Join Hash Cond: ((0 - s.id) = r.id) -> Seq Scan on simple s -> Hash -> Seq Scan on simple r -(6 rows) + Settings: min_parallel_table_scan_size = '0', parallel_setup_cost = '0' +(7 rows) select count(*) from simple r full outer join simple s on (r.id = 0 - s.id); count @@ -845,8 +865,8 @@ set work_mem = '128kB'; explain (costs off) select length(max(s.t)) from wide left join (select id, coalesce(t, '') || '' as t from wide) s using (id); - QUERY PLAN ----------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 2 @@ -856,7 +876,8 @@ explain (costs off) -> Parallel Seq Scan on wide -> Parallel Hash -> Parallel Seq Scan on wide wide_1 -(9 rows) + Settings: min_parallel_table_scan_size = '0', parallel_setup_cost = '0', work_mem = '128kB' +(10 rows) select length(max(s.t)) from wide left join (select id, coalesce(t, '') || '' as t from wide) s using (id); diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out index 1018303006..da4bfd2bdc 100644 --- a/src/test/regress/expected/jsonb.out +++ b/src/test/regress/expected/jsonb.out @@ -2923,7 +2923,8 @@ SELECT count(*) FROM testjsonb WHERE j @@ '$.wait == null'; Recheck Cond: (j @@ '($."wait" == null)'::jsonpath) -> Bitmap Index Scan on jidx Index Cond: (j @@ '($."wait" == null)'::jsonpath) -(5 rows) + Settings: enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM testjsonb WHERE j @@ '$.wait == null'; count @@ -3036,7 +3037,8 @@ SELECT count(*) FROM testjsonb WHERE j @? '$.wait ? (@ == null)'; Recheck Cond: (j @? '$."wait"?(@ == null)'::jsonpath) -> Bitmap Index Scan on jidx Index Cond: (j @? '$."wait"?(@ == null)'::jsonpath) -(5 rows) + Settings: enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM testjsonb WHERE j @? '$.wait ? (@ == null)'; count @@ -3341,7 +3343,8 @@ SELECT count(*) FROM testjsonb WHERE j @? '$.wait ? (@ == null)'; Recheck Cond: (j @? '$."wait"?(@ == null)'::jsonpath) -> Bitmap Index Scan on jidx Index Cond: (j @? '$."wait"?(@ == null)'::jsonpath) -(5 rows) + Settings: enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM testjsonb WHERE j @? '$.wait ? (@ == null)'; count diff --git a/src/test/regress/expected/partition_aggregate.out b/src/test/regress/expected/partition_aggregate.out index 10349ec29c..95ac71d77d 100644 --- a/src/test/regress/expected/partition_aggregate.out +++ b/src/test/regress/expected/partition_aggregate.out @@ -20,8 +20,8 @@ ANALYZE pagg_tab; -- When GROUP BY clause matches; full aggregation is performed for each partition. EXPLAIN (COSTS OFF) SELECT c, sum(a), avg(b), count(*), min(a), max(b) FROM pagg_tab GROUP BY c HAVING avg(d) < 15 ORDER BY 1, 2, 3; - QUERY PLAN ------------------------------------------------------------------------ + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_p1.c, (sum(pagg_tab_p1.a)), (avg(pagg_tab_p1.b)) -> Append @@ -37,7 +37,8 @@ SELECT c, sum(a), avg(b), count(*), min(a), max(b) FROM pagg_tab GROUP BY c HAVI Group Key: pagg_tab_p3.c Filter: (avg(pagg_tab_p3.d) < '15'::numeric) -> Seq Scan on pagg_tab_p3 -(15 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(16 rows) SELECT c, sum(a), avg(b), count(*), min(a), max(b) FROM pagg_tab GROUP BY c HAVING avg(d) < 15 ORDER BY 1, 2, 3; c | sum | avg | count | min | max @@ -53,8 +54,8 @@ SELECT c, sum(a), avg(b), count(*), min(a), max(b) FROM pagg_tab GROUP BY c HAVI -- When GROUP BY clause does not match; partial aggregation is performed for each partition. EXPLAIN (COSTS OFF) SELECT a, sum(b), avg(b), count(*), min(a), max(b) FROM pagg_tab GROUP BY a HAVING avg(d) < 15 ORDER BY 1, 2, 3; - QUERY PLAN ------------------------------------------------------------------------ + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_p1.a, (sum(pagg_tab_p1.b)), (avg(pagg_tab_p1.b)) -> Finalize HashAggregate @@ -70,7 +71,8 @@ SELECT a, sum(b), avg(b), count(*), min(a), max(b) FROM pagg_tab GROUP BY a HAVI -> Partial HashAggregate Group Key: pagg_tab_p3.a -> Seq Scan on pagg_tab_p3 -(15 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(16 rows) SELECT a, sum(b), avg(b), count(*), min(a), max(b) FROM pagg_tab GROUP BY a HAVING avg(d) < 15 ORDER BY 1, 2, 3; a | sum | avg | count | min | max @@ -90,8 +92,8 @@ SELECT a, sum(b), avg(b), count(*), min(a), max(b) FROM pagg_tab GROUP BY a HAVI -- Check with multiple columns in GROUP BY EXPLAIN (COSTS OFF) SELECT a, c, count(*) FROM pagg_tab GROUP BY a, c; - QUERY PLAN -------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Append -> HashAggregate Group Key: pagg_tab_p1.a, pagg_tab_p1.c @@ -102,13 +104,14 @@ SELECT a, c, count(*) FROM pagg_tab GROUP BY a, c; -> HashAggregate Group Key: pagg_tab_p3.a, pagg_tab_p3.c -> Seq Scan on pagg_tab_p3 -(10 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(11 rows) -- Check with multiple columns in GROUP BY, order in GROUP BY is reversed EXPLAIN (COSTS OFF) SELECT a, c, count(*) FROM pagg_tab GROUP BY c, a; - QUERY PLAN -------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Append -> HashAggregate Group Key: pagg_tab_p1.c, pagg_tab_p1.a @@ -119,13 +122,14 @@ SELECT a, c, count(*) FROM pagg_tab GROUP BY c, a; -> HashAggregate Group Key: pagg_tab_p3.c, pagg_tab_p3.a -> Seq Scan on pagg_tab_p3 -(10 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(11 rows) -- Check with multiple columns in GROUP BY, order in target-list is reversed EXPLAIN (COSTS OFF) SELECT c, a, count(*) FROM pagg_tab GROUP BY a, c; - QUERY PLAN -------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Append -> HashAggregate Group Key: pagg_tab_p1.a, pagg_tab_p1.c @@ -136,18 +140,20 @@ SELECT c, a, count(*) FROM pagg_tab GROUP BY a, c; -> HashAggregate Group Key: pagg_tab_p3.a, pagg_tab_p3.c -> Seq Scan on pagg_tab_p3 -(10 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(11 rows) -- Test when input relation for grouping is dummy EXPLAIN (COSTS OFF) SELECT c, sum(a) FROM pagg_tab WHERE 1 = 2 GROUP BY c; - QUERY PLAN --------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- HashAggregate Group Key: c -> Result One-Time Filter: false -(4 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(5 rows) SELECT c, sum(a) FROM pagg_tab WHERE 1 = 2 GROUP BY c; c | sum @@ -156,13 +162,14 @@ SELECT c, sum(a) FROM pagg_tab WHERE 1 = 2 GROUP BY c; EXPLAIN (COSTS OFF) SELECT c, sum(a) FROM pagg_tab WHERE c = 'x' GROUP BY c; - QUERY PLAN --------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- GroupAggregate Group Key: c -> Result One-Time Filter: false -(4 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(5 rows) SELECT c, sum(a) FROM pagg_tab WHERE c = 'x' GROUP BY c; c | sum @@ -174,8 +181,8 @@ SET enable_hashagg TO false; -- When GROUP BY clause matches full aggregation is performed for each partition. EXPLAIN (COSTS OFF) SELECT c, sum(a), avg(b), count(*) FROM pagg_tab GROUP BY 1 HAVING avg(d) < 15 ORDER BY 1, 2, 3; - QUERY PLAN ------------------------------------------------------------------------ + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_p1.c, (sum(pagg_tab_p1.a)), (avg(pagg_tab_p1.b)) -> Append @@ -197,7 +204,8 @@ SELECT c, sum(a), avg(b), count(*) FROM pagg_tab GROUP BY 1 HAVING avg(d) < 15 O -> Sort Sort Key: pagg_tab_p3.c -> Seq Scan on pagg_tab_p3 -(21 rows) + Settings: enable_hashagg = 'off', enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(22 rows) SELECT c, sum(a), avg(b), count(*) FROM pagg_tab GROUP BY 1 HAVING avg(d) < 15 ORDER BY 1, 2, 3; c | sum | avg | count @@ -213,8 +221,8 @@ SELECT c, sum(a), avg(b), count(*) FROM pagg_tab GROUP BY 1 HAVING avg(d) < 15 O -- When GROUP BY clause does not match; partial aggregation is performed for each partition. EXPLAIN (COSTS OFF) SELECT a, sum(b), avg(b), count(*) FROM pagg_tab GROUP BY 1 HAVING avg(d) < 15 ORDER BY 1, 2, 3; - QUERY PLAN ------------------------------------------------------------------------ + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_p1.a, (sum(pagg_tab_p1.b)), (avg(pagg_tab_p1.b)) -> Finalize GroupAggregate @@ -237,7 +245,8 @@ SELECT a, sum(b), avg(b), count(*) FROM pagg_tab GROUP BY 1 HAVING avg(d) < 15 O -> Sort Sort Key: pagg_tab_p3.a -> Seq Scan on pagg_tab_p3 -(22 rows) + Settings: enable_hashagg = 'off', enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(23 rows) SELECT a, sum(b), avg(b), count(*) FROM pagg_tab GROUP BY 1 HAVING avg(d) < 15 ORDER BY 1, 2, 3; a | sum | avg | count @@ -257,8 +266,8 @@ SELECT a, sum(b), avg(b), count(*) FROM pagg_tab GROUP BY 1 HAVING avg(d) < 15 O -- Test partitionwise grouping without any aggregates EXPLAIN (COSTS OFF) SELECT c FROM pagg_tab GROUP BY c ORDER BY 1; - QUERY PLAN -------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Merge Append Sort Key: pagg_tab_p1.c -> Group @@ -276,7 +285,8 @@ SELECT c FROM pagg_tab GROUP BY c ORDER BY 1; -> Sort Sort Key: pagg_tab_p3.c -> Seq Scan on pagg_tab_p3 -(17 rows) + Settings: enable_hashagg = 'off', enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(18 rows) SELECT c FROM pagg_tab GROUP BY c ORDER BY 1; c @@ -297,8 +307,8 @@ SELECT c FROM pagg_tab GROUP BY c ORDER BY 1; EXPLAIN (COSTS OFF) SELECT a FROM pagg_tab WHERE a < 3 GROUP BY a ORDER BY 1; - QUERY PLAN -------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Group Group Key: pagg_tab_p1.a -> Merge Append @@ -321,7 +331,8 @@ SELECT a FROM pagg_tab WHERE a < 3 GROUP BY a ORDER BY 1; Sort Key: pagg_tab_p3.a -> Seq Scan on pagg_tab_p3 Filter: (a < 3) -(22 rows) + Settings: enable_hashagg = 'off', enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(23 rows) SELECT a FROM pagg_tab WHERE a < 3 GROUP BY a ORDER BY 1; a @@ -335,8 +346,8 @@ RESET enable_hashagg; -- ROLLUP, partitionwise aggregation does not apply EXPLAIN (COSTS OFF) SELECT c, sum(a) FROM pagg_tab GROUP BY rollup(c) ORDER BY 1, 2; - QUERY PLAN -------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_p1.c, (sum(pagg_tab_p1.a)) -> MixedAggregate @@ -346,7 +357,8 @@ SELECT c, sum(a) FROM pagg_tab GROUP BY rollup(c) ORDER BY 1, 2; -> Seq Scan on pagg_tab_p1 -> Seq Scan on pagg_tab_p2 -> Seq Scan on pagg_tab_p3 -(9 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(10 rows) -- ORDERED SET within the aggregate. -- Full aggregation; since all the rows that belong to the same group come @@ -354,8 +366,8 @@ SELECT c, sum(a) FROM pagg_tab GROUP BY rollup(c) ORDER BY 1, 2; -- make any difference. EXPLAIN (COSTS OFF) SELECT c, sum(b order by a) FROM pagg_tab GROUP BY c ORDER BY 1, 2; - QUERY PLAN ------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_p1.c, (sum(pagg_tab_p1.b ORDER BY pagg_tab_p1.a)) -> Append @@ -374,15 +386,16 @@ SELECT c, sum(b order by a) FROM pagg_tab GROUP BY c ORDER BY 1, 2; -> Sort Sort Key: pagg_tab_p3.c -> Seq Scan on pagg_tab_p3 -(18 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(19 rows) -- Since GROUP BY clause does not match with PARTITION KEY; we need to do -- partial aggregation. However, ORDERED SET are not partial safe and thus -- partitionwise aggregation plan is not generated. EXPLAIN (COSTS OFF) SELECT a, sum(b order by a) FROM pagg_tab GROUP BY a ORDER BY 1, 2; - QUERY PLAN ------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_p1.a, (sum(pagg_tab_p1.b ORDER BY pagg_tab_p1.a)) -> GroupAggregate @@ -393,7 +406,8 @@ SELECT a, sum(b order by a) FROM pagg_tab GROUP BY a ORDER BY 1, 2; -> Seq Scan on pagg_tab_p1 -> Seq Scan on pagg_tab_p2 -> Seq Scan on pagg_tab_p3 -(10 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(11 rows) -- JOIN query CREATE TABLE pagg_tab1(x int, y int) PARTITION BY RANGE(x); @@ -411,8 +425,8 @@ ANALYZE pagg_tab2; -- When GROUP BY clause matches; full aggregation is performed for each partition. EXPLAIN (COSTS OFF) SELECT t1.x, sum(t1.y), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUP BY t1.x ORDER BY 1, 2, 3; - QUERY PLAN -------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: t1.x, (sum(t1.y)), (count(*)) -> Append @@ -437,7 +451,8 @@ SELECT t1.x, sum(t1.y), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2 -> Seq Scan on pagg_tab2_p3 t2_2 -> Hash -> Seq Scan on pagg_tab1_p3 t1_2 -(24 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(25 rows) SELECT t1.x, sum(t1.y), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUP BY t1.x ORDER BY 1, 2, 3; x | sum | count @@ -452,8 +467,8 @@ SELECT t1.x, sum(t1.y), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2 -- Check with whole-row reference; partitionwise aggregation does not apply EXPLAIN (COSTS OFF) SELECT t1.x, sum(t1.y), count(t1) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUP BY t1.x ORDER BY 1, 2, 3; - QUERY PLAN -------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: t1.x, (sum(t1.y)), (count(((t1.*)::pagg_tab1))) -> HashAggregate @@ -469,7 +484,8 @@ SELECT t1.x, sum(t1.y), count(t1) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t -> Seq Scan on pagg_tab2_p1 t2 -> Seq Scan on pagg_tab2_p2 t2_1 -> Seq Scan on pagg_tab2_p3 t2_2 -(15 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(16 rows) SELECT t1.x, sum(t1.y), count(t1) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUP BY t1.x ORDER BY 1, 2, 3; x | sum | count @@ -484,8 +500,8 @@ SELECT t1.x, sum(t1.y), count(t1) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t -- GROUP BY having other matching key EXPLAIN (COSTS OFF) SELECT t2.y, sum(t1.y), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUP BY t2.y ORDER BY 1, 2, 3; - QUERY PLAN -------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: t2.y, (sum(t1.y)), (count(*)) -> Append @@ -510,15 +526,16 @@ SELECT t2.y, sum(t1.y), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2 -> Seq Scan on pagg_tab2_p3 t2_2 -> Hash -> Seq Scan on pagg_tab1_p3 t1_2 -(24 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(25 rows) -- When GROUP BY clause does not match; partial aggregation is performed for each partition. -- Also test GroupAggregate paths by disabling hash aggregates. SET enable_hashagg TO false; EXPLAIN (COSTS OFF) SELECT t1.y, sum(t1.x), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUP BY t1.y HAVING avg(t1.x) > 10 ORDER BY 1, 2, 3; - QUERY PLAN -------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: t1.y, (sum(t1.x)), (count(*)) -> Finalize GroupAggregate @@ -553,7 +570,8 @@ SELECT t1.y, sum(t1.x), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2 -> Seq Scan on pagg_tab2_p3 t2_2 -> Hash -> Seq Scan on pagg_tab1_p3 t1_2 -(34 rows) + Settings: enable_hashagg = 'off', enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(35 rows) SELECT t1.y, sum(t1.x), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUP BY t1.y HAVING avg(t1.x) > 10 ORDER BY 1, 2, 3; y | sum | count @@ -573,8 +591,8 @@ RESET enable_hashagg; -- GROUP BY is on nullable column EXPLAIN (COSTS OFF) SELECT b.y, sum(a.y) FROM pagg_tab1 a LEFT JOIN pagg_tab2 b ON a.x = b.y GROUP BY b.y ORDER BY 1 NULLS LAST; - QUERY PLAN ------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Finalize GroupAggregate Group Key: b.y -> Sort @@ -601,7 +619,8 @@ SELECT b.y, sum(a.y) FROM pagg_tab1 a LEFT JOIN pagg_tab2 b ON a.x = b.y GROUP B -> Seq Scan on pagg_tab2_p3 b_2 -> Hash -> Seq Scan on pagg_tab1_p3 a_2 -(26 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(27 rows) SELECT b.y, sum(a.y) FROM pagg_tab1 a LEFT JOIN pagg_tab2 b ON a.x = b.y GROUP BY b.y ORDER BY 1 NULLS LAST; y | sum @@ -618,8 +637,8 @@ SELECT b.y, sum(a.y) FROM pagg_tab1 a LEFT JOIN pagg_tab2 b ON a.x = b.y GROUP B -- GROUP BY is on non-nullable column EXPLAIN (COSTS OFF) SELECT b.y, sum(a.y) FROM pagg_tab1 a RIGHT JOIN pagg_tab2 b ON a.x = b.y GROUP BY b.y ORDER BY 1 NULLS LAST; - QUERY PLAN ------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: b.y -> Append @@ -644,7 +663,8 @@ SELECT b.y, sum(a.y) FROM pagg_tab1 a RIGHT JOIN pagg_tab2 b ON a.x = b.y GROUP -> Seq Scan on pagg_tab2_p3 b_2 -> Hash -> Seq Scan on pagg_tab1_p3 a_2 -(24 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(25 rows) SELECT b.y, sum(a.y) FROM pagg_tab1 a RIGHT JOIN pagg_tab2 b ON a.x = b.y GROUP BY b.y ORDER BY 1 NULLS LAST; y | sum @@ -665,8 +685,8 @@ SELECT b.y, sum(a.y) FROM pagg_tab1 a RIGHT JOIN pagg_tab2 b ON a.x = b.y GROUP -- GROUP BY is on nullable column EXPLAIN (COSTS OFF) SELECT a.x, sum(b.x) FROM pagg_tab1 a FULL OUTER JOIN pagg_tab2 b ON a.x = b.y GROUP BY a.x ORDER BY 1 NULLS LAST; - QUERY PLAN ------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Finalize GroupAggregate Group Key: a.x -> Sort @@ -693,7 +713,8 @@ SELECT a.x, sum(b.x) FROM pagg_tab1 a FULL OUTER JOIN pagg_tab2 b ON a.x = b.y G -> Seq Scan on pagg_tab2_p3 b_2 -> Hash -> Seq Scan on pagg_tab1_p3 a_2 -(26 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(27 rows) SELECT a.x, sum(b.x) FROM pagg_tab1 a FULL OUTER JOIN pagg_tab2 b ON a.x = b.y GROUP BY a.x ORDER BY 1 NULLS LAST; x | sum @@ -722,8 +743,8 @@ SELECT a.x, sum(b.x) FROM pagg_tab1 a FULL OUTER JOIN pagg_tab2 b ON a.x = b.y G -- But right now we are unable to do partitionwise join in this case. EXPLAIN (COSTS OFF) SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a LEFT JOIN (SELECT * FROM pagg_tab2 WHERE y > 10) b ON a.x = b.y WHERE a.x > 5 or b.y < 20 GROUP BY a.x, b.y ORDER BY 1, 2; - QUERY PLAN ------------------------------------------------------------------------ + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab1_p1.x, pagg_tab2_p2.y -> HashAggregate @@ -742,7 +763,8 @@ SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a LEFT JOI Filter: (y > 10) -> Seq Scan on pagg_tab2_p3 Filter: (y > 10) -(18 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(19 rows) SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a LEFT JOIN (SELECT * FROM pagg_tab2 WHERE y > 10) b ON a.x = b.y WHERE a.x > 5 or b.y < 20 GROUP BY a.x, b.y ORDER BY 1, 2; x | y | count @@ -762,8 +784,8 @@ SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a LEFT JOI -- But right now we are unable to do partitionwise join in this case. EXPLAIN (COSTS OFF) SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a FULL JOIN (SELECT * FROM pagg_tab2 WHERE y > 10) b ON a.x = b.y WHERE a.x > 5 or b.y < 20 GROUP BY a.x, b.y ORDER BY 1, 2; - QUERY PLAN ------------------------------------------------------------------------ + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab1_p1.x, pagg_tab2_p2.y -> HashAggregate @@ -782,7 +804,8 @@ SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a FULL JOI Filter: (y > 10) -> Seq Scan on pagg_tab2_p3 Filter: (y > 10) -(18 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(19 rows) SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a FULL JOIN (SELECT * FROM pagg_tab2 WHERE y > 10) b ON a.x = b.y WHERE a.x > 5 or b.y < 20 GROUP BY a.x, b.y ORDER BY 1, 2; x | y | count @@ -800,15 +823,16 @@ SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a FULL JOI -- Empty join relation because of empty outer side, no partitionwise agg plan EXPLAIN (COSTS OFF) SELECT a.x, a.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x = 1 AND x = 2) a LEFT JOIN pagg_tab2 b ON a.x = b.y GROUP BY a.x, a.y ORDER BY 1, 2; - QUERY PLAN ---------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- GroupAggregate Group Key: pagg_tab1.x, pagg_tab1.y -> Sort Sort Key: pagg_tab1.y -> Result One-Time Filter: false -(6 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(7 rows) SELECT a.x, a.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x = 1 AND x = 2) a LEFT JOIN pagg_tab2 b ON a.x = b.y GROUP BY a.x, a.y ORDER BY 1, 2; x | y | count @@ -825,8 +849,8 @@ ANALYZE pagg_tab_m; -- Partial aggregation as GROUP BY clause does not match with PARTITION KEY EXPLAIN (COSTS OFF) SELECT a, sum(b), avg(c), count(*) FROM pagg_tab_m GROUP BY a HAVING avg(c) < 22 ORDER BY 1, 2, 3; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_m_p1.a, (sum(pagg_tab_m_p1.b)), (avg(pagg_tab_m_p1.c)) -> Finalize HashAggregate @@ -842,7 +866,8 @@ SELECT a, sum(b), avg(c), count(*) FROM pagg_tab_m GROUP BY a HAVING avg(c) < 22 -> Partial HashAggregate Group Key: pagg_tab_m_p3.a -> Seq Scan on pagg_tab_m_p3 -(15 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(16 rows) SELECT a, sum(b), avg(c), count(*) FROM pagg_tab_m GROUP BY a HAVING avg(c) < 22 ORDER BY 1, 2, 3; a | sum | avg | count @@ -858,8 +883,8 @@ SELECT a, sum(b), avg(c), count(*) FROM pagg_tab_m GROUP BY a HAVING avg(c) < 22 -- Full aggregation as GROUP BY clause matches with PARTITION KEY EXPLAIN (COSTS OFF) SELECT a, sum(b), avg(c), count(*) FROM pagg_tab_m GROUP BY a, (a+b)/2 HAVING sum(b) < 50 ORDER BY 1, 2, 3; - QUERY PLAN -------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_m_p1.a, (sum(pagg_tab_m_p1.b)), (avg(pagg_tab_m_p1.c)) -> Append @@ -875,7 +900,8 @@ SELECT a, sum(b), avg(c), count(*) FROM pagg_tab_m GROUP BY a, (a+b)/2 HAVING su Group Key: pagg_tab_m_p3.a, ((pagg_tab_m_p3.a + pagg_tab_m_p3.b) / 2) Filter: (sum(pagg_tab_m_p3.b) < 50) -> Seq Scan on pagg_tab_m_p3 -(15 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(16 rows) SELECT a, sum(b), avg(c), count(*) FROM pagg_tab_m GROUP BY a, (a+b)/2 HAVING sum(b) < 50 ORDER BY 1, 2, 3; a | sum | avg | count @@ -891,8 +917,8 @@ SELECT a, sum(b), avg(c), count(*) FROM pagg_tab_m GROUP BY a, (a+b)/2 HAVING su -- Full aggregation as PARTITION KEY is part of GROUP BY clause EXPLAIN (COSTS OFF) SELECT a, c, sum(b), avg(c), count(*) FROM pagg_tab_m GROUP BY (a+b)/2, 2, 1 HAVING sum(b) = 50 AND avg(c) > 25 ORDER BY 1, 2, 3; - QUERY PLAN ------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_m_p1.a, pagg_tab_m_p1.c, (sum(pagg_tab_m_p1.b)) -> Append @@ -908,7 +934,8 @@ SELECT a, c, sum(b), avg(c), count(*) FROM pagg_tab_m GROUP BY (a+b)/2, 2, 1 HAV Group Key: ((pagg_tab_m_p3.a + pagg_tab_m_p3.b) / 2), pagg_tab_m_p3.c, pagg_tab_m_p3.a Filter: ((sum(pagg_tab_m_p3.b) = 50) AND (avg(pagg_tab_m_p3.c) > '25'::numeric)) -> Seq Scan on pagg_tab_m_p3 -(15 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', max_parallel_workers_per_gather = '0' +(16 rows) SELECT a, c, sum(b), avg(c), count(*) FROM pagg_tab_m GROUP BY (a+b)/2, 2, 1 HAVING sum(b) = 50 AND avg(c) > 25 ORDER BY 1, 2, 3; a | c | sum | avg | count @@ -972,7 +999,8 @@ SELECT a, sum(b), array_agg(distinct c), count(*) FROM pagg_tab_ml GROUP BY a HA -> Sort Sort Key: pagg_tab_ml_p1.a -> Seq Scan on pagg_tab_ml_p1 -(27 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on' +(28 rows) SELECT a, sum(b), array_agg(distinct c), count(*) FROM pagg_tab_ml GROUP BY a HAVING avg(b) < 3 ORDER BY 1, 2, 3; a | sum | array_agg | count @@ -991,8 +1019,8 @@ SELECT a, sum(b), array_agg(distinct c), count(*) FROM pagg_tab_ml GROUP BY a HA -- Without ORDER BY clause, to test Gather at top-most path EXPLAIN (COSTS OFF) SELECT a, sum(b), array_agg(distinct c), count(*) FROM pagg_tab_ml GROUP BY a HAVING avg(b) < 3; - QUERY PLAN ------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------- Gather Workers Planned: 2 -> Parallel Append @@ -1018,15 +1046,16 @@ SELECT a, sum(b), array_agg(distinct c), count(*) FROM pagg_tab_ml GROUP BY a HA -> Sort Sort Key: pagg_tab_ml_p1.a -> Seq Scan on pagg_tab_ml_p1 -(25 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on' +(26 rows) -- Full aggregation at level 1 as GROUP BY clause matches with PARTITION KEY -- for level 1 only. For subpartitions, GROUP BY clause does not match with -- PARTITION KEY, thus we will have a partial aggregation for them. EXPLAIN (COSTS OFF) SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUP BY a HAVING avg(b) < 3 ORDER BY 1, 2, 3; - QUERY PLAN -------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_ml_p1.a, (sum(pagg_tab_ml_p1.b)), (count(*)) -> Append @@ -1058,7 +1087,8 @@ SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUP BY a HAVING avg(b) < 3 ORDER B -> Partial HashAggregate Group Key: pagg_tab_ml_p3_s2.a -> Seq Scan on pagg_tab_ml_p3_s2 -(31 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on' +(32 rows) SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUP BY a HAVING avg(b) < 3 ORDER BY 1, 2, 3; a | sum | count @@ -1078,8 +1108,8 @@ SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUP BY a HAVING avg(b) < 3 ORDER B -- PARTITION KEY EXPLAIN (COSTS OFF) SELECT b, sum(a), count(*) FROM pagg_tab_ml GROUP BY b ORDER BY 1, 2, 3; - QUERY PLAN -------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_ml_p1.b, (sum(pagg_tab_ml_p1.a)), (count(*)) -> Finalize GroupAggregate @@ -1102,7 +1132,8 @@ SELECT b, sum(a), count(*) FROM pagg_tab_ml GROUP BY b ORDER BY 1, 2, 3; -> Partial HashAggregate Group Key: pagg_tab_ml_p3_s2.b -> Seq Scan on pagg_tab_ml_p3_s2 -(22 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on' +(23 rows) SELECT b, sum(a), count(*) FROM pagg_tab_ml GROUP BY b HAVING avg(a) < 15 ORDER BY 1, 2, 3; b | sum | count @@ -1142,7 +1173,8 @@ SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUP BY a, b, c HAVING avg(b) > 7 O Group Key: pagg_tab_ml_p3_s2.a, pagg_tab_ml_p3_s2.b, pagg_tab_ml_p3_s2.c Filter: (avg(pagg_tab_ml_p3_s2.b) > '7'::numeric) -> Seq Scan on pagg_tab_ml_p3_s2 -(23 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on' +(24 rows) SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUP BY a, b, c HAVING avg(b) > 7 ORDER BY 1, 2, 3; a | sum | count @@ -1169,8 +1201,8 @@ SET parallel_setup_cost TO 0; -- PARTITION KEY, thus we will have a partial aggregation for them. EXPLAIN (COSTS OFF) SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUP BY a HAVING avg(b) < 3 ORDER BY 1, 2, 3; - QUERY PLAN ----------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_ml_p1.a, (sum(pagg_tab_ml_p1.b)), (count(*)) -> Append @@ -1212,7 +1244,8 @@ SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUP BY a HAVING avg(b) < 3 ORDER B -> Partial HashAggregate Group Key: pagg_tab_ml_p3_s2.a -> Parallel Seq Scan on pagg_tab_ml_p3_s2 -(41 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', min_parallel_table_scan_size = '8kB', parallel_setup_cost = '0' +(42 rows) SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUP BY a HAVING avg(b) < 3 ORDER BY 1, 2, 3; a | sum | count @@ -1232,8 +1265,8 @@ SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUP BY a HAVING avg(b) < 3 ORDER B -- PARTITION KEY EXPLAIN (COSTS OFF) SELECT b, sum(a), count(*) FROM pagg_tab_ml GROUP BY b ORDER BY 1, 2, 3; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_ml_p1.b, (sum(pagg_tab_ml_p1.a)), (count(*)) -> Finalize GroupAggregate @@ -1258,7 +1291,8 @@ SELECT b, sum(a), count(*) FROM pagg_tab_ml GROUP BY b ORDER BY 1, 2, 3; -> Partial HashAggregate Group Key: pagg_tab_ml_p3_s2.b -> Parallel Seq Scan on pagg_tab_ml_p3_s2 -(24 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', min_parallel_table_scan_size = '8kB', parallel_setup_cost = '0' +(25 rows) SELECT b, sum(a), count(*) FROM pagg_tab_ml GROUP BY b HAVING avg(a) < 15 ORDER BY 1, 2, 3; b | sum | count @@ -1273,8 +1307,8 @@ SELECT b, sum(a), count(*) FROM pagg_tab_ml GROUP BY b HAVING avg(a) < 15 ORDER -- Full aggregation at all levels as GROUP BY clause matches with PARTITION KEY EXPLAIN (COSTS OFF) SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUP BY a, b, c HAVING avg(b) > 7 ORDER BY 1, 2, 3; - QUERY PLAN ----------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------- Gather Merge Workers Planned: 2 -> Sort @@ -1300,7 +1334,8 @@ SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUP BY a, b, c HAVING avg(b) > 7 O Group Key: pagg_tab_ml_p3_s2.a, pagg_tab_ml_p3_s2.b, pagg_tab_ml_p3_s2.c Filter: (avg(pagg_tab_ml_p3_s2.b) > '7'::numeric) -> Seq Scan on pagg_tab_ml_p3_s2 -(25 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', min_parallel_table_scan_size = '8kB', parallel_setup_cost = '0' +(26 rows) SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUP BY a, b, c HAVING avg(b) > 7 ORDER BY 1, 2, 3; a | sum | count @@ -1337,8 +1372,8 @@ ANALYZE pagg_tab_para; -- When GROUP BY clause matches; full aggregation is performed for each partition. EXPLAIN (COSTS OFF) SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < 7 ORDER BY 1, 2, 3; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_para_p1.x, (sum(pagg_tab_para_p1.y)), (avg(pagg_tab_para_p1.y)) -> Finalize GroupAggregate @@ -1358,7 +1393,8 @@ SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < -> Partial HashAggregate Group Key: pagg_tab_para_p3.x -> Parallel Seq Scan on pagg_tab_para_p3 -(19 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', min_parallel_table_scan_size = '8kB', parallel_setup_cost = '10' +(20 rows) SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < 7 ORDER BY 1, 2, 3; x | sum | avg | count @@ -1374,8 +1410,8 @@ SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < -- When GROUP BY clause does not match; partial aggregation is performed for each partition. EXPLAIN (COSTS OFF) SELECT y, sum(x), avg(x), count(*) FROM pagg_tab_para GROUP BY y HAVING avg(x) < 12 ORDER BY 1, 2, 3; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_para_p1.y, (sum(pagg_tab_para_p1.x)), (avg(pagg_tab_para_p1.x)) -> Finalize GroupAggregate @@ -1395,7 +1431,8 @@ SELECT y, sum(x), avg(x), count(*) FROM pagg_tab_para GROUP BY y HAVING avg(x) < -> Partial HashAggregate Group Key: pagg_tab_para_p3.y -> Parallel Seq Scan on pagg_tab_para_p3 -(19 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', min_parallel_table_scan_size = '8kB', parallel_setup_cost = '10' +(20 rows) SELECT y, sum(x), avg(x), count(*) FROM pagg_tab_para GROUP BY y HAVING avg(x) < 12 ORDER BY 1, 2, 3; y | sum | avg | count @@ -1412,8 +1449,8 @@ ALTER TABLE pagg_tab_para_p3 SET (parallel_workers = 0); ANALYZE pagg_tab_para; EXPLAIN (COSTS OFF) SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < 7 ORDER BY 1, 2, 3; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_para_p1.x, (sum(pagg_tab_para_p1.y)), (avg(pagg_tab_para_p1.y)) -> Finalize GroupAggregate @@ -1429,7 +1466,8 @@ SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < -> Seq Scan on pagg_tab_para_p1 -> Seq Scan on pagg_tab_para_p3 -> Parallel Seq Scan on pagg_tab_para_p2 -(15 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', min_parallel_table_scan_size = '8kB', parallel_setup_cost = '10' +(16 rows) SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < 7 ORDER BY 1, 2, 3; x | sum | avg | count @@ -1446,8 +1484,8 @@ ALTER TABLE pagg_tab_para_p2 SET (parallel_workers = 0); ANALYZE pagg_tab_para; EXPLAIN (COSTS OFF) SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < 7 ORDER BY 1, 2, 3; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: pagg_tab_para_p1.x, (sum(pagg_tab_para_p1.y)), (avg(pagg_tab_para_p1.y)) -> Finalize GroupAggregate @@ -1463,7 +1501,8 @@ SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < -> Seq Scan on pagg_tab_para_p1 -> Seq Scan on pagg_tab_para_p2 -> Seq Scan on pagg_tab_para_p3 -(15 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', min_parallel_table_scan_size = '8kB', parallel_setup_cost = '10' +(16 rows) SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < 7 ORDER BY 1, 2, 3; x | sum | avg | count @@ -1498,7 +1537,8 @@ SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < Group Key: pagg_tab_para_p3.x Filter: (avg(pagg_tab_para_p3.y) < '7'::numeric) -> Seq Scan on pagg_tab_para_p3 -(15 rows) + Settings: enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on' +(16 rows) SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < 7 ORDER BY 1, 2, 3; x | sum | avg | count diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out index 1296edcdae..01a1444311 100644 --- a/src/test/regress/expected/partition_join.out +++ b/src/test/regress/expected/partition_join.out @@ -51,7 +51,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = -> Hash -> Seq Scan on prt1_p3 t1_2 Filter: (b = 0) -(21 rows) + Settings: enable_partitionwise_join = 'on' +(22 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b; a | c | b | c @@ -83,7 +84,8 @@ SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER Filter: (b = 0) -> Seq Scan on prt1_p3 t1_2 Filter: (b = 0) -(16 rows) + Settings: enable_partitionwise_join = 'on' +(17 rows) SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b; t1 | t2 @@ -127,7 +129,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHE Filter: (a = 0) -> Index Scan using iprt1_p3_a on prt1_p3 t1_2 Index Cond: (a = t2_2.b) -(20 rows) + Settings: enable_partitionwise_join = 'on' +(21 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t1.a, t2.b; a | c | b | c @@ -174,7 +177,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0) -> Hash -> Seq Scan on prt2_p3 Filter: (a = 0) -(27 rows) + Settings: enable_partitionwise_join = 'on' +(28 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.a = 0) t2 ON (t1.a = t2.b) WHERE t1.phv = t1.a OR t2.phv = t2.b ORDER BY t1.a, t2.b; a | c | b | c @@ -197,7 +201,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a < -> Hash -> Seq Scan on prt1_p2 t1 Filter: ((a < 450) AND (b = 0)) -(9 rows) + Settings: enable_partitionwise_join = 'on' +(10 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a < 450 AND t2.b > 250 AND t1.b = 0 ORDER BY t1.a, t2.b; a | c | b | c @@ -225,7 +230,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JO Filter: ((a < 450) AND (b = 0)) -> Seq Scan on prt1_p2 Filter: ((a < 450) AND (b = 0)) -(15 rows) + Settings: enable_partitionwise_join = 'on' +(16 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b; a | c | b | c @@ -262,7 +268,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 FULL JO Filter: (b > 250) -> Seq Scan on prt2_p3 Filter: (b > 250) -(16 rows) + Settings: enable_partitionwise_join = 'on' +(17 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 FULL JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.b = 0 OR t2.a = 0 ORDER BY t1.a, t2.b; a | c | b | c @@ -310,7 +317,8 @@ SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t2.b FROM prt2 t2 WHERE t2.a = 0) -> Materialize -> Seq Scan on prt2_p3 t2_2 Filter: (a = 0) -(24 rows) + Settings: enable_partitionwise_join = 'on' +(25 rows) SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t2.b FROM prt2 t2 WHERE t2.a = 0) AND t1.b = 0 ORDER BY t1.a; a | b | c @@ -343,7 +351,8 @@ SELECT sum(t1.a), avg(t1.a), sum(t1.b), avg(t1.b) FROM prt1 t1 WHERE NOT EXISTS -> Seq Scan on prt1_p3 t1_2 -> Hash -> Seq Scan on prt2_p3 t2_2 -(17 rows) + Settings: enable_partitionwise_join = 'on' +(18 rows) SELECT sum(t1.a), avg(t1.a), sum(t1.b), avg(t1.b) FROM prt1 t1 WHERE NOT EXISTS (SELECT 1 FROM prt2 t2 WHERE t1.a = t2.b); sum | avg | sum | avg @@ -385,7 +394,8 @@ SELECT * FROM prt1 t1 LEFT JOIN LATERAL Index Cond: (a = t1_2.a) -> Index Scan using iprt2_p3_b on prt2_p3 t3_2 Index Cond: (b = t2_2.a) -(27 rows) + Settings: enable_partitionwise_join = 'on' +(28 rows) SELECT * FROM prt1 t1 LEFT JOIN LATERAL (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.b) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss @@ -438,7 +448,8 @@ SELECT t1.a, ss.t2a, ss.t2c FROM prt1 t1 LEFT JOIN LATERAL -> Seq Scan on prt1_p3 t2_2 -> Hash -> Seq Scan on prt2_p3 t3_2 -(26 rows) + Settings: enable_partitionwise_join = 'on' +(27 rows) SELECT t1.a, ss.t2a, ss.t2c FROM prt1 t1 LEFT JOIN LATERAL (SELECT t2.a AS t2a, t3.a AS t3a, t2.b t2b, t2.c t2c, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss @@ -502,7 +513,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_e t1, prt2_e t2 WHERE (t1.a + t1.b)/2 = -> Hash -> Seq Scan on prt1_e_p3 t1_2 Filter: (c = 0) -(21 rows) + Settings: enable_partitionwise_join = 'on' +(22 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_e t1, prt2_e t2 WHERE (t1.a + t1.b)/2 = (t2.b + t2.a)/2 AND t1.c = 0 ORDER BY t1.a, t2.b; a | c | b | c @@ -553,7 +565,8 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM prt1 t1, prt2 t2, prt1_e t Filter: (b = 0) -> Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t3_2 Index Cond: (((a + b) / 2) = t2_2.b) -(33 rows) + Settings: enable_partitionwise_join = 'on' +(34 rows) SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM prt1 t1, prt2 t2, prt1_e t3 WHERE t1.a = t2.b AND t1.a = (t3.a + t3.b)/2 AND t1.b = 0 ORDER BY t1.a, t2.b; a | c | b | c | ?column? | c @@ -601,7 +614,8 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 -> Hash -> Seq Scan on prt1_p3 t1_2 Filter: (b = 0) -(33 rows) + Settings: enable_partitionwise_join = 'on' +(34 rows) SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) LEFT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.b = 0 ORDER BY t1.a, t2.b, t3.a + t3.b; a | c | b | c | ?column? | c @@ -654,7 +668,8 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 Filter: (c = 0) -> Index Scan using iprt2_p3_b on prt2_p3 t2_2 Index Cond: (b = t1_2.a) -(30 rows) + Settings: enable_partitionwise_join = 'on' +(31 rows) SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b; a | c | b | c | ?column? | c @@ -721,7 +736,8 @@ SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * F -> Hash -> Seq Scan on prt1_e_p3 Filter: (c = 0) -(42 rows) + Settings: enable_partitionwise_join = 'on' +(43 rows) SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.a = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT 50 phv, * FROM prt1_e WHERE prt1_e.c = 0) t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a = t1.phv OR t2.b = t2.phv OR (t3.a + t3.b)/2 = t3.phv ORDER BY t1.a, t2.b, t3.a + t3.b; a | phv | b | phv | ?column? | phv @@ -776,7 +792,8 @@ SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1, prt1_e t2 WHER -> Index Scan using iprt1_p3_a on prt1_p3 t1_2 Index Cond: (a = ((t2_2.a + t2_2.b) / 2)) Filter: (b = 0) -(41 rows) + Settings: enable_partitionwise_join = 'on' +(42 rows) SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1, prt1_e t2 WHERE t1.a = 0 AND t1.b = (t2.a + t2.b)/2) AND t1.b = 0 ORDER BY t1.a; a | b | c @@ -830,7 +847,8 @@ SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN ( -> Index Scan using iprt1_p3_a on prt1_p3 t1_2 Index Cond: (a = t1_5.b) Filter: (b = 0) -(39 rows) + Settings: enable_partitionwise_join = 'on' +(40 rows) SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.c = 0)) AND t1.b = 0 ORDER BY t1.a; a | b | c @@ -846,8 +864,8 @@ SET enable_hashjoin TO off; SET enable_nestloop TO off; EXPLAIN (COSTS OFF) SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.c = 0)) AND t1.b = 0 ORDER BY t1.a; - QUERY PLAN ----------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------- Merge Append Sort Key: t1.a -> Merge Semi Join @@ -895,7 +913,8 @@ SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN ( Sort Key: (((t1_8.a + t1_8.b) / 2)) -> Seq Scan on prt1_e_p3 t1_8 Filter: (c = 0) -(47 rows) + Settings: enable_hashjoin = 'off', enable_nestloop = 'off', enable_partitionwise_join = 'on' +(48 rows) SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.c = 0)) AND t1.b = 0 ORDER BY t1.a; a | b | c @@ -908,8 +927,8 @@ SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN ( EXPLAIN (COSTS OFF) SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------- Sort Sort Key: t1.a, t2.b, ((t3.a + t3.b)) -> Append @@ -961,7 +980,8 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 -> Sort Sort Key: t2_2.b -> Seq Scan on prt2_p3 t2_2 -(51 rows) + Settings: enable_hashjoin = 'off', enable_nestloop = 'off', enable_partitionwise_join = 'on' +(52 rows) SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b; a | c | b | c | ?column? | c @@ -984,8 +1004,8 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 -- This should generate a partitionwise join, but currently fails to EXPLAIN (COSTS OFF) SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +---------------------------------------------------------------------------------------------- Sort Sort Key: prt1_p1.a, prt2_p2.b -> Merge Left Join @@ -1004,7 +1024,8 @@ SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * Filter: (b > 250) -> Seq Scan on prt2_p3 Filter: (b > 250) -(18 rows) + Settings: enable_hashjoin = 'off', enable_nestloop = 'off', enable_partitionwise_join = 'on' +(19 rows) SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b; a | b @@ -1024,8 +1045,8 @@ SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * -- partitionwise join does not apply EXPLAIN (COSTS OFF) SELECT t1.a, t2.b FROM prt1 t1, prt2 t2 WHERE t1::text = t2::text AND t1.a = t2.b ORDER BY t1.a; - QUERY PLAN ------------------------------------------------------------------------------------------ + QUERY PLAN +---------------------------------------------------------------------------------------------- Merge Join Merge Cond: ((t1.a = t2.b) AND (((((t1.*)::prt1))::text) = ((((t2.*)::prt2))::text))) -> Sort @@ -1042,7 +1063,8 @@ SELECT t1.a, t2.b FROM prt1 t1, prt2 t2 WHERE t1::text = t2::text AND t1.a = t2. -> Seq Scan on prt2_p1 t2 -> Seq Scan on prt2_p2 t2_1 -> Seq Scan on prt2_p3 t2_2 -(16 rows) + Settings: enable_hashjoin = 'off', enable_nestloop = 'off', enable_partitionwise_join = 'on' +(17 rows) SELECT t1.a, t2.b FROM prt1 t1, prt2 t2 WHERE t1::text = t2::text AND t1.a = t2.b ORDER BY t1.a; a | b @@ -1099,7 +1121,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.c = 0) t1 -> Hash -> Seq Scan on prt2_m_p3 Filter: (c = 0) -(24 rows) + Settings: enable_partitionwise_join = 'on' +(25 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.c = 0) t1 FULL JOIN (SELECT * FROM prt2_m WHERE prt2_m.c = 0) t2 ON (t1.a = (t2.b + t2.a)/2 AND t2.b = (t1.a + t1.b)/2) ORDER BY t1.a, t2.b; a | c | b | c @@ -1183,7 +1206,8 @@ SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM plt1 t1, pl -> Seq Scan on plt2_p3 t2_2 -> Hash -> Seq Scan on plt1_e_p3 t3_2 -(32 rows) + Settings: enable_partitionwise_join = 'on' +(33 rows) SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM plt1 t1, plt2 t2, plt1_e t3 WHERE t1.b = t2.b AND t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c; avg | avg | avg | c | c | c @@ -1205,19 +1229,21 @@ SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM plt1 t1, pl -- joins where one of the relations is proven empty EXPLAIN (COSTS OFF) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a = 1 AND t1.a = 2; - QUERY PLAN --------------------------- + QUERY PLAN +-------------------------------------------- Result One-Time Filter: false -(2 rows) + Settings: enable_partitionwise_join = 'on' +(3 rows) EXPLAIN (COSTS OFF) SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 LEFT JOIN prt2 t2 ON t1.a = t2.b; - QUERY PLAN --------------------------- + QUERY PLAN +-------------------------------------------- Result One-Time Filter: false -(2 rows) + Settings: enable_partitionwise_join = 'on' +(3 rows) EXPLAIN (COSTS OFF) SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b, prt1 t3 WHERE t2.b = t3.a; @@ -1244,7 +1270,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 -> Hash -> Result One-Time Filter: false -(21 rows) + Settings: enable_partitionwise_join = 'on' +(22 rows) EXPLAIN (COSTS OFF) SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t1.a, t2.b; @@ -1264,7 +1291,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 -> Hash -> Result One-Time Filter: false -(14 rows) + Settings: enable_partitionwise_join = 'on' +(15 rows) -- -- tests for hash partitioned tables. @@ -1327,7 +1355,8 @@ SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM pht1 t1, ph -> Seq Scan on pht2_p3 t2_2 -> Hash -> Seq Scan on pht1_e_p3 t3_2 -(32 rows) + Settings: enable_partitionwise_join = 'on' +(33 rows) SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM pht1 t1, pht2 t2, pht1_e t3 WHERE t1.b = t2.b AND t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c; avg | avg | avg | c | c | c @@ -1372,7 +1401,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = -> Hash -> Seq Scan on prt1_p3 t1_2 Filter: (b = 0) -(21 rows) + Settings: enable_partitionwise_join = 'on' +(22 rows) -- test default partition behavior for list ALTER TABLE plt1 DETACH PARTITION plt1_p3; @@ -1408,7 +1438,8 @@ SELECT avg(t1.a), avg(t2.b), t1.c, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c -> Hash -> Seq Scan on plt1_p3 t1_2 Filter: ((a % 25) = 0) -(23 rows) + Settings: enable_partitionwise_join = 'on' +(24 rows) -- -- multiple levels of partitioning @@ -1466,7 +1497,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1 -> Hash -> Seq Scan on prt1_l_p3_p1 t1_3 Filter: (b = 0) -(28 rows) + Settings: enable_partitionwise_join = 'on' +(29 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b; a | c | b | c @@ -1511,7 +1543,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b -> Hash -> Seq Scan on prt1_l_p3_p1 t1_3 Filter: (b = 0) -(29 rows) + Settings: enable_partitionwise_join = 'on' +(30 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.b = 0 ORDER BY t1.a, t2.b; a | c | b | c @@ -1564,7 +1597,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b -> Hash -> Seq Scan on prt2_l_p3_p1 t2_3 Filter: (a = 0) -(29 rows) + Settings: enable_partitionwise_join = 'on' +(30 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.a = 0 ORDER BY t1.a, t2.b; a | c | b | c @@ -1615,7 +1649,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.b = 0) t1 -> Hash -> Seq Scan on prt2_l_p3_p1 Filter: (a = 0) -(31 rows) + Settings: enable_partitionwise_join = 'on' +(32 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.b = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.a = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b; a | c | b | c @@ -1689,7 +1724,8 @@ SELECT * FROM prt1_l t1 LEFT JOIN LATERAL Filter: ((t1_3.a = a) AND ((t1_3.c)::text = (c)::text)) -> Seq Scan on prt1_l_p3_p2 t2_4 Filter: ((t1_3.a = a) AND ((t1_3.c)::text = (c)::text)) -(44 rows) + Settings: enable_partitionwise_join = 'on' +(45 rows) SELECT * FROM prt1_l t1 LEFT JOIN LATERAL (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.b AS t3b, least(t1.a,t2.a,t3.b) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss @@ -1726,7 +1762,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE a = 1 AND a = 2) -> Hash -> Result One-Time Filter: false -(11 rows) + Settings: enable_partitionwise_join = 'on' +(12 rows) -- Test case to verify proper handling of subqueries in a partitioned delete. -- The weird-looking lateral join is just there to force creation of a @@ -1769,7 +1806,8 @@ WHERE EXISTS ( -> Subquery Scan on ss_2 -> Limit -> Seq Scan on int8_tbl int8_tbl_2 -(28 rows) + Settings: enable_partitionwise_join = 'on' +(29 rows) -- -- negative testcases @@ -1812,7 +1850,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt4_n t2 WHERE t1.a = t2.a; -> Seq Scan on prt4_n_p1 t2 -> Seq Scan on prt4_n_p2 t2_1 -> Seq Scan on prt4_n_p3 t2_2 -(11 rows) + Settings: enable_partitionwise_join = 'on' +(12 rows) EXPLAIN (COSTS OFF) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt4_n t2, prt2 t3 WHERE t1.a = t2.a and t1.a = t3.b; @@ -1841,7 +1880,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt4_n t2, prt2 t3 WHERE t1.a = t2.a -> Seq Scan on prt1_p3 t1_2 -> Hash -> Seq Scan on prt2_p3 t3_2 -(23 rows) + Settings: enable_partitionwise_join = 'on' +(24 rows) -- partitionwise join can not be applied if there are no equi-join conditions -- between partition keys @@ -1861,7 +1901,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON (t1.a < t2.b); Index Cond: (b > t1.a) -> Index Scan using iprt2_p3_b on prt2_p3 t2_2 Index Cond: (b > t1.a) -(12 rows) + Settings: enable_partitionwise_join = 'on' +(13 rows) -- equi-join with join condition on partial keys does not qualify for -- partitionwise join @@ -1880,7 +1921,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1, prt2_m t2 WHERE t1.a = (t2.b + t2. -> Seq Scan on prt1_m_p1 t1 -> Seq Scan on prt1_m_p2 t1_1 -> Seq Scan on prt1_m_p3 t1_2 -(11 rows) + Settings: enable_partitionwise_join = 'on' +(12 rows) -- equi-join between out-of-order partition key columns does not qualify for -- partitionwise join @@ -1899,7 +1941,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1 LEFT JOIN prt2_m t2 ON t1.a = t2.b; -> Seq Scan on prt2_m_p1 t2 -> Seq Scan on prt2_m_p2 t2_1 -> Seq Scan on prt2_m_p3 t2_2 -(11 rows) + Settings: enable_partitionwise_join = 'on' +(12 rows) -- equi-join between non-key columns does not qualify for partitionwise join EXPLAIN (COSTS OFF) @@ -1917,7 +1960,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1 LEFT JOIN prt2_m t2 ON t1.c = t2.c; -> Seq Scan on prt2_m_p1 t2 -> Seq Scan on prt2_m_p2 t2_1 -> Seq Scan on prt2_m_p3 t2_2 -(11 rows) + Settings: enable_partitionwise_join = 'on' +(12 rows) -- partitionwise join can not be applied between tables with different -- partition lists @@ -1934,7 +1978,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 LEFT JOIN prt2_n t2 ON (t1.c = t2.c -> Append -> Seq Scan on prt1_n_p1 t1 -> Seq Scan on prt1_n_p2 t1_1 -(9 rows) + Settings: enable_partitionwise_join = 'on' +(10 rows) EXPLAIN (COSTS OFF) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 JOIN prt2_n t2 ON (t1.c = t2.c) JOIN plt1 t3 ON (t1.c = t3.c); @@ -1956,7 +2001,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 JOIN prt2_n t2 ON (t1.c = t2.c) JOI -> Append -> Seq Scan on prt1_n_p1 t1 -> Seq Scan on prt1_n_p2 t1_1 -(16 rows) + Settings: enable_partitionwise_join = 'on' +(17 rows) -- partitionwise join can not be applied for a join between list and range -- partitioned table @@ -1974,7 +2020,8 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 FULL JOIN prt1 t2 ON (t1.c = t2.c); -> Append -> Seq Scan on prt1_n_p1 t1 -> Seq Scan on prt1_n_p2 t1_1 -(10 rows) + Settings: enable_partitionwise_join = 'on' +(11 rows) -- partitionwise join can not be applied if only one of joining table has -- default partition @@ -2001,5 +2048,6 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = Filter: (b = 0) -> Seq Scan on prt1_p3 t1_2 Filter: (b = 0) -(16 rows) + Settings: enable_partitionwise_join = 'on' +(17 rows) diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index bd64bed8fc..a0eb3f62d5 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -1623,7 +1623,7 @@ create table ab_a3_b1 partition of ab_a3 for values in (1); create table ab_a3_b2 partition of ab_a3 for values in (2); create table ab_a3_b3 partition of ab_a3 for values in (3); -- Disallow index only scans as concurrent transactions may stop visibility --- bits being set causing "Heap Fetches" to be unstable in the EXPLAIN ANALYZE +-- bits being set causing "Heap Fetches" to be unstable in the EXPLAIN EXEC -- output. set enable_indexonlyscan = off; prepare ab_q1 (int, int, int) as @@ -1655,7 +1655,7 @@ execute ab_q1 (1, 8, 3); ---+--- (0 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2, 3); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 2, 3); QUERY PLAN --------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1666,9 +1666,10 @@ explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2, 3); Filter: ((a >= $1) AND (a <= $2) AND (b <= $3)) -> Seq Scan on ab_a2_b3 (actual rows=0 loops=1) Filter: ((a >= $1) AND (a <= $2) AND (b <= $3)) -(8 rows) + Settings: enable_indexonlyscan = 'off' +(9 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q1 (1, 2, 3); +explain (exec, costs off, summary off, timing off) execute ab_q1 (1, 2, 3); QUERY PLAN --------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1685,7 +1686,8 @@ explain (analyze, costs off, summary off, timing off) execute ab_q1 (1, 2, 3); Filter: ((a >= $1) AND (a <= $2) AND (b <= $3)) -> Seq Scan on ab_a2_b3 (actual rows=0 loops=1) Filter: ((a >= $1) AND (a <= $2) AND (b <= $3)) -(14 rows) + Settings: enable_indexonlyscan = 'off' +(15 rows) deallocate ab_q1; -- Runtime pruning after optimizer pruning @@ -1718,7 +1720,7 @@ execute ab_q1 (1, 8); --- (0 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 2); QUERY PLAN ------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1727,9 +1729,10 @@ explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2); Filter: ((a >= $1) AND (a <= $2) AND (b < 3)) -> Seq Scan on ab_a2_b2 (actual rows=0 loops=1) Filter: ((a >= $1) AND (a <= $2) AND (b < 3)) -(6 rows) + Settings: enable_indexonlyscan = 'off' +(7 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 4); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 4); QUERY PLAN ------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1742,7 +1745,8 @@ explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 4); Filter: ((a >= $1) AND (a <= $2) AND (b < 3)) -> Seq Scan on ab_a3_b2 (actual rows=0 loops=1) Filter: ((a >= $1) AND (a <= $2) AND (b < 3)) -(10 rows) + Settings: enable_indexonlyscan = 'off' +(11 rows) -- Ensure a mix of PARAM_EXTERN and PARAM_EXEC Params work together at -- different levels of partitioning. @@ -1773,7 +1777,7 @@ execute ab_q2 (1, 8); --- (0 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q2 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q2 (2, 2); QUERY PLAN -------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1786,7 +1790,8 @@ explain (analyze, costs off, summary off, timing off) execute ab_q2 (2, 2); Filter: ((a >= $1) AND (a <= $2) AND (b < $0)) -> Seq Scan on ab_a2_b3 (never executed) Filter: ((a >= $1) AND (a <= $2) AND (b < $0)) -(10 rows) + Settings: enable_indexonlyscan = 'off' +(11 rows) -- As above, but swap the PARAM_EXEC Param to the first partition level prepare ab_q3 (int, int) as @@ -1816,7 +1821,7 @@ execute ab_q3 (1, 8); --- (0 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q3 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q3 (2, 2); QUERY PLAN -------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1829,7 +1834,8 @@ explain (analyze, costs off, summary off, timing off) execute ab_q3 (2, 2); Filter: ((b >= $1) AND (b <= $2) AND (a < $0)) -> Seq Scan on ab_a3_b2 (never executed) Filter: ((b >= $1) AND (b <= $2) AND (a < $0)) -(10 rows) + Settings: enable_indexonlyscan = 'off' +(11 rows) -- Test a backwards Append scan create table list_part (a int) partition by list (a); @@ -1857,48 +1863,63 @@ begin; -- Test run-time pruning using stable functions create function list_part_fn(int) returns int as $$ begin return $1; end;$$ language plpgsql stable; -- Ensure pruning works using a stable function containing no Vars -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1); +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1); QUERY PLAN ------------------------------------------------------ Append (actual rows=1 loops=1) + Buffers: shared hit=1 Subplans Removed: 3 -> Seq Scan on list_part1 (actual rows=1 loops=1) Filter: (a = list_part_fn(1)) -(4 rows) + Buffers: shared hit=1 + Settings: enable_indexonlyscan = 'off' +(7 rows) -- Ensure pruning does not take place when the function has a Var parameter -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(a); +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(a); QUERY PLAN ------------------------------------------------------ Append (actual rows=4 loops=1) + Buffers: shared hit=4 -> Seq Scan on list_part1 (actual rows=1 loops=1) Filter: (a = list_part_fn(a)) + Buffers: shared hit=1 -> Seq Scan on list_part2 (actual rows=1 loops=1) Filter: (a = list_part_fn(a)) + Buffers: shared hit=1 -> Seq Scan on list_part3 (actual rows=1 loops=1) Filter: (a = list_part_fn(a)) + Buffers: shared hit=1 -> Seq Scan on list_part4 (actual rows=1 loops=1) Filter: (a = list_part_fn(a)) -(9 rows) + Buffers: shared hit=1 + Settings: enable_indexonlyscan = 'off' +(15 rows) -- Ensure pruning does not take place when the expression contains a Var. -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1) + a; +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1) + a; QUERY PLAN ------------------------------------------------------ Append (actual rows=0 loops=1) + Buffers: shared hit=4 -> Seq Scan on list_part1 (actual rows=0 loops=1) Filter: (a = (list_part_fn(1) + a)) Rows Removed by Filter: 1 + Buffers: shared hit=1 -> Seq Scan on list_part2 (actual rows=0 loops=1) Filter: (a = (list_part_fn(1) + a)) Rows Removed by Filter: 1 + Buffers: shared hit=1 -> Seq Scan on list_part3 (actual rows=0 loops=1) Filter: (a = (list_part_fn(1) + a)) Rows Removed by Filter: 1 + Buffers: shared hit=1 -> Seq Scan on list_part4 (actual rows=0 loops=1) Filter: (a = (list_part_fn(1) + a)) Rows Removed by Filter: 1 -(13 rows) + Buffers: shared hit=1 + Settings: enable_indexonlyscan = 'off' +(19 rows) rollback; drop table list_part; @@ -1913,7 +1934,7 @@ declare ln text; begin for ln in - execute format('explain (analyze, costs off, summary off, timing off) %s', + execute format('explain (exec, costs off, summary off, timing off) %s', $1) loop if ln like '%Parallel%' then @@ -1963,8 +1984,8 @@ execute ab_q4 (1, 8); (1 row) select explain_parallel_append('execute ab_q4 (2, 2)'); - explain_parallel_append -------------------------------------------------------------------------------- + explain_parallel_append +---------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate (actual rows=1 loops=1) -> Gather (actual rows=3 loops=1) Workers Planned: 2 @@ -1978,7 +1999,8 @@ select explain_parallel_append('execute ab_q4 (2, 2)'); Filter: ((a >= $1) AND (a <= $2) AND (b < 4)) -> Parallel Seq Scan on ab_a2_b3 (actual rows=0 loops=N) Filter: ((a >= $1) AND (a <= $2) AND (b < 4)) -(13 rows) + Settings: enable_indexonlyscan = 'off', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(14 rows) -- Test run-time pruning with IN lists. prepare ab_q5 (int, int, int) as @@ -2016,8 +2038,8 @@ execute ab_q5 (1, 2, 3); (1 row) select explain_parallel_append('execute ab_q5 (1, 1, 1)'); - explain_parallel_append -------------------------------------------------------------------------------- + explain_parallel_append +---------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate (actual rows=1 loops=1) -> Gather (actual rows=3 loops=1) Workers Planned: 2 @@ -2031,11 +2053,12 @@ select explain_parallel_append('execute ab_q5 (1, 1, 1)'); Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3]))) -> Parallel Seq Scan on ab_a1_b3 (actual rows=0 loops=N) Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3]))) -(13 rows) + Settings: enable_indexonlyscan = 'off', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(14 rows) select explain_parallel_append('execute ab_q5 (2, 3, 3)'); - explain_parallel_append -------------------------------------------------------------------------------- + explain_parallel_append +---------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate (actual rows=1 loops=1) -> Gather (actual rows=3 loops=1) Workers Planned: 2 @@ -2055,13 +2078,14 @@ select explain_parallel_append('execute ab_q5 (2, 3, 3)'); Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3]))) -> Parallel Seq Scan on ab_a3_b3 (actual rows=0 loops=N) Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3]))) -(19 rows) + Settings: enable_indexonlyscan = 'off', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(20 rows) -- Try some params whose values do not belong to any partition. -- We'll still get a single subplan in this case, but it should not be scanned. select explain_parallel_append('execute ab_q5 (33, 44, 55)'); - explain_parallel_append -------------------------------------------------------------------------------- + explain_parallel_append +---------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate (actual rows=1 loops=1) -> Gather (actual rows=3 loops=1) Workers Planned: 2 @@ -2071,12 +2095,13 @@ select explain_parallel_append('execute ab_q5 (33, 44, 55)'); Subplans Removed: 8 -> Parallel Seq Scan on ab_a1_b1 (never executed) Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3]))) -(9 rows) + Settings: enable_indexonlyscan = 'off', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(10 rows) -- Test Parallel Append with PARAM_EXEC Params select explain_parallel_append('select count(*) from ab where (a = (select 1) or a = (select 3)) and b = 2'); - explain_parallel_append -------------------------------------------------------------------------- + explain_parallel_append +---------------------------------------------------------------------------------------------------------------------------------- Aggregate (actual rows=1 loops=1) InitPlan 1 (returns $0) -> Result (actual rows=1 loops=1) @@ -2093,7 +2118,8 @@ select explain_parallel_append('select count(*) from ab where (a = (select 1) or Filter: ((b = 2) AND ((a = $0) OR (a = $1))) -> Parallel Seq Scan on ab_a3_b2 (actual rows=0 loops=N) Filter: ((b = 2) AND ((a = $0) OR (a = $1))) -(16 rows) + Settings: enable_indexonlyscan = 'off', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(17 rows) -- Test pruning during parallel nested loop query create table lprt_a (a int not null); @@ -2114,23 +2140,32 @@ create index ab_a3_b3_a_idx on ab_a3_b3 (a); set enable_hashjoin = 0; set enable_mergejoin = 0; select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on ab.a = a.a where a.a in(0, 0, 1)'); - explain_parallel_append ---------------------------------------------------------------------------------------------------- + explain_parallel_append +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate (actual rows=1 loops=1) + Buffers: shared hit=13 -> Gather (actual rows=2 loops=1) Workers Planned: 1 Workers Launched: 1 + Buffers: shared hit=13 -> Partial Aggregate (actual rows=1 loops=2) + Buffers: shared hit=13 -> Nested Loop (actual rows=0 loops=2) + Buffers: shared hit=13 -> Parallel Seq Scan on lprt_a a (actual rows=51 loops=N) Filter: (a = ANY ('{0,0,1}'::integer[])) + Buffers: shared hit=1 -> Append (actual rows=0 loops=102) + Buffers: shared hit=12 -> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (actual rows=0 loops=2) Index Cond: (a = a.a) + Buffers: shared hit=4 -> Index Scan using ab_a1_b2_a_idx on ab_a1_b2 (actual rows=0 loops=2) Index Cond: (a = a.a) + Buffers: shared hit=4 -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 (actual rows=0 loops=2) Index Cond: (a = a.a) + Buffers: shared hit=4 -> Index Scan using ab_a2_b1_a_idx on ab_a2_b1 (never executed) Index Cond: (a = a.a) -> Index Scan using ab_a2_b2_a_idx on ab_a2_b2 (never executed) @@ -2143,28 +2178,38 @@ select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on Index Cond: (a = a.a) -> Index Scan using ab_a3_b3_a_idx on ab_a3_b3 (never executed) Index Cond: (a = a.a) -(27 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(37 rows) -- Ensure the same partitions are pruned when we make the nested loop -- parameter an Expr rather than a plain Param. select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on ab.a = a.a + 0 where a.a in(0, 0, 1)'); - explain_parallel_append ---------------------------------------------------------------------------------------------------- + explain_parallel_append +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate (actual rows=1 loops=1) + Buffers: shared hit=13 -> Gather (actual rows=2 loops=1) Workers Planned: 1 Workers Launched: 1 + Buffers: shared hit=13 -> Partial Aggregate (actual rows=1 loops=2) + Buffers: shared hit=13 -> Nested Loop (actual rows=0 loops=2) + Buffers: shared hit=13 -> Parallel Seq Scan on lprt_a a (actual rows=51 loops=N) Filter: (a = ANY ('{0,0,1}'::integer[])) + Buffers: shared hit=1 -> Append (actual rows=0 loops=102) + Buffers: shared hit=12 -> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (actual rows=0 loops=2) Index Cond: (a = (a.a + 0)) + Buffers: shared hit=4 -> Index Scan using ab_a1_b2_a_idx on ab_a1_b2 (actual rows=0 loops=2) Index Cond: (a = (a.a + 0)) + Buffers: shared hit=4 -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 (actual rows=0 loops=2) Index Cond: (a = (a.a + 0)) + Buffers: shared hit=4 -> Index Scan using ab_a2_b1_a_idx on ab_a2_b1 (never executed) Index Cond: (a = (a.a + 0)) -> Index Scan using ab_a2_b2_a_idx on ab_a2_b2 (never executed) @@ -2177,27 +2222,37 @@ select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on Index Cond: (a = (a.a + 0)) -> Index Scan using ab_a3_b3_a_idx on ab_a3_b3 (never executed) Index Cond: (a = (a.a + 0)) -(27 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(37 rows) insert into lprt_a values(3),(3); select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on ab.a = a.a where a.a in(1, 0, 3)'); - explain_parallel_append ---------------------------------------------------------------------------------------------------- + explain_parallel_append +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate (actual rows=1 loops=1) + Buffers: shared hit=25 -> Gather (actual rows=2 loops=1) Workers Planned: 1 Workers Launched: 1 + Buffers: shared hit=25 -> Partial Aggregate (actual rows=1 loops=2) + Buffers: shared hit=25 -> Nested Loop (actual rows=0 loops=2) + Buffers: shared hit=25 -> Parallel Seq Scan on lprt_a a (actual rows=52 loops=N) Filter: (a = ANY ('{1,0,3}'::integer[])) + Buffers: shared hit=1 -> Append (actual rows=0 loops=104) + Buffers: shared hit=24 -> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (actual rows=0 loops=2) Index Cond: (a = a.a) + Buffers: shared hit=4 -> Index Scan using ab_a1_b2_a_idx on ab_a1_b2 (actual rows=0 loops=2) Index Cond: (a = a.a) + Buffers: shared hit=4 -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 (actual rows=0 loops=2) Index Cond: (a = a.a) + Buffers: shared hit=4 -> Index Scan using ab_a2_b1_a_idx on ab_a2_b1 (never executed) Index Cond: (a = a.a) -> Index Scan using ab_a2_b2_a_idx on ab_a2_b2 (never executed) @@ -2206,31 +2261,44 @@ select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on Index Cond: (a = a.a) -> Index Scan using ab_a3_b1_a_idx on ab_a3_b1 (actual rows=0 loops=2) Index Cond: (a = a.a) + Buffers: shared hit=4 -> Index Scan using ab_a3_b2_a_idx on ab_a3_b2 (actual rows=0 loops=2) Index Cond: (a = a.a) + Buffers: shared hit=4 -> Index Scan using ab_a3_b3_a_idx on ab_a3_b3 (actual rows=0 loops=2) Index Cond: (a = a.a) -(27 rows) + Buffers: shared hit=4 + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(40 rows) select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on ab.a = a.a where a.a in(1, 0, 0)'); - explain_parallel_append ---------------------------------------------------------------------------------------------------- + explain_parallel_append +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate (actual rows=1 loops=1) + Buffers: shared hit=13 -> Gather (actual rows=2 loops=1) Workers Planned: 1 Workers Launched: 1 + Buffers: shared hit=13 -> Partial Aggregate (actual rows=1 loops=2) + Buffers: shared hit=13 -> Nested Loop (actual rows=0 loops=2) + Buffers: shared hit=13 -> Parallel Seq Scan on lprt_a a (actual rows=51 loops=N) Filter: (a = ANY ('{1,0,0}'::integer[])) Rows Removed by Filter: 1 + Buffers: shared hit=1 -> Append (actual rows=0 loops=102) + Buffers: shared hit=12 -> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (actual rows=0 loops=2) Index Cond: (a = a.a) + Buffers: shared hit=4 -> Index Scan using ab_a1_b2_a_idx on ab_a1_b2 (actual rows=0 loops=2) Index Cond: (a = a.a) + Buffers: shared hit=4 -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 (actual rows=0 loops=2) Index Cond: (a = a.a) + Buffers: shared hit=4 -> Index Scan using ab_a2_b1_a_idx on ab_a2_b1 (never executed) Index Cond: (a = a.a) -> Index Scan using ab_a2_b2_a_idx on ab_a2_b2 (never executed) @@ -2243,21 +2311,27 @@ select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on Index Cond: (a = a.a) -> Index Scan using ab_a3_b3_a_idx on ab_a3_b3 (never executed) Index Cond: (a = a.a) -(28 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(38 rows) delete from lprt_a where a = 1; select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on ab.a = a.a where a.a in(1, 0, 0)'); - explain_parallel_append --------------------------------------------------------------------------------------------- + explain_parallel_append +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate (actual rows=1 loops=1) + Buffers: shared hit=1 -> Gather (actual rows=2 loops=1) Workers Planned: 1 Workers Launched: 1 + Buffers: shared hit=1 -> Partial Aggregate (actual rows=1 loops=2) + Buffers: shared hit=1 -> Nested Loop (actual rows=0 loops=2) + Buffers: shared hit=1 -> Parallel Seq Scan on lprt_a a (actual rows=50 loops=N) Filter: (a = ANY ('{1,0,0}'::integer[])) Rows Removed by Filter: 1 + Buffers: shared hit=1 -> Append (actual rows=0 loops=100) -> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (never executed) Index Cond: (a = a.a) @@ -2277,7 +2351,8 @@ select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on Index Cond: (a = a.a) -> Index Scan using ab_a3_b3_a_idx on ab_a3_b3 (never executed) Index Cond: (a = a.a) -(28 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(34 rows) reset enable_hashjoin; reset enable_mergejoin; @@ -2286,17 +2361,22 @@ reset parallel_tuple_cost; reset min_parallel_table_scan_size; reset max_parallel_workers_per_gather; -- Test run-time partition pruning with an initplan -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from ab where a = (select max(a) from lprt_a) and b = (select max(a)-1 from lprt_a); QUERY PLAN ------------------------------------------------------------------------- Append (actual rows=0 loops=1) + Buffers: shared hit=4 InitPlan 1 (returns $0) -> Aggregate (actual rows=1 loops=1) + Buffers: shared hit=1 -> Seq Scan on lprt_a (actual rows=102 loops=1) + Buffers: shared hit=1 InitPlan 2 (returns $1) -> Aggregate (actual rows=1 loops=1) + Buffers: shared hit=1 -> Seq Scan on lprt_a lprt_a_1 (actual rows=102 loops=1) + Buffers: shared hit=1 -> Bitmap Heap Scan on ab_a1_b1 (never executed) Recheck Cond: (a = $0) Filter: (b = $1) @@ -2335,29 +2415,36 @@ select * from ab where a = (select max(a) from lprt_a) and b = (select max(a)-1 -> Bitmap Heap Scan on ab_a3_b2 (actual rows=0 loops=1) Recheck Cond: (a = $0) Filter: (b = $1) + Buffers: shared hit=2 -> Bitmap Index Scan on ab_a3_b2_a_idx (actual rows=0 loops=1) Index Cond: (a = $0) + Buffers: shared hit=2 -> Bitmap Heap Scan on ab_a3_b3 (never executed) Recheck Cond: (a = $0) Filter: (b = $1) -> Bitmap Index Scan on ab_a3_b3_a_idx (never executed) Index Cond: (a = $0) -(52 rows) + Settings: enable_indexonlyscan = 'off' +(60 rows) -- Test run-time partition pruning with UNION ALL parents -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from (select * from ab where a = 1 union all select * from ab) ab where b = (select 1); QUERY PLAN ------------------------------------------------------------------------------- Append (actual rows=0 loops=1) + Buffers: shared hit=2 InitPlan 1 (returns $0) -> Result (actual rows=1 loops=1) -> Append (actual rows=0 loops=1) + Buffers: shared hit=2 -> Bitmap Heap Scan on ab_a1_b1 ab_a1_b1_1 (actual rows=0 loops=1) Recheck Cond: (a = 1) Filter: (b = $0) + Buffers: shared hit=2 -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1) Index Cond: (a = 1) + Buffers: shared hit=2 -> Bitmap Heap Scan on ab_a1_b2 ab_a1_b2_1 (never executed) Recheck Cond: (a = 1) Filter: (b = $0) @@ -2386,22 +2473,27 @@ select * from (select * from ab where a = 1 union all select * from ab) ab where Filter: (b = $0) -> Seq Scan on ab_a3_b3 (never executed) Filter: (b = $0) -(37 rows) + Settings: enable_indexonlyscan = 'off' +(42 rows) -- A case containing a UNION ALL with a non-partitioned child. -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from (select * from ab where a = 1 union all (values(10,5)) union all select * from ab) ab where b = (select 1); QUERY PLAN ------------------------------------------------------------------------------- Append (actual rows=0 loops=1) + Buffers: shared hit=2 InitPlan 1 (returns $0) -> Result (actual rows=1 loops=1) -> Append (actual rows=0 loops=1) + Buffers: shared hit=2 -> Bitmap Heap Scan on ab_a1_b1 ab_a1_b1_1 (actual rows=0 loops=1) Recheck Cond: (a = 1) Filter: (b = $0) + Buffers: shared hit=2 -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1) Index Cond: (a = 1) + Buffers: shared hit=2 -> Bitmap Heap Scan on ab_a1_b2 ab_a1_b2_1 (never executed) Recheck Cond: (a = 1) Filter: (b = $0) @@ -2432,7 +2524,8 @@ select * from (select * from ab where a = 1 union all (values(10,5)) union all s Filter: (b = $0) -> Seq Scan on ab_a3_b3 (never executed) Filter: (b = $0) -(39 rows) + Settings: enable_indexonlyscan = 'off' +(44 rows) -- Another UNION ALL test, but containing a mix of exec init and exec run-time pruning. create table xy_1 (x int, y int); @@ -2449,10 +2542,11 @@ union all select tableoid::regclass,a,b from ab ) ab where a = $1 and b = (select -10); -- Ensure the xy_1 subplan is not pruned. -explain (analyze, costs off, summary off, timing off) execute ab_q6(1); - QUERY PLAN --------------------------------------------------------- +explain (exec, costs off, summary off, timing off) execute ab_q6(1); + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------- Append (actual rows=0 loops=1) + Buffers: shared hit=1 InitPlan 1 (returns $0) -> Result (actual rows=1 loops=1) Subplans Removed: 12 @@ -2465,13 +2559,15 @@ explain (analyze, costs off, summary off, timing off) execute ab_q6(1); -> Seq Scan on xy_1 (actual rows=0 loops=1) Filter: ((x = $1) AND (y = $0)) Rows Removed by Filter: 1 + Buffers: shared hit=1 -> Seq Scan on ab_a1_b1 ab_a1_b1_1 (never executed) Filter: ((a = $1) AND (b = $0)) -> Seq Scan on ab_a1_b2 ab_a1_b2_1 (never executed) Filter: ((a = $1) AND (b = $0)) -> Seq Scan on ab_a1_b3 ab_a1_b3_1 (never executed) Filter: ((a = $1) AND (b = $0)) -(19 rows) + Settings: enable_bitmapscan = 'off', enable_indexonlyscan = 'off', enable_indexscan = 'off', plan_cache_mode = 'force_generic_plan' +(22 rows) -- Ensure we see just the xy_1 row. execute ab_q6(100); @@ -2491,7 +2587,7 @@ deallocate ab_q5; deallocate ab_q6; -- UPDATE on a partition subtree has been seen to have problems. insert into ab values (1,2); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a; QUERY PLAN ------------------------------------------------------------------------------------- @@ -2499,68 +2595,103 @@ update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a; Update on ab_a1_b1 Update on ab_a1_b2 Update on ab_a1_b3 + Buffers: shared hit=25 dirtied=3 written=2 -> Nested Loop (actual rows=0 loops=1) + Buffers: shared hit=8 -> Append (actual rows=1 loops=1) + Buffers: shared hit=6 -> Bitmap Heap Scan on ab_a1_b1 ab_a1_b1_1 (actual rows=0 loops=1) Recheck Cond: (a = 1) + Buffers: shared hit=2 -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1) Index Cond: (a = 1) + Buffers: shared hit=2 -> Bitmap Heap Scan on ab_a1_b2 ab_a1_b2_1 (actual rows=1 loops=1) Recheck Cond: (a = 1) Heap Blocks: exact=1 + Buffers: shared hit=2 -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1) Index Cond: (a = 1) + Buffers: shared hit=1 -> Bitmap Heap Scan on ab_a1_b3 ab_a1_b3_1 (actual rows=0 loops=1) Recheck Cond: (a = 1) + Buffers: shared hit=2 -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=0 loops=1) Index Cond: (a = 1) + Buffers: shared hit=2 -> Materialize (actual rows=0 loops=1) + Buffers: shared hit=2 -> Bitmap Heap Scan on ab_a1_b1 (actual rows=0 loops=1) Recheck Cond: (a = 1) + Buffers: shared hit=2 -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1) Index Cond: (a = 1) + Buffers: shared hit=2 -> Nested Loop (actual rows=1 loops=1) + Buffers: shared hit=8 -> Append (actual rows=1 loops=1) + Buffers: shared hit=6 -> Bitmap Heap Scan on ab_a1_b1 ab_a1_b1_1 (actual rows=0 loops=1) Recheck Cond: (a = 1) + Buffers: shared hit=2 -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1) Index Cond: (a = 1) + Buffers: shared hit=2 -> Bitmap Heap Scan on ab_a1_b2 ab_a1_b2_1 (actual rows=1 loops=1) Recheck Cond: (a = 1) Heap Blocks: exact=1 + Buffers: shared hit=2 -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1) Index Cond: (a = 1) + Buffers: shared hit=1 -> Bitmap Heap Scan on ab_a1_b3 ab_a1_b3_1 (actual rows=0 loops=1) Recheck Cond: (a = 1) + Buffers: shared hit=2 -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=1 loops=1) Index Cond: (a = 1) + Buffers: shared hit=2 -> Materialize (actual rows=1 loops=1) + Buffers: shared hit=2 -> Bitmap Heap Scan on ab_a1_b2 (actual rows=1 loops=1) Recheck Cond: (a = 1) Heap Blocks: exact=1 + Buffers: shared hit=2 -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1) Index Cond: (a = 1) + Buffers: shared hit=1 -> Nested Loop (actual rows=0 loops=1) + Buffers: shared hit=6 -> Append (actual rows=1 loops=1) + Buffers: shared hit=5 -> Bitmap Heap Scan on ab_a1_b1 ab_a1_b1_1 (actual rows=0 loops=1) Recheck Cond: (a = 1) + Buffers: shared hit=2 -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1) Index Cond: (a = 1) + Buffers: shared hit=2 -> Bitmap Heap Scan on ab_a1_b2 ab_a1_b2_1 (actual rows=1 loops=1) Recheck Cond: (a = 1) Heap Blocks: exact=1 + Buffers: shared hit=2 -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1) Index Cond: (a = 1) + Buffers: shared hit=1 -> Bitmap Heap Scan on ab_a1_b3 ab_a1_b3_1 (actual rows=0 loops=1) Recheck Cond: (a = 1) + Buffers: shared hit=1 -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=1 loops=1) Index Cond: (a = 1) + Buffers: shared hit=1 -> Materialize (actual rows=0 loops=1) + Buffers: shared hit=1 -> Bitmap Heap Scan on ab_a1_b3 (actual rows=0 loops=1) Recheck Cond: (a = 1) + Buffers: shared hit=1 -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=1 loops=1) Index Cond: (a = 1) -(65 rows) + Buffers: shared hit=1 + Settings: enable_indexonlyscan = 'off' +(100 rows) table ab; a | b @@ -2571,7 +2702,7 @@ table ab; -- Test UPDATE where source relation has run-time pruning enabled truncate ab; insert into ab values (1, 1), (1, 2), (1, 3), (2, 1); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) update ab_a1 set b = 3 from ab_a2 where ab_a2.b = (select 1); QUERY PLAN ---------------------------------------------------------------------- @@ -2579,39 +2710,56 @@ update ab_a1 set b = 3 from ab_a2 where ab_a2.b = (select 1); Update on ab_a1_b1 Update on ab_a1_b2 Update on ab_a1_b3 + Buffers: shared hit=13 InitPlan 1 (returns $0) -> Result (actual rows=1 loops=1) -> Nested Loop (actual rows=1 loops=1) + Buffers: shared hit=2 -> Seq Scan on ab_a1_b1 (actual rows=1 loops=1) + Buffers: shared hit=1 -> Materialize (actual rows=1 loops=1) + Buffers: shared hit=1 -> Append (actual rows=1 loops=1) + Buffers: shared hit=1 -> Seq Scan on ab_a2_b1 (actual rows=1 loops=1) Filter: (b = $0) + Buffers: shared hit=1 -> Seq Scan on ab_a2_b2 (never executed) Filter: (b = $0) -> Seq Scan on ab_a2_b3 (never executed) Filter: (b = $0) -> Nested Loop (actual rows=1 loops=1) + Buffers: shared hit=2 -> Seq Scan on ab_a1_b2 (actual rows=1 loops=1) + Buffers: shared hit=1 -> Materialize (actual rows=1 loops=1) + Buffers: shared hit=1 -> Append (actual rows=1 loops=1) + Buffers: shared hit=1 -> Seq Scan on ab_a2_b1 (actual rows=1 loops=1) Filter: (b = $0) + Buffers: shared hit=1 -> Seq Scan on ab_a2_b2 (never executed) Filter: (b = $0) -> Seq Scan on ab_a2_b3 (never executed) Filter: (b = $0) -> Nested Loop (actual rows=1 loops=1) + Buffers: shared hit=2 -> Seq Scan on ab_a1_b3 (actual rows=1 loops=1) + Buffers: shared hit=1 -> Materialize (actual rows=1 loops=1) + Buffers: shared hit=1 -> Append (actual rows=1 loops=1) + Buffers: shared hit=1 -> Seq Scan on ab_a2_b1 (actual rows=1 loops=1) Filter: (b = $0) + Buffers: shared hit=1 -> Seq Scan on ab_a2_b2 (never executed) Filter: (b = $0) -> Seq Scan on ab_a2_b3 (never executed) Filter: (b = $0) -(36 rows) + Settings: enable_indexonlyscan = 'off' +(53 rows) select tableoid::regclass, * from ab; tableoid | a | b @@ -2643,17 +2791,22 @@ create index tprt6_idx on tprt_6 (col1); insert into tprt values (10), (20), (501), (502), (505), (1001), (4500); set enable_hashjoin = off; set enable_mergejoin = off; -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 > tprt.col1; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------- Nested Loop (actual rows=6 loops=1) + Buffers: shared hit=7 -> Seq Scan on tbl1 (actual rows=2 loops=1) + Buffers: shared hit=1 -> Append (actual rows=3 loops=2) + Buffers: shared hit=6 -> Index Scan using tprt1_idx on tprt_1 (actual rows=2 loops=2) Index Cond: (col1 < tbl1.col1) + Buffers: shared hit=4 -> Index Scan using tprt2_idx on tprt_2 (actual rows=2 loops=1) Index Cond: (col1 < tbl1.col1) + Buffers: shared hit=2 -> Index Scan using tprt3_idx on tprt_3 (never executed) Index Cond: (col1 < tbl1.col1) -> Index Scan using tprt4_idx on tprt_4 (never executed) @@ -2662,19 +2815,24 @@ select * from tbl1 join tprt on tbl1.col1 > tprt.col1; Index Cond: (col1 < tbl1.col1) -> Index Scan using tprt6_idx on tprt_6 (never executed) Index Cond: (col1 < tbl1.col1) -(15 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off' +(21 rows) -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------- Nested Loop (actual rows=2 loops=1) + Buffers: shared hit=5 -> Seq Scan on tbl1 (actual rows=2 loops=1) + Buffers: shared hit=1 -> Append (actual rows=1 loops=2) + Buffers: shared hit=4 -> Index Scan using tprt1_idx on tprt_1 (never executed) Index Cond: (col1 = tbl1.col1) -> Index Scan using tprt2_idx on tprt_2 (actual rows=1 loops=2) Index Cond: (col1 = tbl1.col1) + Buffers: shared hit=4 -> Index Scan using tprt3_idx on tprt_3 (never executed) Index Cond: (col1 = tbl1.col1) -> Index Scan using tprt4_idx on tprt_4 (never executed) @@ -2683,7 +2841,8 @@ select * from tbl1 join tprt on tbl1.col1 = tprt.col1; Index Cond: (col1 = tbl1.col1) -> Index Scan using tprt6_idx on tprt_6 (never executed) Index Cond: (col1 = tbl1.col1) -(15 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off' +(20 rows) select tbl1.col1, tprt.col1 from tbl1 inner join tprt on tbl1.col1 > tprt.col1 @@ -2709,47 +2868,60 @@ order by tbl1.col1, tprt.col1; -- Multiple partitions insert into tbl1 values (1001), (1010), (1011); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 inner join tprt on tbl1.col1 > tprt.col1; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------- Nested Loop (actual rows=23 loops=1) + Buffers: shared hit=23 -> Seq Scan on tbl1 (actual rows=5 loops=1) + Buffers: shared hit=1 -> Append (actual rows=5 loops=5) + Buffers: shared hit=22 -> Index Scan using tprt1_idx on tprt_1 (actual rows=2 loops=5) Index Cond: (col1 < tbl1.col1) + Buffers: shared hit=10 -> Index Scan using tprt2_idx on tprt_2 (actual rows=3 loops=4) Index Cond: (col1 < tbl1.col1) + Buffers: shared hit=8 -> Index Scan using tprt3_idx on tprt_3 (actual rows=1 loops=2) Index Cond: (col1 < tbl1.col1) + Buffers: shared hit=4 -> Index Scan using tprt4_idx on tprt_4 (never executed) Index Cond: (col1 < tbl1.col1) -> Index Scan using tprt5_idx on tprt_5 (never executed) Index Cond: (col1 < tbl1.col1) -> Index Scan using tprt6_idx on tprt_6 (never executed) Index Cond: (col1 < tbl1.col1) -(15 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off' +(22 rows) -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 inner join tprt on tbl1.col1 = tprt.col1; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------- Nested Loop (actual rows=3 loops=1) + Buffers: shared hit=9 -> Seq Scan on tbl1 (actual rows=5 loops=1) + Buffers: shared hit=1 -> Append (actual rows=1 loops=5) + Buffers: shared hit=8 -> Index Scan using tprt1_idx on tprt_1 (never executed) Index Cond: (col1 = tbl1.col1) -> Index Scan using tprt2_idx on tprt_2 (actual rows=1 loops=2) Index Cond: (col1 = tbl1.col1) + Buffers: shared hit=4 -> Index Scan using tprt3_idx on tprt_3 (actual rows=0 loops=3) Index Cond: (col1 = tbl1.col1) + Buffers: shared hit=4 -> Index Scan using tprt4_idx on tprt_4 (never executed) Index Cond: (col1 = tbl1.col1) -> Index Scan using tprt5_idx on tprt_5 (never executed) Index Cond: (col1 = tbl1.col1) -> Index Scan using tprt6_idx on tprt_6 (never executed) Index Cond: (col1 = tbl1.col1) -(15 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off' +(21 rows) select tbl1.col1, tprt.col1 from tbl1 inner join tprt on tbl1.col1 > tprt.col1 @@ -2794,13 +2966,16 @@ order by tbl1.col1, tprt.col1; -- Last partition delete from tbl1; insert into tbl1 values (4400); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 < tprt.col1; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------- Nested Loop (actual rows=1 loops=1) + Buffers: shared hit=3 -> Seq Scan on tbl1 (actual rows=1 loops=1) + Buffers: shared hit=1 -> Append (actual rows=1 loops=1) + Buffers: shared hit=2 -> Index Scan using tprt1_idx on tprt_1 (never executed) Index Cond: (col1 > tbl1.col1) -> Index Scan using tprt2_idx on tprt_2 (never executed) @@ -2813,7 +2988,9 @@ select * from tbl1 join tprt on tbl1.col1 < tprt.col1; Index Cond: (col1 > tbl1.col1) -> Index Scan using tprt6_idx on tprt_6 (actual rows=1 loops=1) Index Cond: (col1 > tbl1.col1) -(15 rows) + Buffers: shared hit=2 + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off' +(20 rows) select tbl1.col1, tprt.col1 from tbl1 inner join tprt on tbl1.col1 < tprt.col1 @@ -2826,12 +3003,14 @@ order by tbl1.col1, tprt.col1; -- No matching partition delete from tbl1; insert into tbl1 values (10000); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; - QUERY PLAN -------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------- Nested Loop (actual rows=0 loops=1) + Buffers: shared hit=1 -> Seq Scan on tbl1 (actual rows=1 loops=1) + Buffers: shared hit=1 -> Append (actual rows=0 loops=1) -> Index Scan using tprt1_idx on tprt_1 (never executed) Index Cond: (col1 = tbl1.col1) @@ -2845,7 +3024,8 @@ select * from tbl1 join tprt on tbl1.col1 = tprt.col1; Index Cond: (col1 = tbl1.col1) -> Index Scan using tprt6_idx on tprt_6 (never executed) Index Cond: (col1 = tbl1.col1) -(15 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off' +(18 rows) select tbl1.col1, tprt.col1 from tbl1 inner join tprt on tbl1.col1 = tprt.col1 @@ -2893,12 +3073,13 @@ execute part_abc_q1 (1, 2, 3); (0 rows) -- Single partition should be scanned. -explain (analyze, costs off, summary off, timing off) execute part_abc_q1 (1, 2, 3); - QUERY PLAN -------------------------------------------------- +explain (exec, costs off, summary off, timing off) execute part_abc_q1 (1, 2, 3); + QUERY PLAN +------------------------------------------------------------------------------------------- Seq Scan on part_abc_p1 (actual rows=0 loops=1) Filter: ((a = $1) AND (b = $2) AND (c = $3)) -(2 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off' +(3 rows) deallocate part_abc_q1; drop table part_abc; @@ -2943,34 +3124,37 @@ execute q1 (1,2); ---+--- (0 rows) -explain (analyze, costs off, summary off, timing off) execute q1 (1,1); - QUERY PLAN ------------------------------------------------------ +explain (exec, costs off, summary off, timing off) execute q1 (1,1); + QUERY PLAN +------------------------------------------------------------------------------------------- Append (actual rows=0 loops=1) Subplans Removed: 1 -> Seq Scan on listp_1_1 (actual rows=0 loops=1) Filter: (b = ANY (ARRAY[$1, $2])) -(4 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off' +(5 rows) -explain (analyze, costs off, summary off, timing off) execute q1 (2,2); - QUERY PLAN ------------------------------------------------------ +explain (exec, costs off, summary off, timing off) execute q1 (2,2); + QUERY PLAN +------------------------------------------------------------------------------------------- Append (actual rows=0 loops=1) Subplans Removed: 1 -> Seq Scan on listp_2_1 (actual rows=0 loops=1) Filter: (b = ANY (ARRAY[$1, $2])) -(4 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off' +(5 rows) -- Try with no matching partitions. One subplan should remain in this case, -- but it shouldn't be executed. -explain (analyze, costs off, summary off, timing off) execute q1 (0,0); - QUERY PLAN ----------------------------------------------- +explain (exec, costs off, summary off, timing off) execute q1 (0,0); + QUERY PLAN +------------------------------------------------------------------------------------------- Append (actual rows=0 loops=1) Subplans Removed: 1 -> Seq Scan on listp_1_1 (never executed) Filter: (b = ANY (ARRAY[$1, $2])) -(4 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off' +(5 rows) deallocate q1; -- Test more complex cases where a not-equal condition further eliminates partitions. @@ -3001,31 +3185,33 @@ execute q1 (1,2,3,4); (0 rows) -- Both partitions allowed by IN clause, but one disallowed by <> clause -explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,0); - QUERY PLAN -------------------------------------------------------------------------- +explain (exec, costs off, summary off, timing off) execute q1 (1,2,2,0); + QUERY PLAN +------------------------------------------------------------------------------------------- Append (actual rows=0 loops=1) Subplans Removed: 1 -> Seq Scan on listp_1_1 (actual rows=0 loops=1) Filter: ((b = ANY (ARRAY[$1, $2])) AND ($3 <> b) AND ($4 <> b)) -(4 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off' +(5 rows) -- Both partitions allowed by IN clause, then both excluded again by <> clauses. -- One subplan will remain in this case, but it should not be executed. -explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,1); - QUERY PLAN -------------------------------------------------------------------------- +explain (exec, costs off, summary off, timing off) execute q1 (1,2,2,1); + QUERY PLAN +------------------------------------------------------------------------------------------- Append (actual rows=0 loops=1) Subplans Removed: 1 -> Seq Scan on listp_1_1 (never executed) Filter: ((b = ANY (ARRAY[$1, $2])) AND ($3 <> b) AND ($4 <> b)) -(4 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off' +(5 rows) -- Ensure Params that evaluate to NULL properly prune away all partitions -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from listp where a = (select null::int); - QUERY PLAN ----------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------- Append (actual rows=0 loops=1) InitPlan 1 (returns $0) -> Result (actual rows=1 loops=1) @@ -3033,7 +3219,8 @@ select * from listp where a = (select null::int); Filter: (a = $0) -> Seq Scan on listp_2_1 (never executed) Filter: (a = $0) -(7 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off' +(8 rows) drop table listp; -- Ensure runtime pruning works with initplans params with boolean types @@ -3042,35 +3229,41 @@ insert into boolvalues values('t'),('f'); create table boolp (a bool) partition by list (a); create table boolp_t partition of boolp for values in('t'); create table boolp_f partition of boolp for values in('f'); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from boolp where a = (select value from boolvalues where value); - QUERY PLAN --------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------- Append (actual rows=0 loops=1) + Buffers: shared hit=1 InitPlan 1 (returns $0) -> Seq Scan on boolvalues (actual rows=1 loops=1) Filter: value Rows Removed by Filter: 1 + Buffers: shared hit=1 -> Seq Scan on boolp_f (never executed) Filter: (a = $0) -> Seq Scan on boolp_t (actual rows=0 loops=1) Filter: (a = $0) -(9 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off' +(12 rows) -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from boolp where a = (select value from boolvalues where not value); - QUERY PLAN --------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------- Append (actual rows=0 loops=1) + Buffers: shared hit=1 InitPlan 1 (returns $0) -> Seq Scan on boolvalues (actual rows=1 loops=1) Filter: (NOT value) Rows Removed by Filter: 1 + Buffers: shared hit=1 -> Seq Scan on boolp_f (actual rows=0 loops=1) Filter: (a = $0) -> Seq Scan on boolp_t (never executed) Filter: (a = $0) -(9 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off' +(12 rows) drop table boolp; -- @@ -3128,19 +3321,23 @@ execute mt_q1(0); 25 (3 rows) -explain (analyze, costs off, summary off, timing off) execute mt_q1(15); - QUERY PLAN -------------------------------------------------------------------------------- +explain (exec, costs off, summary off, timing off) execute mt_q1(15); + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------- Merge Append (actual rows=2 loops=1) Sort Key: ma_test_p2.b + Buffers: shared hit=4 Subplans Removed: 1 -> Index Scan using ma_test_p2_b_idx on ma_test_p2 (actual rows=1 loops=1) Filter: ((a >= $1) AND ((a % 10) = 5)) Rows Removed by Filter: 9 + Buffers: shared hit=2 -> Index Scan using ma_test_p3_b_idx on ma_test_p3 (actual rows=1 loops=1) Filter: ((a >= $1) AND ((a % 10) = 5)) Rows Removed by Filter: 9 -(9 rows) + Buffers: shared hit=2 + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off', enable_seqscan = 'off', enable_sort = 'off' +(13 rows) execute mt_q1(15); a @@ -3149,16 +3346,19 @@ execute mt_q1(15); 25 (2 rows) -explain (analyze, costs off, summary off, timing off) execute mt_q1(25); - QUERY PLAN -------------------------------------------------------------------------------- +explain (exec, costs off, summary off, timing off) execute mt_q1(25); + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------- Merge Append (actual rows=1 loops=1) Sort Key: ma_test_p3.b + Buffers: shared hit=2 Subplans Removed: 2 -> Index Scan using ma_test_p3_b_idx on ma_test_p3 (actual rows=1 loops=1) Filter: ((a >= $1) AND ((a % 10) = 5)) Rows Removed by Filter: 9 -(6 rows) + Buffers: shared hit=2 + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off', enable_seqscan = 'off', enable_sort = 'off' +(9 rows) execute mt_q1(25); a @@ -3167,15 +3367,16 @@ execute mt_q1(25); (1 row) -- Ensure MergeAppend behaves correctly when no subplans match -explain (analyze, costs off, summary off, timing off) execute mt_q1(35); - QUERY PLAN ------------------------------------------------------------------------- +explain (exec, costs off, summary off, timing off) execute mt_q1(35); + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------- Merge Append (actual rows=0 loops=1) Sort Key: ma_test_p1.b Subplans Removed: 2 -> Index Scan using ma_test_p1_b_idx on ma_test_p1 (never executed) Filter: ((a >= $1) AND ((a % 10) = 5)) -(5 rows) + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off', enable_seqscan = 'off', enable_sort = 'off' +(6 rows) execute mt_q1(35); a @@ -3184,24 +3385,31 @@ execute mt_q1(35); deallocate mt_q1; -- ensure initplan params properly prune partitions -explain (analyze, costs off, summary off, timing off) select * from ma_test where a >= (select min(b) from ma_test_p2) order by b; - QUERY PLAN ------------------------------------------------------------------------------------------------------------- +explain (exec, costs off, summary off, timing off) select * from ma_test where a >= (select min(b) from ma_test_p2) order by b; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------- Merge Append (actual rows=20 loops=1) Sort Key: ma_test_p1.b + Buffers: shared hit=6 InitPlan 2 (returns $1) -> Result (actual rows=1 loops=1) + Buffers: shared hit=2 InitPlan 1 (returns $0) -> Limit (actual rows=1 loops=1) + Buffers: shared hit=2 -> Index Scan using ma_test_p2_b_idx on ma_test_p2 ma_test_p2_1 (actual rows=1 loops=1) Index Cond: (b IS NOT NULL) + Buffers: shared hit=2 -> Index Scan using ma_test_p1_b_idx on ma_test_p1 (never executed) Filter: (a >= $1) -> Index Scan using ma_test_p2_b_idx on ma_test_p2 (actual rows=10 loops=1) Filter: (a >= $1) + Buffers: shared hit=2 -> Index Scan using ma_test_p3_b_idx on ma_test_p3 (actual rows=10 loops=1) Filter: (a >= $1) -(14 rows) + Buffers: shared hit=2 + Settings: enable_hashjoin = 'off', enable_indexonlyscan = 'off', enable_mergejoin = 'off', enable_seqscan = 'off', enable_sort = 'off' +(21 rows) reset enable_seqscan; reset enable_sort; @@ -3216,18 +3424,20 @@ create table pp_arrpart (a int[]) partition by list (a); create table pp_arrpart1 partition of pp_arrpart for values in ('{1}'); create table pp_arrpart2 partition of pp_arrpart for values in ('{2, 3}', '{4, 5}'); explain (costs off) select * from pp_arrpart where a = '{1}'; - QUERY PLAN ----------------------------------- + QUERY PLAN +------------------------------------------------------------- Seq Scan on pp_arrpart1 Filter: (a = '{1}'::integer[]) -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(3 rows) explain (costs off) select * from pp_arrpart where a = '{1, 2}'; - QUERY PLAN --------------------------- + QUERY PLAN +------------------------------------------------------------- Result One-Time Filter: false -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(3 rows) explain (costs off) select * from pp_arrpart where a in ('{4, 5}', '{1}'); QUERY PLAN @@ -3237,25 +3447,28 @@ explain (costs off) select * from pp_arrpart where a in ('{4, 5}', '{1}'); Filter: ((a = '{4,5}'::integer[]) OR (a = '{1}'::integer[])) -> Seq Scan on pp_arrpart2 Filter: ((a = '{4,5}'::integer[]) OR (a = '{1}'::integer[])) -(5 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(6 rows) explain (costs off) update pp_arrpart set a = a where a = '{1}'; - QUERY PLAN ----------------------------------------- + QUERY PLAN +------------------------------------------------------------- Update on pp_arrpart Update on pp_arrpart1 -> Seq Scan on pp_arrpart1 Filter: (a = '{1}'::integer[]) -(4 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(5 rows) explain (costs off) delete from pp_arrpart where a = '{1}'; - QUERY PLAN ----------------------------------------- + QUERY PLAN +------------------------------------------------------------- Delete on pp_arrpart Delete on pp_arrpart1 -> Seq Scan on pp_arrpart1 Filter: (a = '{1}'::integer[]) -(4 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(5 rows) drop table pp_arrpart; -- array type hash partition key @@ -3272,18 +3485,20 @@ select tableoid::regclass, * from pph_arrpart order by 1; (3 rows) explain (costs off) select * from pph_arrpart where a = '{1}'; - QUERY PLAN ----------------------------------- + QUERY PLAN +------------------------------------------------------------- Seq Scan on pph_arrpart2 Filter: (a = '{1}'::integer[]) -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(3 rows) explain (costs off) select * from pph_arrpart where a = '{1, 2}'; - QUERY PLAN ------------------------------------- + QUERY PLAN +------------------------------------------------------------- Seq Scan on pph_arrpart1 Filter: (a = '{1,2}'::integer[]) -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(3 rows) explain (costs off) select * from pph_arrpart where a in ('{4, 5}', '{1}'); QUERY PLAN @@ -3293,7 +3508,8 @@ explain (costs off) select * from pph_arrpart where a in ('{4, 5}', '{1}'); Filter: ((a = '{4,5}'::integer[]) OR (a = '{1}'::integer[])) -> Seq Scan on pph_arrpart2 Filter: ((a = '{4,5}'::integer[]) OR (a = '{1}'::integer[])) -(5 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(6 rows) drop table pph_arrpart; -- enum type list partition key @@ -3302,18 +3518,20 @@ create table pp_enumpart (a pp_colors) partition by list (a); create table pp_enumpart_green partition of pp_enumpart for values in ('green'); create table pp_enumpart_blue partition of pp_enumpart for values in ('blue'); explain (costs off) select * from pp_enumpart where a = 'blue'; - QUERY PLAN ------------------------------------ + QUERY PLAN +------------------------------------------------------------- Seq Scan on pp_enumpart_blue Filter: (a = 'blue'::pp_colors) -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(3 rows) explain (costs off) select * from pp_enumpart where a = 'black'; - QUERY PLAN --------------------------- + QUERY PLAN +------------------------------------------------------------- Result One-Time Filter: false -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(3 rows) drop table pp_enumpart; drop type pp_colors; @@ -3323,18 +3541,20 @@ create table pp_recpart (a pp_rectype) partition by list (a); create table pp_recpart_11 partition of pp_recpart for values in ('(1,1)'); create table pp_recpart_23 partition of pp_recpart for values in ('(2,3)'); explain (costs off) select * from pp_recpart where a = '(1,1)'::pp_rectype; - QUERY PLAN -------------------------------------- + QUERY PLAN +------------------------------------------------------------- Seq Scan on pp_recpart_11 Filter: (a = '(1,1)'::pp_rectype) -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(3 rows) explain (costs off) select * from pp_recpart where a = '(1,2)'::pp_rectype; - QUERY PLAN --------------------------- + QUERY PLAN +------------------------------------------------------------- Result One-Time Filter: false -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(3 rows) drop table pp_recpart; drop type pp_rectype; @@ -3343,18 +3563,20 @@ create table pp_intrangepart (a int4range) partition by list (a); create table pp_intrangepart12 partition of pp_intrangepart for values in ('[1,2]'); create table pp_intrangepart2inf partition of pp_intrangepart for values in ('[2,)'); explain (costs off) select * from pp_intrangepart where a = '[1,2]'::int4range; - QUERY PLAN ------------------------------------- + QUERY PLAN +------------------------------------------------------------- Seq Scan on pp_intrangepart12 Filter: (a = '[1,3)'::int4range) -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(3 rows) explain (costs off) select * from pp_intrangepart where a = '(1,2)'::int4range; - QUERY PLAN --------------------------- + QUERY PLAN +------------------------------------------------------------- Result One-Time Filter: false -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(3 rows) drop table pp_intrangepart; -- @@ -3364,45 +3586,49 @@ create table pp_lp (a int, value int) partition by list (a); create table pp_lp1 partition of pp_lp for values in(1); create table pp_lp2 partition of pp_lp for values in(2); explain (costs off) select * from pp_lp where a = 1; - QUERY PLAN --------------------- + QUERY PLAN +------------------------------------------------------------- Seq Scan on pp_lp1 Filter: (a = 1) -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(3 rows) explain (costs off) update pp_lp set value = 10 where a = 1; - QUERY PLAN --------------------------- + QUERY PLAN +------------------------------------------------------------- Update on pp_lp Update on pp_lp1 -> Seq Scan on pp_lp1 Filter: (a = 1) -(4 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(5 rows) explain (costs off) delete from pp_lp where a = 1; - QUERY PLAN --------------------------- + QUERY PLAN +------------------------------------------------------------- Delete on pp_lp Delete on pp_lp1 -> Seq Scan on pp_lp1 Filter: (a = 1) -(4 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(5 rows) set enable_partition_pruning = off; set constraint_exclusion = 'partition'; -- this should not affect the result. explain (costs off) select * from pp_lp where a = 1; - QUERY PLAN --------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------- Append -> Seq Scan on pp_lp1 Filter: (a = 1) -> Seq Scan on pp_lp2 Filter: (a = 1) -(5 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off', enable_partition_pruning = 'off' +(6 rows) explain (costs off) update pp_lp set value = 10 where a = 1; - QUERY PLAN --------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------- Update on pp_lp Update on pp_lp1 Update on pp_lp2 @@ -3410,11 +3636,12 @@ explain (costs off) update pp_lp set value = 10 where a = 1; Filter: (a = 1) -> Seq Scan on pp_lp2 Filter: (a = 1) -(7 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off', enable_partition_pruning = 'off' +(8 rows) explain (costs off) delete from pp_lp where a = 1; - QUERY PLAN --------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------- Delete on pp_lp Delete on pp_lp1 Delete on pp_lp2 @@ -3422,22 +3649,24 @@ explain (costs off) delete from pp_lp where a = 1; Filter: (a = 1) -> Seq Scan on pp_lp2 Filter: (a = 1) -(7 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off', enable_partition_pruning = 'off' +(8 rows) set constraint_exclusion = 'off'; -- this should not affect the result. explain (costs off) select * from pp_lp where a = 1; - QUERY PLAN --------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Append -> Seq Scan on pp_lp1 Filter: (a = 1) -> Seq Scan on pp_lp2 Filter: (a = 1) -(5 rows) + Settings: constraint_exclusion = 'off', enable_hashjoin = 'off', enable_mergejoin = 'off', enable_partition_pruning = 'off' +(6 rows) explain (costs off) update pp_lp set value = 10 where a = 1; - QUERY PLAN --------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Update on pp_lp Update on pp_lp1 Update on pp_lp2 @@ -3445,11 +3674,12 @@ explain (costs off) update pp_lp set value = 10 where a = 1; Filter: (a = 1) -> Seq Scan on pp_lp2 Filter: (a = 1) -(7 rows) + Settings: constraint_exclusion = 'off', enable_hashjoin = 'off', enable_mergejoin = 'off', enable_partition_pruning = 'off' +(8 rows) explain (costs off) delete from pp_lp where a = 1; - QUERY PLAN --------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Delete on pp_lp Delete on pp_lp1 Delete on pp_lp2 @@ -3457,7 +3687,8 @@ explain (costs off) delete from pp_lp where a = 1; Filter: (a = 1) -> Seq Scan on pp_lp2 Filter: (a = 1) -(7 rows) + Settings: constraint_exclusion = 'off', enable_hashjoin = 'off', enable_mergejoin = 'off', enable_partition_pruning = 'off' +(8 rows) drop table pp_lp; -- Ensure enable_partition_prune does not affect non-partitioned tables. @@ -3471,18 +3702,19 @@ NOTICE: merging column "value" with inherited definition set constraint_exclusion = 'partition'; -- inh_lp2 should be removed in the following 3 cases. explain (costs off) select * from inh_lp where a = 1; - QUERY PLAN ---------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------- Append -> Seq Scan on inh_lp Filter: (a = 1) -> Seq Scan on inh_lp1 Filter: (a = 1) -(5 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off', enable_partition_pruning = 'off' +(6 rows) explain (costs off) update inh_lp set value = 10 where a = 1; - QUERY PLAN ---------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------- Update on inh_lp Update on inh_lp Update on inh_lp1 @@ -3490,11 +3722,12 @@ explain (costs off) update inh_lp set value = 10 where a = 1; Filter: (a = 1) -> Seq Scan on inh_lp1 Filter: (a = 1) -(7 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off', enable_partition_pruning = 'off' +(8 rows) explain (costs off) delete from inh_lp where a = 1; - QUERY PLAN ---------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------- Delete on inh_lp Delete on inh_lp Delete on inh_lp1 @@ -3502,17 +3735,19 @@ explain (costs off) delete from inh_lp where a = 1; Filter: (a = 1) -> Seq Scan on inh_lp1 Filter: (a = 1) -(7 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off', enable_partition_pruning = 'off' +(8 rows) -- Ensure we don't exclude normal relations when we only expect to exclude -- inheritance children explain (costs off) update inh_lp1 set value = 10 where a = 2; - QUERY PLAN ---------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------- Update on inh_lp1 -> Seq Scan on inh_lp1 Filter: (a = 2) -(3 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off', enable_partition_pruning = 'off' +(4 rows) drop table inh_lp cascade; NOTICE: drop cascades to 2 other objects @@ -3525,19 +3760,21 @@ create temp table pp_temp_parent (a int) partition by list (a); create temp table pp_temp_part_1 partition of pp_temp_parent for values in (1); create temp table pp_temp_part_def partition of pp_temp_parent default; explain (costs off) select * from pp_temp_parent where true; - QUERY PLAN ------------------------------------- + QUERY PLAN +------------------------------------------------------------- Append -> Seq Scan on pp_temp_part_1 -> Seq Scan on pp_temp_part_def -(3 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(4 rows) explain (costs off) select * from pp_temp_parent where a = 2; - QUERY PLAN ------------------------------- + QUERY PLAN +------------------------------------------------------------- Seq Scan on pp_temp_part_def Filter: (a = 2) -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(3 rows) drop table pp_temp_parent; -- Stress run-time partition pruning a bit more, per bug reports @@ -3562,8 +3799,8 @@ from ( select 1, 1, 1 ) s(a, b, c) where s.a = 1 and s.b = 1 and s.c = (select 1); - QUERY PLAN ----------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Append InitPlan 1 (returns $0) -> Result @@ -3573,7 +3810,8 @@ where s.a = 1 and s.b = 1 and s.c = (select 1); Filter: ((a = 1) AND (b = 1) AND (c = $0)) -> Result One-Time Filter: (1 = $0) -(9 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(10 rows) select * from ( @@ -3601,8 +3839,8 @@ from ( where s.a = $1 and s.b = $2 and s.c = (select 1); set plan_cache_mode to force_generic_plan; explain (costs off) execute q (1, 1); - QUERY PLAN ---------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------- Append InitPlan 1 (returns $0) -> Result @@ -3613,7 +3851,8 @@ explain (costs off) execute q (1, 1); Filter: ((a = $1) AND (b = $2) AND (c = $0)) -> Result One-Time Filter: ((1 = $1) AND (1 = $2) AND (1 = $0)) -(10 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off', plan_cache_mode = 'force_generic_plan' +(11 rows) execute q (1, 1); a | b | c @@ -3629,15 +3868,16 @@ create table listp (a int, b int) partition by list (a); create table listp1 partition of listp for values in(1); create table listp2 partition of listp for values in(2) partition by list(b); create table listp2_10 partition of listp2 for values in (10); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from listp where a = (select 2) and b <> 10; - QUERY PLAN --------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Seq Scan on listp1 (actual rows=0 loops=1) Filter: ((b <> 10) AND (a = $0)) InitPlan 1 (returns $0) -> Result (never executed) -(4 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off' +(5 rows) -- -- check that a partition directly accessed in a query is excluded with @@ -3648,36 +3888,40 @@ set enable_partition_pruning to off; -- setting constraint_exclusion to 'partition' disables exclusion set constraint_exclusion to 'partition'; explain (costs off) select * from listp1 where a = 2; - QUERY PLAN --------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------- Seq Scan on listp1 Filter: (a = 2) -(2 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off', enable_partition_pruning = 'off' +(3 rows) explain (costs off) update listp1 set a = 1 where a = 2; - QUERY PLAN --------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------- Update on listp1 -> Seq Scan on listp1 Filter: (a = 2) -(3 rows) + Settings: enable_hashjoin = 'off', enable_mergejoin = 'off', enable_partition_pruning = 'off' +(4 rows) -- constraint exclusion enabled set constraint_exclusion to 'on'; explain (costs off) select * from listp1 where a = 2; - QUERY PLAN --------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------- Result One-Time Filter: false -(2 rows) + Settings: constraint_exclusion = 'on', enable_hashjoin = 'off', enable_mergejoin = 'off', enable_partition_pruning = 'off' +(3 rows) explain (costs off) update listp1 set a = 1 where a = 2; - QUERY PLAN --------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------- Update on listp1 -> Result One-Time Filter: false -(3 rows) + Settings: constraint_exclusion = 'on', enable_hashjoin = 'off', enable_mergejoin = 'off', enable_partition_pruning = 'off' +(4 rows) reset constraint_exclusion; reset enable_partition_pruning; diff --git a/src/test/regress/expected/plancache.out b/src/test/regress/expected/plancache.out index 7d289b8c5e..0dd5de5078 100644 --- a/src/test/regress/expected/plancache.out +++ b/src/test/regress/expected/plancache.out @@ -296,12 +296,13 @@ explain (costs off) execute test_mode_pp(2); -- force generic plan set plan_cache_mode to force_generic_plan; explain (costs off) execute test_mode_pp(2); - QUERY PLAN ------------------------------ + QUERY PLAN +-------------------------------------------------- Aggregate -> Seq Scan on test_mode Filter: (a = $1) -(3 rows) + Settings: plan_cache_mode = 'force_generic_plan' +(4 rows) -- get to generic plan by 5 executions set plan_cache_mode to auto; @@ -352,6 +353,7 @@ explain (costs off) execute test_mode_pp(2); Aggregate -> Index Only Scan using test_mode_a_idx on test_mode Index Cond: (a = 2) -(3 rows) + Settings: plan_cache_mode = 'force_custom_plan' +(4 rows) drop table test_mode; diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out index f319239b2e..8d654c6289 100644 --- a/src/test/regress/expected/polygon.out +++ b/src/test/regress/expected/polygon.out @@ -82,7 +82,8 @@ SELECT count(*) FROM quad_poly_tbl WHERE p << polygon '((300,300),(400,600),(600 Recheck Cond: (p << '((300,300),(400,600),(600,500),(700,200))'::polygon) -> Bitmap Index Scan on quad_poly_tbl_idx Index Cond: (p << '((300,300),(400,600),(600,500),(700,200))'::polygon) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_poly_tbl WHERE p << polygon '((300,300),(400,600),(600,500),(700,200))'; count @@ -99,7 +100,8 @@ SELECT count(*) FROM quad_poly_tbl WHERE p &< polygon '((300,300),(400,600),(600 Recheck Cond: (p &< '((300,300),(400,600),(600,500),(700,200))'::polygon) -> Bitmap Index Scan on quad_poly_tbl_idx Index Cond: (p &< '((300,300),(400,600),(600,500),(700,200))'::polygon) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_poly_tbl WHERE p &< polygon '((300,300),(400,600),(600,500),(700,200))'; count @@ -116,7 +118,8 @@ SELECT count(*) FROM quad_poly_tbl WHERE p && polygon '((300,300),(400,600),(600 Recheck Cond: (p && '((300,300),(400,600),(600,500),(700,200))'::polygon) -> Bitmap Index Scan on quad_poly_tbl_idx Index Cond: (p && '((300,300),(400,600),(600,500),(700,200))'::polygon) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_poly_tbl WHERE p && polygon '((300,300),(400,600),(600,500),(700,200))'; count @@ -133,7 +136,8 @@ SELECT count(*) FROM quad_poly_tbl WHERE p &> polygon '((300,300),(400,600),(600 Recheck Cond: (p &> '((300,300),(400,600),(600,500),(700,200))'::polygon) -> Bitmap Index Scan on quad_poly_tbl_idx Index Cond: (p &> '((300,300),(400,600),(600,500),(700,200))'::polygon) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_poly_tbl WHERE p &> polygon '((300,300),(400,600),(600,500),(700,200))'; count @@ -150,7 +154,8 @@ SELECT count(*) FROM quad_poly_tbl WHERE p >> polygon '((300,300),(400,600),(600 Recheck Cond: (p >> '((300,300),(400,600),(600,500),(700,200))'::polygon) -> Bitmap Index Scan on quad_poly_tbl_idx Index Cond: (p >> '((300,300),(400,600),(600,500),(700,200))'::polygon) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_poly_tbl WHERE p >> polygon '((300,300),(400,600),(600,500),(700,200))'; count @@ -167,7 +172,8 @@ SELECT count(*) FROM quad_poly_tbl WHERE p <<| polygon '((300,300),(400,600),(60 Recheck Cond: (p <<| '((300,300),(400,600),(600,500),(700,200))'::polygon) -> Bitmap Index Scan on quad_poly_tbl_idx Index Cond: (p <<| '((300,300),(400,600),(600,500),(700,200))'::polygon) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_poly_tbl WHERE p <<| polygon '((300,300),(400,600),(600,500),(700,200))'; count @@ -184,7 +190,8 @@ SELECT count(*) FROM quad_poly_tbl WHERE p &<| polygon '((300,300),(400,600),(60 Recheck Cond: (p &<| '((300,300),(400,600),(600,500),(700,200))'::polygon) -> Bitmap Index Scan on quad_poly_tbl_idx Index Cond: (p &<| '((300,300),(400,600),(600,500),(700,200))'::polygon) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_poly_tbl WHERE p &<| polygon '((300,300),(400,600),(600,500),(700,200))'; count @@ -201,7 +208,8 @@ SELECT count(*) FROM quad_poly_tbl WHERE p |&> polygon '((300,300),(400,600),(60 Recheck Cond: (p |&> '((300,300),(400,600),(600,500),(700,200))'::polygon) -> Bitmap Index Scan on quad_poly_tbl_idx Index Cond: (p |&> '((300,300),(400,600),(600,500),(700,200))'::polygon) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_poly_tbl WHERE p |&> polygon '((300,300),(400,600),(600,500),(700,200))'; count @@ -218,7 +226,8 @@ SELECT count(*) FROM quad_poly_tbl WHERE p |>> polygon '((300,300),(400,600),(60 Recheck Cond: (p |>> '((300,300),(400,600),(600,500),(700,200))'::polygon) -> Bitmap Index Scan on quad_poly_tbl_idx Index Cond: (p |>> '((300,300),(400,600),(600,500),(700,200))'::polygon) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_poly_tbl WHERE p |>> polygon '((300,300),(400,600),(600,500),(700,200))'; count @@ -235,7 +244,8 @@ SELECT count(*) FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600 Recheck Cond: (p <@ '((300,300),(400,600),(600,500),(700,200))'::polygon) -> Bitmap Index Scan on quad_poly_tbl_idx Index Cond: (p <@ '((300,300),(400,600),(600,500),(700,200))'::polygon) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200))'; count @@ -252,7 +262,8 @@ SELECT count(*) FROM quad_poly_tbl WHERE p @> polygon '((340,550),(343,552),(341 Recheck Cond: (p @> '((340,550),(343,552),(341,553))'::polygon) -> Bitmap Index Scan on quad_poly_tbl_idx Index Cond: (p @> '((340,550),(343,552),(341,553))'::polygon) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_poly_tbl WHERE p @> polygon '((340,550),(343,552),(341,553))'; count @@ -269,7 +280,8 @@ SELECT count(*) FROM quad_poly_tbl WHERE p ~= polygon '((200, 300),(210, 310),(2 Recheck Cond: (p ~= '((200,300),(210,310),(230,290))'::polygon) -> Bitmap Index Scan on quad_poly_tbl_idx Index Cond: (p ~= '((200,300),(210,310),(230,290))'::polygon) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM quad_poly_tbl WHERE p ~= polygon '((200, 300),(210, 310),(230, 290))'; count @@ -289,7 +301,8 @@ FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200)) -> Index Scan using quad_poly_tbl_idx on quad_poly_tbl Index Cond: (p <@ '((300,300),(400,600),(600,500),(700,200))'::polygon) Order By: (p <-> '(123,456)'::point) -(4 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(5 rows) CREATE TEMP TABLE quad_poly_tbl_ord_idx2 AS SELECT rank() OVER (ORDER BY p <-> point '123,456') n, p <-> point '123,456' dist, id diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out index accf1e0d9e..cb3f968dc5 100644 --- a/src/test/regress/expected/rangetypes.out +++ b/src/test/regress/expected/rangetypes.out @@ -1099,7 +1099,8 @@ select ir from test_range_spgist where ir -|- int4range(10,20) order by ir; Sort Key: ir -> Index Only Scan using test_range_spgist_idx on test_range_spgist Index Cond: (ir -|- '[10,20)'::int4range) -(4 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(5 rows) select ir from test_range_spgist where ir -|- int4range(10,20) order by ir; ir diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out index aa3b083ee3..6abd169172 100644 --- a/src/test/regress/expected/rowsecurity.out +++ b/src/test/regress/expected/rowsecurity.out @@ -272,7 +272,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle); InitPlan 1 (returns $0) -> Index Scan using uaccount_pkey on uaccount Index Cond: (pguser = CURRENT_USER) -(5 rows) + Settings: search_path = 'regress_rls_schema' +(6 rows) EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle); QUERY PLAN @@ -286,7 +287,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dt -> Hash -> Seq Scan on document Filter: ((dlevel <= $0) AND f_leak(dtitle)) -(9 rows) + Settings: search_path = 'regress_rls_schema' +(10 rows) -- viewpoint from regress_rls_dave SET SESSION AUTHORIZATION regress_rls_dave; @@ -336,7 +338,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle); InitPlan 1 (returns $0) -> Index Scan using uaccount_pkey on uaccount Index Cond: (pguser = CURRENT_USER) -(5 rows) + Settings: search_path = 'regress_rls_schema' +(6 rows) EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle); QUERY PLAN @@ -350,7 +353,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dt -> Hash -> Seq Scan on document Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle)) -(9 rows) + Settings: search_path = 'regress_rls_schema' +(10 rows) -- 44 would technically fail for both p2r and p1r, but we should get an error -- back from p1r for this because it sorts first @@ -427,7 +431,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle); --------------------------------------------------------- Seq Scan on document Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle)) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle); QUERY PLAN @@ -437,7 +442,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dt Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle)) -> Index Scan using category_pkey on category Index Cond: (cid = document.cid) -(5 rows) + Settings: search_path = 'regress_rls_schema' +(6 rows) -- interaction of FK/PK constraints SET SESSION AUTHORIZATION regress_rls_alice; @@ -659,8 +665,8 @@ SELECT * FROM t1; (5 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1; - QUERY PLAN -------------------------------- + QUERY PLAN +---------------------------------------------- Append -> Seq Scan on t1 Filter: ((a % 2) = 0) @@ -668,7 +674,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM t1; Filter: ((a % 2) = 0) -> Seq Scan on t3 Filter: ((a % 2) = 0) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) SELECT * FROM t1 WHERE f_leak(b); NOTICE: f_leak => bbb @@ -695,7 +702,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b); Filter: (((a % 2) = 0) AND f_leak(b)) -> Seq Scan on t3 Filter: (((a % 2) = 0) AND f_leak(b)) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) -- reference to system column SELECT tableoid::regclass, * FROM t1; @@ -709,8 +717,8 @@ SELECT tableoid::regclass, * FROM t1; (5 rows) EXPLAIN (COSTS OFF) SELECT *, t1 FROM t1; - QUERY PLAN -------------------------------- + QUERY PLAN +---------------------------------------------- Append -> Seq Scan on t1 Filter: ((a % 2) = 0) @@ -718,7 +726,8 @@ EXPLAIN (COSTS OFF) SELECT *, t1 FROM t1; Filter: ((a % 2) = 0) -> Seq Scan on t3 Filter: ((a % 2) = 0) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) -- reference to whole-row reference SELECT *, t1 FROM t1; @@ -732,8 +741,8 @@ SELECT *, t1 FROM t1; (5 rows) EXPLAIN (COSTS OFF) SELECT *, t1 FROM t1; - QUERY PLAN -------------------------------- + QUERY PLAN +---------------------------------------------- Append -> Seq Scan on t1 Filter: ((a % 2) = 0) @@ -741,7 +750,8 @@ EXPLAIN (COSTS OFF) SELECT *, t1 FROM t1; Filter: ((a % 2) = 0) -> Seq Scan on t3 Filter: ((a % 2) = 0) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) -- for share/update lock SELECT * FROM t1 FOR SHARE; @@ -755,8 +765,8 @@ SELECT * FROM t1 FOR SHARE; (5 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1 FOR SHARE; - QUERY PLAN -------------------------------------- + QUERY PLAN +---------------------------------------------- LockRows -> Append -> Seq Scan on t1 @@ -765,7 +775,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM t1 FOR SHARE; Filter: ((a % 2) = 0) -> Seq Scan on t3 Filter: ((a % 2) = 0) -(8 rows) + Settings: search_path = 'regress_rls_schema' +(9 rows) SELECT * FROM t1 WHERE f_leak(b) FOR SHARE; NOTICE: f_leak => bbb @@ -793,7 +804,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b) FOR SHARE; Filter: (((a % 2) = 0) AND f_leak(b)) -> Seq Scan on t3 Filter: (((a % 2) = 0) AND f_leak(b)) -(8 rows) + Settings: search_path = 'regress_rls_schema' +(9 rows) -- union all query SELECT a, b, tableoid::regclass FROM t2 UNION ALL SELECT a, b, tableoid::regclass FROM t3; @@ -807,13 +819,14 @@ SELECT a, b, tableoid::regclass FROM t2 UNION ALL SELECT a, b, tableoid::regclas (5 rows) EXPLAIN (COSTS OFF) SELECT a, b, tableoid::regclass FROM t2 UNION ALL SELECT a, b, tableoid::regclass FROM t3; - QUERY PLAN -------------------------------- + QUERY PLAN +---------------------------------------------- Append -> Seq Scan on t2 Filter: ((a % 2) = 1) -> Seq Scan on t3 -(4 rows) + Settings: search_path = 'regress_rls_schema' +(5 rows) -- superuser is allowed to bypass RLS checks RESET SESSION AUTHORIZATION; @@ -846,8 +859,8 @@ NOTICE: f_leak => zzz (11 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b); - QUERY PLAN ---------------------------- + QUERY PLAN +---------------------------------------------- Append -> Seq Scan on t1 Filter: f_leak(b) @@ -855,7 +868,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b); Filter: f_leak(b) -> Seq Scan on t3 Filter: f_leak(b) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) -- non-superuser with bypass privilege can bypass RLS policy when disabled SET SESSION AUTHORIZATION regress_rls_exempt_user; @@ -888,8 +902,8 @@ NOTICE: f_leak => zzz (11 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b); - QUERY PLAN ---------------------------- + QUERY PLAN +---------------------------------------------- Append -> Seq Scan on t1 Filter: f_leak(b) @@ -897,7 +911,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b); Filter: f_leak(b) -> Seq Scan on t3 Filter: f_leak(b) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) -- -- Partitioned Tables @@ -997,7 +1012,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle); Filter: ((dlevel <= $0) AND f_leak(dtitle)) -> Seq Scan on part_document_nonfiction Filter: ((dlevel <= $0) AND f_leak(dtitle)) -(10 rows) + Settings: search_path = 'regress_rls_schema' +(11 rows) -- viewpoint from regress_rls_carol SET SESSION AUTHORIZATION regress_rls_carol; @@ -1039,7 +1055,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle); Filter: ((dlevel <= $0) AND f_leak(dtitle)) -> Seq Scan on part_document_nonfiction Filter: ((dlevel <= $0) AND f_leak(dtitle)) -(10 rows) + Settings: search_path = 'regress_rls_schema' +(11 rows) -- viewpoint from regress_rls_dave SET SESSION AUTHORIZATION regress_rls_dave; @@ -1064,7 +1081,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle); InitPlan 1 (returns $0) -> Index Scan using uaccount_pkey on uaccount Index Cond: (pguser = CURRENT_USER) -(5 rows) + Settings: search_path = 'regress_rls_schema' +(6 rows) -- pp1 ERROR INSERT INTO part_document VALUES (100, 11, 5, 'regress_rls_dave', 'testing pp1'); -- fail @@ -1142,7 +1160,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle); InitPlan 1 (returns $0) -> Index Scan using uaccount_pkey on uaccount Index Cond: (pguser = CURRENT_USER) -(5 rows) + Settings: search_path = 'regress_rls_schema' +(6 rows) -- viewpoint from regress_rls_carol SET SESSION AUTHORIZATION regress_rls_carol; @@ -1186,7 +1205,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle); Filter: ((dlevel <= $0) AND f_leak(dtitle)) -> Seq Scan on part_document_nonfiction Filter: ((dlevel <= $0) AND f_leak(dtitle)) -(10 rows) + Settings: search_path = 'regress_rls_schema' +(11 rows) -- only owner can change policies ALTER POLICY pp1 ON part_document USING (true); --fail @@ -1235,7 +1255,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle); Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle)) -> Seq Scan on part_document_nonfiction Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle)) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) -- database superuser does bypass RLS policy when enabled RESET SESSION AUTHORIZATION; @@ -1348,10 +1369,11 @@ HINT: Use DROP ... CASCADE to drop the dependent objects too. DROP TABLE dependee CASCADE; NOTICE: drop cascades to policy d1 on table dependent EXPLAIN (COSTS OFF) SELECT * FROM dependent; -- After drop, should be unqualified - QUERY PLAN ------------------------ + QUERY PLAN +---------------------------------------------- Seq Scan on dependent -(1 row) + Settings: search_path = 'regress_rls_schema' +(2 rows) ----- RECURSION ---- -- @@ -1444,7 +1466,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM only s1 WHERE f_leak(b); SubPlan 1 -> Seq Scan on s2 Filter: (((x % 2) = 0) AND (y ~~ '%2f%'::text)) -(5 rows) + Settings: search_path = 'regress_rls_schema' +(6 rows) SET SESSION AUTHORIZATION regress_rls_alice; ALTER POLICY p1 ON s1 USING (a in (select x from v2)); -- using VIEW in RLS policy @@ -1466,7 +1489,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM s1 WHERE f_leak(b); SubPlan 1 -> Seq Scan on s2 Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text)) -(5 rows) + Settings: search_path = 'regress_rls_schema' +(6 rows) SELECT (SELECT x FROM s1 LIMIT 1) xx, * FROM s2 WHERE y like '%28%'; xx | x | y @@ -1488,7 +1512,8 @@ EXPLAIN (COSTS OFF) SELECT (SELECT x FROM s1 LIMIT 1) xx, * FROM s2 WHERE y like SubPlan 1 -> Seq Scan on s2 s2_1 Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text)) -(9 rows) + Settings: search_path = 'regress_rls_schema' +(10 rows) SET SESSION AUTHORIZATION regress_rls_alice; ALTER POLICY p2 ON s2 USING (x in (select a from s1 where b like '%d2%')); @@ -1515,7 +1540,8 @@ EXPLAIN (COSTS OFF) EXECUTE p1(2); Filter: ((a <= 2) AND ((a % 2) = 0)) -> Seq Scan on t3 Filter: ((a <= 2) AND ((a % 2) = 0)) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) -- superuser is allowed to bypass RLS checks RESET SESSION AUTHORIZATION; @@ -1548,8 +1574,8 @@ NOTICE: f_leak => zzz (11 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b); - QUERY PLAN ---------------------------- + QUERY PLAN +---------------------------------------------- Append -> Seq Scan on t1 Filter: f_leak(b) @@ -1557,7 +1583,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b); Filter: f_leak(b) -> Seq Scan on t3 Filter: f_leak(b) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) -- plan cache should be invalidated EXECUTE p1(2); @@ -1572,8 +1599,8 @@ EXECUTE p1(2); (6 rows) EXPLAIN (COSTS OFF) EXECUTE p1(2); - QUERY PLAN --------------------------- + QUERY PLAN +---------------------------------------------- Append -> Seq Scan on t1 Filter: (a <= 2) @@ -1581,7 +1608,8 @@ EXPLAIN (COSTS OFF) EXECUTE p1(2); Filter: (a <= 2) -> Seq Scan on t3 Filter: (a <= 2) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) PREPARE p2(int) AS SELECT * FROM t1 WHERE a = $1; EXECUTE p2(2); @@ -1593,8 +1621,8 @@ EXECUTE p2(2); (3 rows) EXPLAIN (COSTS OFF) EXECUTE p2(2); - QUERY PLAN -------------------------- + QUERY PLAN +---------------------------------------------- Append -> Seq Scan on t1 Filter: (a = 2) @@ -1602,7 +1630,8 @@ EXPLAIN (COSTS OFF) EXECUTE p2(2); Filter: (a = 2) -> Seq Scan on t3 Filter: (a = 2) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) -- also, case when privilege switch from superuser SET SESSION AUTHORIZATION regress_rls_bob; @@ -1616,8 +1645,8 @@ EXECUTE p2(2); (3 rows) EXPLAIN (COSTS OFF) EXECUTE p2(2); - QUERY PLAN ---------------------------------------------- + QUERY PLAN +---------------------------------------------- Append -> Seq Scan on t1 Filter: ((a = 2) AND ((a % 2) = 0)) @@ -1625,7 +1654,8 @@ EXPLAIN (COSTS OFF) EXECUTE p2(2); Filter: ((a = 2) AND ((a % 2) = 0)) -> Seq Scan on t3 Filter: ((a = 2) AND ((a % 2) = 0)) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) -- -- UPDATE / DELETE and Row-level security @@ -1644,7 +1674,8 @@ EXPLAIN (COSTS OFF) UPDATE t1 SET b = b || b WHERE f_leak(b); Filter: (((a % 2) = 0) AND f_leak(b)) -> Seq Scan on t3 Filter: (((a % 2) = 0) AND f_leak(b)) -(10 rows) + Settings: search_path = 'regress_rls_schema' +(11 rows) UPDATE t1 SET b = b || b WHERE f_leak(b); NOTICE: f_leak => bbb @@ -1658,7 +1689,8 @@ EXPLAIN (COSTS OFF) UPDATE only t1 SET b = b || '_updt' WHERE f_leak(b); Update on t1 -> Seq Scan on t1 Filter: (((a % 2) = 0) AND f_leak(b)) -(3 rows) + Settings: search_path = 'regress_rls_schema' +(4 rows) UPDATE only t1 SET b = b || '_updt' WHERE f_leak(b); NOTICE: f_leak => bbbbbb @@ -1714,7 +1746,8 @@ WHERE t2.a = 3 and t3.a = 2 AND f_leak(t2.b) AND f_leak(t3.b); Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) -> Seq Scan on t3 Filter: ((a = 2) AND f_leak(b)) -(6 rows) + Settings: search_path = 'regress_rls_schema' +(7 rows) UPDATE t2 SET b=t2.b FROM t3 WHERE t2.a = 3 and t3.a = 2 AND f_leak(t2.b) AND f_leak(t3.b); @@ -1743,7 +1776,8 @@ WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b); Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b)) -> Seq Scan on t2 Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) -(19 rows) + Settings: search_path = 'regress_rls_schema' +(20 rows) UPDATE t1 SET b=t1.b FROM t2 WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b); @@ -1762,7 +1796,8 @@ WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b); Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b)) -> Seq Scan on t3 Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b)) -(11 rows) + Settings: search_path = 'regress_rls_schema' +(12 rows) UPDATE t2 SET b=t2.b FROM t1 WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b); @@ -1780,7 +1815,8 @@ AND f_leak(t2_1.b) AND f_leak(t2_2.b) RETURNING *, t2_1, t2_2; Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) -> Seq Scan on t2 t2_2 Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) UPDATE t2 t2_1 SET b = t2_2.b FROM t2 t2_2 WHERE t2_1.a = 3 AND t2_2.a = t2_1.a AND t2_2.b = t2_1.b @@ -1834,7 +1870,8 @@ AND f_leak(t1_1.b) AND f_leak(t1_2.b) RETURNING *, t1_1, t1_2; Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) -> Seq Scan on t3 t1_2_2 Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) -(37 rows) + Settings: search_path = 'regress_rls_schema' +(38 rows) UPDATE t1 t1_1 SET b = t1_2.b FROM t1 t1_2 WHERE t1_1.a = 4 AND t1_2.a = t1_1.a AND t1_2.b = t1_1.b @@ -1877,7 +1914,8 @@ EXPLAIN (COSTS OFF) DELETE FROM only t1 WHERE f_leak(b); Delete on t1 -> Seq Scan on t1 Filter: (((a % 2) = 0) AND f_leak(b)) -(3 rows) + Settings: search_path = 'regress_rls_schema' +(4 rows) EXPLAIN (COSTS OFF) DELETE FROM t1 WHERE f_leak(b); QUERY PLAN @@ -1892,7 +1930,8 @@ EXPLAIN (COSTS OFF) DELETE FROM t1 WHERE f_leak(b); Filter: (((a % 2) = 0) AND f_leak(b)) -> Seq Scan on t3 Filter: (((a % 2) = 0) AND f_leak(b)) -(10 rows) + Settings: search_path = 'regress_rls_schema' +(11 rows) DELETE FROM only t1 WHERE f_leak(b) RETURNING tableoid::regclass, *, t1; NOTICE: f_leak => bbbbbb_updt @@ -1928,13 +1967,14 @@ CREATE VIEW bv1 WITH (security_barrier) AS SELECT * FROM b1 WHERE a > 0 WITH CHE GRANT ALL ON bv1 TO regress_rls_carol; SET SESSION AUTHORIZATION regress_rls_carol; EXPLAIN (COSTS OFF) SELECT * FROM bv1 WHERE f_leak(b); - QUERY PLAN ---------------------------------------------- + QUERY PLAN +---------------------------------------------- Subquery Scan on bv1 Filter: f_leak(bv1.b) -> Seq Scan on b1 Filter: ((a > 0) AND ((a % 2) = 0)) -(4 rows) + Settings: search_path = 'regress_rls_schema' +(5 rows) SELECT * FROM bv1 WHERE f_leak(b); NOTICE: f_leak => c81e728d9d4c2f636f067f89cc14862c @@ -1962,7 +2002,8 @@ EXPLAIN (COSTS OFF) UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b); Update on b1 -> Seq Scan on b1 Filter: ((a > 0) AND (a = 4) AND ((a % 2) = 0) AND f_leak(b)) -(3 rows) + Settings: search_path = 'regress_rls_schema' +(4 rows) UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b); NOTICE: f_leak => a87ff679a2f3e71d9181a67b7542122c @@ -1972,7 +2013,8 @@ EXPLAIN (COSTS OFF) DELETE FROM bv1 WHERE a = 6 AND f_leak(b); Delete on b1 -> Seq Scan on b1 Filter: ((a > 0) AND (a = 6) AND ((a % 2) = 0) AND f_leak(b)) -(3 rows) + Settings: search_path = 'regress_rls_schema' +(4 rows) DELETE FROM bv1 WHERE a = 6 AND f_leak(b); NOTICE: f_leak => 1679091c5a880faf6fb5e6087eb1b2dc @@ -2163,19 +2205,21 @@ NOTICE: f_leak => dad (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b); - QUERY PLAN ------------------------------------------ + QUERY PLAN +---------------------------------------------- Seq Scan on z1 Filter: (((a % 2) = 0) AND f_leak(b)) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) PREPARE plancache_test AS SELECT * FROM z1 WHERE f_leak(b); EXPLAIN (COSTS OFF) EXECUTE plancache_test; - QUERY PLAN ------------------------------------------ + QUERY PLAN +---------------------------------------------- Seq Scan on z1 Filter: (((a % 2) = 0) AND f_leak(b)) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) PREPARE plancache_test2 AS WITH q AS MATERIALIZED (SELECT * FROM z1 WHERE f_leak(b)) SELECT * FROM q,z2; EXPLAIN (COSTS OFF) EXECUTE plancache_test2; @@ -2188,7 +2232,8 @@ EXPLAIN (COSTS OFF) EXECUTE plancache_test2; -> CTE Scan on q -> Materialize -> Seq Scan on z2 -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) PREPARE plancache_test3 AS WITH q AS MATERIALIZED (SELECT * FROM z2) SELECT * FROM q,z1 WHERE f_leak(z1.b); EXPLAIN (COSTS OFF) EXECUTE plancache_test3; @@ -2201,7 +2246,8 @@ EXPLAIN (COSTS OFF) EXECUTE plancache_test3; -> Materialize -> Seq Scan on z1 Filter: (((a % 2) = 0) AND f_leak(b)) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) SET ROLE regress_rls_group1; SELECT * FROM z1 WHERE f_leak(b); @@ -2214,18 +2260,20 @@ NOTICE: f_leak => dad (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b); - QUERY PLAN ------------------------------------------ + QUERY PLAN +---------------------------------------------- Seq Scan on z1 Filter: (((a % 2) = 0) AND f_leak(b)) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test; - QUERY PLAN ------------------------------------------ + QUERY PLAN +---------------------------------------------- Seq Scan on z1 Filter: (((a % 2) = 0) AND f_leak(b)) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test2; QUERY PLAN @@ -2237,7 +2285,8 @@ EXPLAIN (COSTS OFF) EXECUTE plancache_test2; -> CTE Scan on q -> Materialize -> Seq Scan on z2 -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test3; QUERY PLAN @@ -2249,7 +2298,8 @@ EXPLAIN (COSTS OFF) EXECUTE plancache_test3; -> Materialize -> Seq Scan on z1 Filter: (((a % 2) = 0) AND f_leak(b)) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) SET SESSION AUTHORIZATION regress_rls_carol; SELECT * FROM z1 WHERE f_leak(b); @@ -2262,18 +2312,20 @@ NOTICE: f_leak => ccc (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b); - QUERY PLAN ------------------------------------------ + QUERY PLAN +---------------------------------------------- Seq Scan on z1 Filter: (((a % 2) = 1) AND f_leak(b)) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test; - QUERY PLAN ------------------------------------------ + QUERY PLAN +---------------------------------------------- Seq Scan on z1 Filter: (((a % 2) = 1) AND f_leak(b)) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test2; QUERY PLAN @@ -2285,7 +2337,8 @@ EXPLAIN (COSTS OFF) EXECUTE plancache_test2; -> CTE Scan on q -> Materialize -> Seq Scan on z2 -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test3; QUERY PLAN @@ -2297,7 +2350,8 @@ EXPLAIN (COSTS OFF) EXECUTE plancache_test3; -> Materialize -> Seq Scan on z1 Filter: (((a % 2) = 1) AND f_leak(b)) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) SET ROLE regress_rls_group2; SELECT * FROM z1 WHERE f_leak(b); @@ -2310,18 +2364,20 @@ NOTICE: f_leak => ccc (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b); - QUERY PLAN ------------------------------------------ + QUERY PLAN +---------------------------------------------- Seq Scan on z1 Filter: (((a % 2) = 1) AND f_leak(b)) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test; - QUERY PLAN ------------------------------------------ + QUERY PLAN +---------------------------------------------- Seq Scan on z1 Filter: (((a % 2) = 1) AND f_leak(b)) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test2; QUERY PLAN @@ -2333,7 +2389,8 @@ EXPLAIN (COSTS OFF) EXECUTE plancache_test2; -> CTE Scan on q -> Materialize -> Seq Scan on z2 -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test3; QUERY PLAN @@ -2345,7 +2402,8 @@ EXPLAIN (COSTS OFF) EXECUTE plancache_test3; -> Materialize -> Seq Scan on z1 Filter: (((a % 2) = 1) AND f_leak(b)) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) -- -- Views should follow policy for view owner. @@ -2370,11 +2428,12 @@ NOTICE: f_leak => dad (4 rows) EXPLAIN (COSTS OFF) SELECT * FROM rls_view; - QUERY PLAN ---------------------- + QUERY PLAN +---------------------------------------------- Seq Scan on z1 Filter: f_leak(b) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) -- Query as view/table owner. Should return all records. SET SESSION AUTHORIZATION regress_rls_alice; @@ -2392,11 +2451,12 @@ NOTICE: f_leak => dad (4 rows) EXPLAIN (COSTS OFF) SELECT * FROM rls_view; - QUERY PLAN ---------------------- + QUERY PLAN +---------------------------------------------- Seq Scan on z1 Filter: f_leak(b) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) DROP VIEW rls_view; -- View and Table owners are different. @@ -2416,11 +2476,12 @@ NOTICE: f_leak => dad (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM rls_view; - QUERY PLAN ------------------------------------------ + QUERY PLAN +---------------------------------------------- Seq Scan on z1 Filter: (((a % 2) = 0) AND f_leak(b)) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) -- Query as role that is not owner of table but is owner of view. -- Should return records based on view owner policies. @@ -2435,11 +2496,12 @@ NOTICE: f_leak => dad (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM rls_view; - QUERY PLAN ------------------------------------------ + QUERY PLAN +---------------------------------------------- Seq Scan on z1 Filter: (((a % 2) = 0) AND f_leak(b)) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) -- Query as role that is not the owner of the table or view without permissions. SET SESSION AUTHORIZATION regress_rls_carol; @@ -2460,11 +2522,12 @@ NOTICE: f_leak => dad (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM rls_view; - QUERY PLAN ------------------------------------------ + QUERY PLAN +---------------------------------------------- Seq Scan on z1 Filter: (((a % 2) = 0) AND f_leak(b)) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) SET SESSION AUTHORIZATION regress_rls_bob; DROP VIEW rls_view; @@ -2598,11 +2661,12 @@ SET SESSION AUTHORIZATION regress_rls_alice; CREATE VIEW rls_sbv WITH (security_barrier) AS SELECT * FROM y1 WHERE f_leak(b); EXPLAIN (COSTS OFF) SELECT * FROM rls_sbv WHERE (a = 1); - QUERY PLAN ------------------------------------ + QUERY PLAN +---------------------------------------------- Seq Scan on y1 Filter: (f_leak(b) AND (a = 1)) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) DROP VIEW rls_sbv; -- Create view as role that does not own table. RLS should be applied. @@ -2614,7 +2678,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM rls_sbv WHERE (a = 1); ------------------------------------------------------------------ Seq Scan on y1 Filter: ((a = 1) AND ((a > 2) OR ((a % 2) = 0)) AND f_leak(b)) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) DROP VIEW rls_sbv; -- @@ -2663,7 +2728,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM y2 WHERE f_leak(b); ----------------------------------------------------------------------------- Seq Scan on y2 Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b)) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) -- -- Qual push-down of leaky functions, when not referring to table @@ -2713,7 +2779,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM y2 WHERE f_leak('abc'); --------------------------------------------------------------------------------------- Seq Scan on y2 Filter: (f_leak('abc'::text) AND (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0))) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) CREATE TABLE test_qual_pushdown ( abc text @@ -2736,7 +2803,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM y2 JOIN test_qual_pushdown ON (b = abc) WHERE -> Hash -> Seq Scan on y2 Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) -(7 rows) + Settings: search_path = 'regress_rls_schema' +(8 rows) SELECT * FROM y2 JOIN test_qual_pushdown ON (b = abc) WHERE f_leak(b); NOTICE: f_leak => cfcd208495d565ef66e7dff9f98764da @@ -2766,7 +2834,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM y2 JOIN test_qual_pushdown ON (b = abc) WHERE -> Hash -> Seq Scan on y2 Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b)) -(6 rows) + Settings: search_path = 'regress_rls_schema' +(7 rows) DROP TABLE test_qual_pushdown; -- @@ -2787,31 +2856,34 @@ SET ROLE regress_rls_bob; PREPARE role_inval AS SELECT * FROM t1; -- Check plan EXPLAIN (COSTS OFF) EXECUTE role_inval; - QUERY PLAN -------------------------- + QUERY PLAN +---------------------------------------------- Seq Scan on t1 Filter: ((a % 2) = 0) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) -- Change to regress_rls_carol SET ROLE regress_rls_carol; -- Check plan- should be different EXPLAIN (COSTS OFF) EXECUTE role_inval; - QUERY PLAN -------------------------- + QUERY PLAN +---------------------------------------------- Seq Scan on t1 Filter: ((a % 4) = 0) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) -- Change back to regress_rls_bob SET ROLE regress_rls_bob; -- Check plan- should be back to original EXPLAIN (COSTS OFF) EXECUTE role_inval; - QUERY PLAN -------------------------- + QUERY PLAN +---------------------------------------------- Seq Scan on t1 Filter: ((a % 2) = 0) -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) -- -- CTE and RLS @@ -2859,7 +2931,8 @@ WITH cte1 AS MATERIALIZED (SELECT * FROM t1 WHERE f_leak(b)) SELECT * FROM cte1; CTE cte1 -> Seq Scan on t1 Filter: (((a % 2) = 0) AND f_leak(b)) -(4 rows) + Settings: search_path = 'regress_rls_schema' +(5 rows) WITH cte1 AS (UPDATE t1 SET a = a + 1 RETURNING *) SELECT * FROM cte1; --fail ERROR: new row violates row-level security policy for table "t1" @@ -2919,12 +2992,13 @@ SET SESSION AUTHORIZATION regress_rls_bob; CREATE TABLE t2 (a integer, b text); INSERT INTO t2 (SELECT * FROM t1); EXPLAIN (COSTS OFF) INSERT INTO t2 (SELECT * FROM t1); - QUERY PLAN -------------------------------- + QUERY PLAN +---------------------------------------------- Insert on t2 -> Seq Scan on t1 Filter: ((a % 2) = 0) -(3 rows) + Settings: search_path = 'regress_rls_schema' +(4 rows) SELECT * FROM t2; a | b @@ -2944,10 +3018,11 @@ SELECT * FROM t2; (12 rows) EXPLAIN (COSTS OFF) SELECT * FROM t2; - QUERY PLAN ----------------- + QUERY PLAN +---------------------------------------------- Seq Scan on t2 -(1 row) + Settings: search_path = 'regress_rls_schema' +(2 rows) CREATE TABLE t3 AS SELECT * FROM t1; SELECT * FROM t3; @@ -3079,10 +3154,11 @@ SELECT * FROM t1; (22 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1; - QUERY PLAN ----------------- + QUERY PLAN +---------------------------------------------- Seq Scan on t1 -(1 row) + Settings: search_path = 'regress_rls_schema' +(2 rows) -- Check that default deny does not apply to table owner. SET SESSION AUTHORIZATION regress_rls_alice; @@ -3114,10 +3190,11 @@ SELECT * FROM t1; (22 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1; - QUERY PLAN ----------------- + QUERY PLAN +---------------------------------------------- Seq Scan on t1 -(1 row) + Settings: search_path = 'regress_rls_schema' +(2 rows) -- Check that default deny applies to non-owner/non-superuser when RLS on. SET SESSION AUTHORIZATION regress_rls_bob; @@ -3128,11 +3205,12 @@ SELECT * FROM t1; (0 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1; - QUERY PLAN --------------------------- + QUERY PLAN +---------------------------------------------- Result One-Time Filter: false -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) SET SESSION AUTHORIZATION regress_rls_bob; SELECT * FROM t1; @@ -3141,11 +3219,12 @@ SELECT * FROM t1; (0 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1; - QUERY PLAN --------------------------- + QUERY PLAN +---------------------------------------------- Result One-Time Filter: false -(2 rows) + Settings: search_path = 'regress_rls_schema' +(3 rows) -- -- COPY TO/FROM @@ -3376,7 +3455,8 @@ EXPLAIN (COSTS OFF) UPDATE current_check SET payload = payload WHERE CURRENT OF -> Tid Scan on current_check TID Cond: CURRENT OF current_check_cursor Filter: ((currentid = 4) AND ((currentid % 2) = 0)) -(4 rows) + Settings: search_path = 'regress_rls_schema' +(5 rows) -- Similarly can only delete row 4 FETCH ABSOLUTE 1 FROM current_check_cursor; diff --git a/src/test/regress/expected/rowtypes.out b/src/test/regress/expected/rowtypes.out index ffccaa5c9d..3c39450839 100644 --- a/src/test/regress/expected/rowtypes.out +++ b/src/test/regress/expected/rowtypes.out @@ -406,7 +406,8 @@ select a,b from test_table where (a,b) > ('a','a') order by a,b; -------------------------------------------------------- Index Only Scan using test_table_a_b_idx on test_table Index Cond: (ROW(a, b) > ROW('a'::text, 'a'::text)) -(2 rows) + Settings: enable_sort = 'off' +(3 rows) select a,b from test_table where (a,b) > ('a','a') order by a,b; a | b diff --git a/src/test/regress/expected/select.out b/src/test/regress/expected/select.out index c441049f41..da4c1b8202 100644 --- a/src/test/regress/expected/select.out +++ b/src/test/regress/expected/select.out @@ -744,7 +744,8 @@ select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; Index Scan using onek2_u2_prtl on onek2 Index Cond: (unique2 = 11) Filter: (stringu1 = 'ATAAAA'::name) -(3 rows) + Settings: enable_sort = 'off' +(4 rows) select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 @@ -753,14 +754,16 @@ select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; (1 row) -- actually run the query with an analyze to use the partial index -explain (costs off, analyze on, timing off, summary off) +explain (costs off, exec on, timing off, summary off) select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; QUERY PLAN ----------------------------------------------------------------- Index Scan using onek2_u2_prtl on onek2 (actual rows=1 loops=1) Index Cond: (unique2 = 11) Filter: (stringu1 = 'ATAAAA'::name) -(3 rows) + Buffers: shared hit=2 + Settings: enable_sort = 'off' +(5 rows) explain (costs off) select unique2 from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; @@ -769,7 +772,8 @@ select unique2 from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; Index Scan using onek2_u2_prtl on onek2 Index Cond: (unique2 = 11) Filter: (stringu1 = 'ATAAAA'::name) -(3 rows) + Settings: enable_sort = 'off' +(4 rows) select unique2 from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; unique2 @@ -784,7 +788,8 @@ select * from onek2 where unique2 = 11 and stringu1 < 'B'; ----------------------------------------- Index Scan using onek2_u2_prtl on onek2 Index Cond: (unique2 = 11) -(2 rows) + Settings: enable_sort = 'off' +(3 rows) select * from onek2 where unique2 = 11 and stringu1 < 'B'; unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 @@ -798,7 +803,8 @@ select unique2 from onek2 where unique2 = 11 and stringu1 < 'B'; ---------------------------------------------- Index Only Scan using onek2_u2_prtl on onek2 Index Cond: (unique2 = 11) -(2 rows) + Settings: enable_sort = 'off' +(3 rows) select unique2 from onek2 where unique2 = 11 and stringu1 < 'B'; unique2 @@ -815,7 +821,8 @@ select unique2 from onek2 where unique2 = 11 and stringu1 < 'B' for update; -> Index Scan using onek2_u2_prtl on onek2 Index Cond: (unique2 = 11) Filter: (stringu1 < 'B'::name) -(4 rows) + Settings: enable_sort = 'off' +(5 rows) select unique2 from onek2 where unique2 = 11 and stringu1 < 'B' for update; unique2 @@ -830,7 +837,8 @@ select unique2 from onek2 where unique2 = 11 and stringu1 < 'C'; ------------------------------------------------------- Seq Scan on onek2 Filter: ((stringu1 < 'C'::name) AND (unique2 = 11)) -(2 rows) + Settings: enable_sort = 'off' +(3 rows) select unique2 from onek2 where unique2 = 11 and stringu1 < 'C'; unique2 @@ -848,7 +856,8 @@ select unique2 from onek2 where unique2 = 11 and stringu1 < 'B'; Recheck Cond: ((unique2 = 11) AND (stringu1 < 'B'::name)) -> Bitmap Index Scan on onek2_u2_prtl Index Cond: (unique2 = 11) -(4 rows) + Settings: enable_indexscan = 'off', enable_sort = 'off' +(5 rows) select unique2 from onek2 where unique2 = 11 and stringu1 < 'B'; unique2 @@ -871,30 +880,32 @@ select unique1, unique2 from onek2 Index Cond: (unique2 = 11) -> Bitmap Index Scan on onek2_u1_prtl Index Cond: (unique1 = 0) + Settings: enable_sort = 'off' +(9 rows) + +select unique1, unique2 from onek2 + where (unique2 = 11 or unique1 = 0) and stringu1 < 'B'; + unique1 | unique2 +---------+--------- + 494 | 11 + 0 | 998 +(2 rows) + +explain (costs off) +select unique1, unique2 from onek2 + where (unique2 = 11 and stringu1 < 'B') or unique1 = 0; + QUERY PLAN +-------------------------------------------------------------------------------- + Bitmap Heap Scan on onek2 + Recheck Cond: (((unique2 = 11) AND (stringu1 < 'B'::name)) OR (unique1 = 0)) + -> BitmapOr + -> Bitmap Index Scan on onek2_u2_prtl + Index Cond: (unique2 = 11) + -> Bitmap Index Scan on onek2_u1_prtl + Index Cond: (unique1 = 0) + Settings: enable_sort = 'off' (8 rows) -select unique1, unique2 from onek2 - where (unique2 = 11 or unique1 = 0) and stringu1 < 'B'; - unique1 | unique2 ----------+--------- - 494 | 11 - 0 | 998 -(2 rows) - -explain (costs off) -select unique1, unique2 from onek2 - where (unique2 = 11 and stringu1 < 'B') or unique1 = 0; - QUERY PLAN --------------------------------------------------------------------------------- - Bitmap Heap Scan on onek2 - Recheck Cond: (((unique2 = 11) AND (stringu1 < 'B'::name)) OR (unique1 = 0)) - -> BitmapOr - -> Bitmap Index Scan on onek2_u2_prtl - Index Cond: (unique2 = 11) - -> Bitmap Index Scan on onek2_u1_prtl - Index Cond: (unique1 = 0) -(7 rows) - select unique1, unique2 from onek2 where (unique2 = 11 and stringu1 < 'B') or unique1 = 0; unique1 | unique2 @@ -957,10 +968,11 @@ create table list_parted_tbl (a int,b int) partition by list (a); create table list_parted_tbl1 partition of list_parted_tbl for values in (1) partition by list(b); explain (costs off) select * from list_parted_tbl; - QUERY PLAN --------------------------- + QUERY PLAN +------------------------------- Result One-Time Filter: false -(2 rows) + Settings: enable_sort = 'off' +(3 rows) drop table list_parted_tbl; diff --git a/src/test/regress/expected/select_into.out b/src/test/regress/expected/select_into.out index f373fae679..3ddb485965 100644 --- a/src/test/regress/expected/select_into.out +++ b/src/test/regress/expected/select_into.out @@ -112,15 +112,21 @@ SELECT * FROM created_table; 4567890123456789 | -4567890123456789 (5 rows) --- Try EXPLAIN ANALYZE SELECT INTO and EXPLAIN ANALYZE CREATE TABLE AS +-- Try EXPLAIN EXEC SELECT INTO and EXPLAIN EXEC CREATE TABLE AS -- WITH NO DATA, but hide the outputs since they won't be stable. DO $$ BEGIN - EXECUTE 'EXPLAIN ANALYZE SELECT * INTO TABLE easi FROM int8_tbl'; - EXECUTE 'EXPLAIN ANALYZE CREATE TABLE easi2 AS SELECT * FROM int8_tbl WITH NO DATA'; + EXECUTE 'EXPLAIN EXEC SELECT * INTO TABLE easi FROM int8_tbl'; + EXECUTE 'EXPLAIN EXEC CREATE TABLE easi2 AS SELECT * FROM int8_tbl WITH NO DATA'; END$$; +ERROR: syntax error at or near "EXEC" +LINE 1: EXPLAIN EXEC SELECT * INTO TABLE easi FROM int8_tbl + ^ +QUERY: EXPLAIN EXEC SELECT * INTO TABLE easi FROM int8_tbl +CONTEXT: PL/pgSQL function inline_code_block line 3 at EXECUTE DROP TABLE created_table; DROP TABLE easi, easi2; +ERROR: table "easi" does not exist -- -- Disallowed uses of SELECT ... INTO. All should fail -- diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out index 0eca76cb41..5787360a23 100644 --- a/src/test/regress/expected/select_parallel.out +++ b/src/test/regress/expected/select_parallel.out @@ -14,8 +14,8 @@ set max_parallel_workers_per_gather=4; -- Parallel Append with partial-subplans explain (costs off) select round(avg(aa)), sum(aa) from a_star; - QUERY PLAN ------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 3 @@ -27,7 +27,8 @@ explain (costs off) -> Parallel Seq Scan on b_star -> Parallel Seq Scan on c_star -> Parallel Seq Scan on a_star -(11 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(12 rows) select round(avg(aa)), sum(aa) from a_star a1; round | sum @@ -40,8 +41,8 @@ alter table c_star set (parallel_workers = 0); alter table d_star set (parallel_workers = 0); explain (costs off) select round(avg(aa)), sum(aa) from a_star; - QUERY PLAN ------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 3 @@ -53,7 +54,8 @@ explain (costs off) -> Parallel Seq Scan on e_star -> Parallel Seq Scan on b_star -> Parallel Seq Scan on a_star -(11 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(12 rows) select round(avg(aa)), sum(aa) from a_star a2; round | sum @@ -68,8 +70,8 @@ alter table e_star set (parallel_workers = 0); alter table f_star set (parallel_workers = 0); explain (costs off) select round(avg(aa)), sum(aa) from a_star; - QUERY PLAN --------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 3 @@ -81,7 +83,8 @@ explain (costs off) -> Seq Scan on b_star -> Seq Scan on c_star -> Seq Scan on a_star -(11 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(12 rows) select round(avg(aa)), sum(aa) from a_star a3; round | sum @@ -99,8 +102,8 @@ alter table f_star reset (parallel_workers); set enable_parallel_append to off; explain (costs off) select round(avg(aa)), sum(aa) from a_star; - QUERY PLAN ------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 1 @@ -112,7 +115,8 @@ explain (costs off) -> Parallel Seq Scan on d_star -> Parallel Seq Scan on e_star -> Parallel Seq Scan on f_star -(11 rows) + Settings: enable_parallel_append = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(12 rows) select round(avg(aa)), sum(aa) from a_star a4; round | sum @@ -139,8 +143,8 @@ create table part_pa_test_p2 partition of part_pa_test for values from (0) to (m explain (costs off) select (select max((select pa1.b from part_pa_test pa1 where pa1.a = pa2.a))) from part_pa_test pa2; - QUERY PLAN --------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Aggregate -> Gather Workers Planned: 3 @@ -155,22 +159,24 @@ explain (costs off) Filter: (a = pa2.a) -> Seq Scan on part_pa_test_p2 pa1_1 Filter: (a = pa2.a) -(14 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(15 rows) drop table part_pa_test; -- test with leader participation disabled set parallel_leader_participation = off; explain (costs off) select count(*) from tenk1 where stringu1 = 'GRAAAA'; - QUERY PLAN ---------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 4 -> Partial Aggregate -> Parallel Seq Scan on tenk1 Filter: (stringu1 = 'GRAAAA'::name) -(6 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_leader_participation = 'off', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(7 rows) select count(*) from tenk1 where stringu1 = 'GRAAAA'; count @@ -183,15 +189,16 @@ select count(*) from tenk1 where stringu1 = 'GRAAAA'; set max_parallel_workers = 0; explain (costs off) select count(*) from tenk1 where stringu1 = 'GRAAAA'; - QUERY PLAN ---------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 4 -> Partial Aggregate -> Parallel Seq Scan on tenk1 Filter: (stringu1 = 'GRAAAA'::name) -(6 rows) + Settings: max_parallel_workers = '0', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_leader_participation = 'off', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(7 rows) select count(*) from tenk1 where stringu1 = 'GRAAAA'; count @@ -206,8 +213,8 @@ alter table tenk1 set (parallel_workers = 4); explain (verbose, costs off) select sp_parallel_restricted(unique1) from tenk1 where stringu1 = 'GRAAAA' order by 1; - QUERY PLAN ---------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Sort Output: (sp_parallel_restricted(unique1)) Sort Key: (sp_parallel_restricted(tenk1.unique1)) @@ -217,13 +224,14 @@ select sp_parallel_restricted(unique1) from tenk1 -> Parallel Seq Scan on public.tenk1 Output: unique1 Filter: (tenk1.stringu1 = 'GRAAAA'::name) -(9 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(10 rows) -- test parallel plan when group by expression is in target list. explain (costs off) select length(stringu1) from tenk1 group by length(stringu1); - QUERY PLAN ---------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Finalize HashAggregate Group Key: (length((stringu1)::text)) -> Gather @@ -231,7 +239,8 @@ explain (costs off) -> Partial HashAggregate Group Key: length((stringu1)::text) -> Parallel Seq Scan on tenk1 -(7 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(8 rows) select length(stringu1) from tenk1 group by length(stringu1); length @@ -241,8 +250,8 @@ select length(stringu1) from tenk1 group by length(stringu1); explain (costs off) select stringu1, count(*) from tenk1 group by stringu1 order by stringu1; - QUERY PLAN ----------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: stringu1 -> Finalize HashAggregate @@ -252,34 +261,37 @@ explain (costs off) -> Partial HashAggregate Group Key: stringu1 -> Parallel Seq Scan on tenk1 -(9 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(10 rows) -- test that parallel plan for aggregates is not selected when -- target list contains parallel restricted clause. explain (costs off) select sum(sp_parallel_restricted(unique1)) from tenk1 group by(sp_parallel_restricted(unique1)); - QUERY PLAN -------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- HashAggregate Group Key: sp_parallel_restricted(unique1) -> Gather Workers Planned: 4 -> Parallel Index Only Scan using tenk1_unique1 on tenk1 -(5 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(6 rows) -- test prepared statement prepare tenk1_count(integer) As select count((unique1)) from tenk1 where hundred > $1; explain (costs off) execute tenk1_count(1); - QUERY PLAN ----------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 4 -> Partial Aggregate -> Parallel Seq Scan on tenk1 Filter: (hundred > 1) -(6 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(7 rows) execute tenk1_count(1); count @@ -293,8 +305,8 @@ alter table tenk2 set (parallel_workers = 0); explain (costs off) select count(*) from tenk1 where (two, four) not in (select hundred, thousand from tenk2 where thousand > 100); - QUERY PLAN ------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 4 @@ -304,7 +316,8 @@ explain (costs off) SubPlan 1 -> Seq Scan on tenk2 Filter: (thousand > 100) -(9 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(10 rows) select count(*) from tenk1 where (two, four) not in (select hundred, thousand from tenk2 where thousand > 100); @@ -317,13 +330,14 @@ select count(*) from tenk1 where (two, four) not in explain (costs off) select * from tenk1 where (unique1 + random())::integer not in (select ten from tenk2); - QUERY PLAN ------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Seq Scan on tenk1 Filter: (NOT (hashed SubPlan 1)) SubPlan 1 -> Seq Scan on tenk2 -(4 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(5 rows) alter table tenk2 reset (parallel_workers); -- test parallel plan for a query containing initplan. @@ -334,8 +348,8 @@ alter table tenk2 set (parallel_workers = 2); explain (costs off) select count(*) from tenk1 where tenk1.unique1 = (Select max(tenk2.unique1) from tenk2); - QUERY PLAN ------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Aggregate InitPlan 1 (returns $2) -> Finalize Aggregate @@ -348,7 +362,8 @@ explain (costs off) Params Evaluated: $2 -> Parallel Seq Scan on tenk1 Filter: (unique1 = $2) -(12 rows) + Settings: enable_bitmapscan = 'off', enable_indexonlyscan = 'off', enable_indexscan = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(13 rows) select count(*) from tenk1 where tenk1.unique1 = (Select max(tenk2.unique1) from tenk2); @@ -366,15 +381,16 @@ set enable_seqscan to off; set enable_bitmapscan to off; explain (costs off) select count((unique1)) from tenk1 where hundred > 1; - QUERY PLAN --------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 4 -> Partial Aggregate -> Parallel Index Scan using tenk1_hundred on tenk1 Index Cond: (hundred > 1) -(6 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(7 rows) select count((unique1)) from tenk1 where hundred > 1; count @@ -385,15 +401,16 @@ select count((unique1)) from tenk1 where hundred > 1; -- test parallel index-only scans. explain (costs off) select count(*) from tenk1 where thousand > 95; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 4 -> Partial Aggregate -> Parallel Index Only Scan using tenk1_thous_tenthous on tenk1 Index Cond: (thousand > 95) -(6 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(7 rows) select count(*) from tenk1 where thousand > 95; count @@ -407,8 +424,8 @@ explain (costs off) select * from (select count(unique1) from tenk1 where hundred > 10) ss right join (values (1),(2),(3)) v(x) on true; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Nested Loop Left Join -> Values Scan on "*VALUES*" -> Finalize Aggregate @@ -417,7 +434,8 @@ select * from -> Partial Aggregate -> Parallel Index Scan using tenk1_hundred on tenk1 Index Cond: (hundred > 10) -(8 rows) + Settings: enable_bitmapscan = 'off', enable_material = 'off', enable_seqscan = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(9 rows) select * from (select count(unique1) from tenk1 where hundred > 10) ss @@ -433,8 +451,8 @@ explain (costs off) select * from (select count(*) from tenk1 where thousand > 99) ss right join (values (1),(2),(3)) v(x) on true; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Nested Loop Left Join -> Values Scan on "*VALUES*" -> Finalize Aggregate @@ -443,7 +461,8 @@ select * from -> Partial Aggregate -> Parallel Index Only Scan using tenk1_thous_tenthous on tenk1 Index Cond: (thousand > 99) -(8 rows) + Settings: enable_bitmapscan = 'off', enable_material = 'off', enable_seqscan = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(9 rows) select * from (select count(*) from tenk1 where thousand > 99) ss @@ -473,8 +492,8 @@ END $$; set work_mem='64kB'; --set small work mem to force lossy pages explain (costs off) select count(*) from tenk1, tenk2 where tenk1.hundred > 1 and tenk2.thousand=0; - QUERY PLAN ------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Aggregate -> Nested Loop -> Seq Scan on tenk2 @@ -485,7 +504,8 @@ explain (costs off) Recheck Cond: (hundred > 1) -> Bitmap Index Scan on tenk1_hundred Index Cond: (hundred > 1) -(10 rows) + Settings: effective_io_concurrency = '50', enable_hashjoin = 'off', enable_indexscan = 'off', enable_material = 'off', enable_mergejoin = 'off', enable_seqscan = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0', work_mem = '64kB' +(11 rows) select count(*) from tenk1, tenk2 where tenk1.hundred > 1 and tenk2.thousand=0; count @@ -505,23 +525,29 @@ select count(*) from bmscantest where a>1; -- test accumulation of stats for parallel nodes reset enable_seqscan; alter table tenk2 set (parallel_workers = 0); -explain (analyze, timing off, summary off, costs off) +explain (exec, timing off, summary off, costs off) select count(*) from tenk1, tenk2 where tenk1.hundred > 1 and tenk2.thousand=0; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Aggregate (actual rows=1 loops=1) + Buffers: shared hit=3795 -> Nested Loop (actual rows=98000 loops=1) + Buffers: shared hit=3795 -> Seq Scan on tenk2 (actual rows=10 loops=1) Filter: (thousand = 0) Rows Removed by Filter: 9990 + Buffers: shared hit=345 -> Gather (actual rows=9800 loops=10) Workers Planned: 4 Workers Launched: 4 + Buffers: shared hit=3450 -> Parallel Seq Scan on tenk1 (actual rows=1960 loops=50) Filter: (hundred > 1) Rows Removed by Filter: 40 -(11 rows) + Buffers: shared hit=3450 + Settings: effective_io_concurrency = '50', enable_hashjoin = 'off', enable_indexscan = 'off', enable_material = 'off', enable_mergejoin = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0', work_mem = '64kB' +(17 rows) alter table tenk2 reset (parallel_workers); reset work_mem; @@ -531,7 +557,7 @@ $$ declare ln text; begin for ln in - explain (analyze, timing off, summary off, costs off) + explain (exec, timing off, summary off, costs off) select * from (select ten from tenk1 where ten < 100 order by ten) ss right join (values (1),(2),(3)) v(x) on true @@ -542,13 +568,15 @@ begin end; $$; select * from explain_parallel_sort_stats(); - explain_parallel_sort_stats --------------------------------------------------------------------------- + explain_parallel_sort_stats +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Nested Loop Left Join (actual rows=30000 loops=1) + Buffers: shared hit=1427 -> Values Scan on "*VALUES*" (actual rows=3 loops=1) -> Gather Merge (actual rows=10000 loops=3) Workers Planned: 4 Workers Launched: 4 + Buffers: shared hit=1231 -> Sort (actual rows=2000 loops=15) Sort Key: tenk1.ten Sort Method: quicksort Memory: xxx @@ -556,9 +584,12 @@ select * from explain_parallel_sort_stats(); Worker 1: Sort Method: quicksort Memory: xxx Worker 2: Sort Method: quicksort Memory: xxx Worker 3: Sort Method: quicksort Memory: xxx + Buffers: shared hit=1623 -> Parallel Seq Scan on tenk1 (actual rows=2000 loops=15) Filter: (ten < 100) -(14 rows) + Buffers: shared hit=1035 + Settings: effective_io_concurrency = '50', enable_hashjoin = 'off', enable_indexscan = 'off', enable_material = 'off', enable_mergejoin = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(19 rows) reset enable_indexscan; reset enable_hashjoin; @@ -572,8 +603,8 @@ set enable_hashjoin to off; set enable_nestloop to off; explain (costs off) select count(*) from tenk1, tenk2 where tenk1.unique1 = tenk2.unique1; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 4 @@ -582,7 +613,8 @@ explain (costs off) Merge Cond: (tenk1.unique1 = tenk2.unique1) -> Parallel Index Only Scan using tenk1_unique1 on tenk1 -> Index Only Scan using tenk2_unique1 on tenk2 -(8 rows) + Settings: enable_hashjoin = 'off', enable_nestloop = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(9 rows) select count(*) from tenk1, tenk2 where tenk1.unique1 = tenk2.unique1; count @@ -596,8 +628,8 @@ reset enable_nestloop; set enable_hashagg = false; explain (costs off) select count(*) from tenk1 group by twenty; - QUERY PLAN ----------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize GroupAggregate Group Key: twenty -> Gather Merge @@ -607,7 +639,8 @@ explain (costs off) -> Sort Sort Key: twenty -> Parallel Seq Scan on tenk1 -(9 rows) + Settings: enable_hashagg = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(10 rows) select count(*) from tenk1 group by twenty; count @@ -643,8 +676,8 @@ end; $$ language plpgsql PARALLEL SAFE; explain (costs off, verbose) select ten, sp_simple_func(ten) from tenk1 where ten < 100 order by ten; - QUERY PLAN ------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------- Gather Merge Output: ten, (sp_simple_func(ten)) Workers Planned: 4 @@ -656,14 +689,15 @@ explain (costs off, verbose) -> Parallel Seq Scan on public.tenk1 Output: ten Filter: (tenk1.ten < 100) -(11 rows) + Settings: enable_hashagg = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(12 rows) drop function sp_simple_func(integer); -- test handling of SRFs in targetlist (bug in 10.0) explain (costs off) select count(*), generate_series(1,2) from tenk1 group by twenty; - QUERY PLAN ----------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------- ProjectSet -> Finalize GroupAggregate Group Key: twenty @@ -674,7 +708,8 @@ explain (costs off) -> Sort Sort Key: twenty -> Parallel Seq Scan on tenk1 -(10 rows) + Settings: enable_hashagg = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(11 rows) select count(*), generate_series(1,2) from tenk1 group by twenty; count | generate_series @@ -725,8 +760,8 @@ select count(*), generate_series(1,2) from tenk1 group by twenty; set parallel_leader_participation = off; explain (costs off) select count(*) from tenk1 group by twenty; - QUERY PLAN ----------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize GroupAggregate Group Key: twenty -> Gather Merge @@ -736,7 +771,8 @@ explain (costs off) -> Sort Sort Key: twenty -> Parallel Seq Scan on tenk1 -(9 rows) + Settings: enable_hashagg = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_leader_participation = 'off', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(10 rows) select count(*) from tenk1 group by twenty; count @@ -771,8 +807,8 @@ select * from (select string4, count(unique2) from tenk1 group by string4 order by string4) ss right join (values (1),(2),(3)) v(x) on true; - QUERY PLAN ----------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Nested Loop Left Join -> Values Scan on "*VALUES*" -> Finalize GroupAggregate @@ -784,7 +820,8 @@ select * from -> Sort Sort Key: tenk1.string4 -> Parallel Seq Scan on tenk1 -(11 rows) + Settings: enable_hashagg = 'off', enable_material = 'off', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(12 rows) select * from (select string4, count(unique2) @@ -811,14 +848,15 @@ reset enable_hashagg; -- check parallelized int8 aggregate (bug #14897) explain (costs off) select avg(unique1::int8) from tenk1; - QUERY PLAN -------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate -> Gather Workers Planned: 4 -> Partial Aggregate -> Parallel Index Only Scan using tenk1_unique1 on tenk1 -(5 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(6 rows) select avg(unique1::int8) from tenk1; avg @@ -829,15 +867,16 @@ select avg(unique1::int8) from tenk1; -- gather merge test with a LIMIT explain (costs off) select fivethous from tenk1 order by fivethous limit 4; - QUERY PLAN ----------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Limit -> Gather Merge Workers Planned: 4 -> Sort Sort Key: fivethous -> Parallel Seq Scan on tenk1 -(6 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(7 rows) select fivethous from tenk1 order by fivethous limit 4; fivethous @@ -852,15 +891,16 @@ select fivethous from tenk1 order by fivethous limit 4; set max_parallel_workers = 0; explain (costs off) select string4 from tenk1 order by string4 limit 5; - QUERY PLAN ----------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------- Limit -> Gather Merge Workers Planned: 4 -> Sort Sort Key: string4 -> Parallel Seq Scan on tenk1 -(6 rows) + Settings: max_parallel_workers = '0', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(7 rows) select string4 from tenk1 order by string4 limit 5; string4 @@ -878,15 +918,16 @@ select string4 from tenk1 order by string4 limit 5; set parallel_leader_participation = off; explain (costs off) select string4 from tenk1 order by string4 limit 5; - QUERY PLAN ----------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Limit -> Gather Merge Workers Planned: 4 -> Sort Sort Key: string4 -> Parallel Seq Scan on tenk1 -(6 rows) + Settings: max_parallel_workers = '0', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_leader_participation = 'off', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(7 rows) select string4 from tenk1 order by string4 limit 5; string4 @@ -904,14 +945,15 @@ SAVEPOINT settings; SET LOCAL force_parallel_mode = 1; explain (costs off) select stringu1::int2 from tenk1 where unique1 = 1; - QUERY PLAN ------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------- Gather Workers Planned: 1 Single Copy: true -> Index Scan using tenk1_unique1 on tenk1 Index Cond: (unique1 = 1) -(5 rows) + Settings: force_parallel_mode = 'on', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(6 rows) ROLLBACK TO SAVEPOINT settings; -- exercise record typmod remapping between backends @@ -962,8 +1004,8 @@ reset role; explain (costs off, verbose) select count(*) from tenk1 a where (unique1, two) in (select unique1, row_number() over() from tenk1 b); - QUERY PLAN ----------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Aggregate Output: count(*) -> Hash Semi Join @@ -982,14 +1024,15 @@ explain (costs off, verbose) Workers Planned: 4 -> Parallel Index Only Scan using tenk1_unique1 on public.tenk1 b Output: b.unique1 -(18 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(19 rows) -- LIMIT/OFFSET within sub-selects can't be pushed to workers. explain (costs off) select * from tenk1 a where two in (select two from tenk1 b where stringu1 like '%AAAA' limit 3); - QUERY PLAN ---------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Hash Semi Join Hash Cond: (a.two = b.two) -> Gather @@ -1001,19 +1044,23 @@ explain (costs off) Workers Planned: 4 -> Parallel Seq Scan on tenk1 b Filter: (stringu1 ~~ '%AAAA'::text) -(11 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(12 rows) -- to increase the parallel query test coverage SAVEPOINT settings; SET LOCAL force_parallel_mode = 1; -EXPLAIN (analyze, timing off, summary off, costs off) SELECT * FROM tenk1; - QUERY PLAN -------------------------------------------------------------- +EXPLAIN (exec, timing off, summary off, costs off) SELECT * FROM tenk1; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------- Gather (actual rows=10000 loops=1) Workers Planned: 4 Workers Launched: 4 + Buffers: shared hit=345 -> Parallel Seq Scan on tenk1 (actual rows=2000 loops=5) -(4 rows) + Buffers: shared hit=345 + Settings: force_parallel_mode = 'on', max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(7 rows) ROLLBACK TO SAVEPOINT settings; -- provoke error in worker @@ -1032,8 +1079,8 @@ EXPLAIN (COSTS OFF) SELECT unique1 FROM tenk1 WHERE fivethous = tenthous + 1 UNION ALL SELECT unique1 FROM tenk1 WHERE fivethous = tenthous + 1; - QUERY PLAN ----------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------- Gather Workers Planned: 4 -> Parallel Append @@ -1041,7 +1088,8 @@ SELECT unique1 FROM tenk1 WHERE fivethous = tenthous + 1; Filter: (fivethous = (tenthous + 1)) -> Parallel Seq Scan on tenk1 tenk1_1 Filter: (fivethous = (tenthous + 1)) -(7 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '10', parallel_tuple_cost = '0' +(8 rows) ROLLBACK TO SAVEPOINT settings; -- can't use multiple subqueries under a single Gather node due to initPlans @@ -1052,8 +1100,8 @@ UNION ALL SELECT unique1 FROM tenk1 WHERE fivethous = (SELECT unique2 FROM tenk1 WHERE fivethous = 1 LIMIT 1) ORDER BY 1; - QUERY PLAN --------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: tenk1.unique1 -> Append @@ -1079,7 +1127,8 @@ ORDER BY 1; Filter: (fivethous = 1) -> Parallel Seq Scan on tenk1 tenk1_1 Filter: (fivethous = $3) -(25 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(26 rows) -- test interaction with SRFs SELECT * FROM information_schema.foreign_data_wrapper_options @@ -1100,13 +1149,14 @@ CREATE TABLE fooarr(f1 text, f2 int[], f3 text); INSERT INTO fooarr VALUES('1', ARRAY[1,2], 'one'); PREPARE pstmt(text, int[]) AS SELECT * FROM fooarr WHERE f1 = $1 AND f2 = $2; EXPLAIN (COSTS OFF) EXECUTE pstmt('1', make_some_array(1,2)); - QUERY PLAN ------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Gather Workers Planned: 3 -> Parallel Seq Scan on fooarr Filter: ((f1 = '1'::text) AND (f2 = '{1,2}'::integer[])) -(4 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(5 rows) EXECUTE pstmt('1', make_some_array(1,2)); f1 | f2 | f3 @@ -1120,8 +1170,8 @@ CREATE VIEW tenk1_vw_sec WITH (security_barrier) AS SELECT * FROM tenk1; EXPLAIN (COSTS OFF) SELECT 1 FROM tenk1_vw_sec WHERE (SELECT sum(f1) FROM int4_tbl WHERE f1 < unique1) < 100; - QUERY PLAN -------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Subquery Scan on tenk1_vw_sec Filter: ((SubPlan 1) < 100) -> Gather @@ -1131,6 +1181,7 @@ SELECT 1 FROM tenk1_vw_sec -> Aggregate -> Seq Scan on int4_tbl Filter: (f1 < tenk1_vw_sec.unique1) -(9 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(10 rows) rollback; diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out index 6dfca7a606..836ee928a0 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -12,7 +12,7 @@ declare first_row bool := true; begin for ln in - execute format('explain analyze %s', $1) + execute format('explain exec %s', $1) loop if first_row then first_row := false; @@ -167,35 +167,35 @@ INSERT INTO ndistinct (a, b, c, filler1) ANALYZE ndistinct; -- Group Aggregate, due to over-estimate of the number of groups SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, b'); - estimated | actual ------------+-------- - 100 | 11 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY b, c'); - estimated | actual ------------+-------- - 100 | 11 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY b, c + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY b, c +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c'); - estimated | actual ------------+-------- - 100 | 11 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c, d'); - estimated | actual ------------+-------- - 200 | 11 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c... + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c, d +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY b, c, d'); - estimated | actual ------------+-------- - 200 | 11 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY b, c, d + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY b, c, d +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement -- correct command CREATE STATISTICS s10 ON a, b, c FROM ndistinct; ANALYZE ndistinct; @@ -208,37 +208,37 @@ SELECT stxkind, stxndistinct -- Hash Aggregate, thanks to estimates improved by the statistic SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, b'); - estimated | actual ------------+-------- - 11 | 11 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY b, c'); - estimated | actual ------------+-------- - 11 | 11 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY b, c + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY b, c +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c'); - estimated | actual ------------+-------- - 11 | 11 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement -- last two plans keep using Group Aggregate, because 'd' is not covered -- by the statistic and while it's NULL-only we assume 200 values for it SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c, d'); - estimated | actual ------------+-------- - 200 | 11 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c... + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c, d +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY b, c, d'); - estimated | actual ------------+-------- - 200 | 11 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY b, c, d + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY b, c, d +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement TRUNCATE TABLE ndistinct; -- under-estimates when using only per-column statistics INSERT INTO ndistinct (a, b, c, filler1) @@ -255,35 +255,35 @@ SELECT stxkind, stxndistinct -- correct esimates SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, b'); - estimated | actual ------------+-------- - 2550 | 2550 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c'); - estimated | actual ------------+-------- - 5000 | 5000 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c, d'); - estimated | actual ------------+-------- - 5000 | 5000 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c... + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c, d +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY b, c, d'); - estimated | actual ------------+-------- - 1632 | 1632 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY b, c, d + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY b, c, d +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, d'); - estimated | actual ------------+-------- - 500 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, d + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, d +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement DROP STATISTICS s10; SELECT stxkind, stxndistinct FROM pg_statistic_ext WHERE stxrelid = 'ndistinct'::regclass; @@ -293,35 +293,35 @@ SELECT stxkind, stxndistinct -- dropping the statistics results in under-estimates SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, b'); - estimated | actual ------------+-------- - 500 | 2550 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c'); - estimated | actual ------------+-------- - 500 | 5000 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c, d'); - estimated | actual ------------+-------- - 500 | 5000 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c... + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, b, c, d +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY b, c, d'); - estimated | actual ------------+-------- - 500 | 1632 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY b, c, d + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY b, c, d +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, d'); - estimated | actual ------------+-------- - 500 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, d + ^ +QUERY: explain exec SELECT COUNT(*) FROM ndistinct GROUP BY a, d +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement -- functional dependencies tests CREATE TABLE functional_dependencies ( filler1 TEXT, @@ -339,32 +339,32 @@ INSERT INTO functional_dependencies (a, b, c, filler1) SELECT mod(i, 23), mod(i, 29), mod(i, 31), i FROM generate_series(1,5000) s(i); ANALYZE functional_dependencies; SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a = 1 AND b = ''1'''); - estimated | actual ------------+-------- - 8 | 8 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM functional_dependencies WHERE a =... + ^ +QUERY: explain exec SELECT * FROM functional_dependencies WHERE a = 1 AND b = '1' +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a = 1 AND b = ''1'' AND c = 1'); - estimated | actual ------------+-------- - 1 | 1 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM functional_dependencies WHERE a =... + ^ +QUERY: explain exec SELECT * FROM functional_dependencies WHERE a = 1 AND b = '1' AND c = 1 +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement -- create statistics CREATE STATISTICS func_deps_stat (dependencies) ON a, b, c FROM functional_dependencies; ANALYZE functional_dependencies; SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a = 1 AND b = ''1'''); - estimated | actual ------------+-------- - 8 | 8 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM functional_dependencies WHERE a =... + ^ +QUERY: explain exec SELECT * FROM functional_dependencies WHERE a = 1 AND b = '1' +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a = 1 AND b = ''1'' AND c = 1'); - estimated | actual ------------+-------- - 1 | 1 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM functional_dependencies WHERE a =... + ^ +QUERY: explain exec SELECT * FROM functional_dependencies WHERE a = 1 AND b = '1' AND c = 1 +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement -- a => b, a => c, b => c TRUNCATE functional_dependencies; DROP STATISTICS func_deps_stat; @@ -372,47 +372,47 @@ INSERT INTO functional_dependencies (a, b, c, filler1) SELECT mod(i,100), mod(i,50), mod(i,25), i FROM generate_series(1,5000) s(i); ANALYZE functional_dependencies; SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a = 1 AND b = ''1'''); - estimated | actual ------------+-------- - 1 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM functional_dependencies WHERE a =... + ^ +QUERY: explain exec SELECT * FROM functional_dependencies WHERE a = 1 AND b = '1' +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a = 1 AND b = ''1'' AND c = 1'); - estimated | actual ------------+-------- - 1 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM functional_dependencies WHERE a =... + ^ +QUERY: explain exec SELECT * FROM functional_dependencies WHERE a = 1 AND b = '1' AND c = 1 +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement -- create statistics CREATE STATISTICS func_deps_stat (dependencies) ON a, b, c FROM functional_dependencies; ANALYZE functional_dependencies; SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a = 1 AND b = ''1'''); - estimated | actual ------------+-------- - 50 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM functional_dependencies WHERE a =... + ^ +QUERY: explain exec SELECT * FROM functional_dependencies WHERE a = 1 AND b = '1' +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a = 1 AND b = ''1'' AND c = 1'); - estimated | actual ------------+-------- - 50 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM functional_dependencies WHERE a =... + ^ +QUERY: explain exec SELECT * FROM functional_dependencies WHERE a = 1 AND b = '1' AND c = 1 +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement -- check change of column type doesn't break it ALTER TABLE functional_dependencies ALTER COLUMN c TYPE numeric; SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a = 1 AND b = ''1'' AND c = 1'); - estimated | actual ------------+-------- - 50 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM functional_dependencies WHERE a =... + ^ +QUERY: explain exec SELECT * FROM functional_dependencies WHERE a = 1 AND b = '1' AND c = 1 +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement ANALYZE functional_dependencies; SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a = 1 AND b = ''1'' AND c = 1'); - estimated | actual ------------+-------- - 50 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM functional_dependencies WHERE a =... + ^ +QUERY: explain exec SELECT * FROM functional_dependencies WHERE a = 1 AND b = '1' AND c = 1 +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement -- MCV lists CREATE TABLE mcv_lists ( filler1 TEXT, @@ -428,32 +428,32 @@ INSERT INTO mcv_lists (a, b, c, filler1) SELECT mod(i,37), mod(i,41), mod(i,43), mod(i,47) FROM generate_series(1,5000) s(i); ANALYZE mcv_lists; SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a = 1 AND b = ''1'''); - estimated | actual ------------+-------- - 3 | 4 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a = 1 AND b = ''1'' AND c = 1'); - estimated | actual ------------+-------- - 1 | 1 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1'... + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' AND c = 1 +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement -- create statistics CREATE STATISTICS mcv_lists_stats (mcv) ON a, b, c FROM mcv_lists; ANALYZE mcv_lists; SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a = 1 AND b = ''1'''); - estimated | actual ------------+-------- - 3 | 4 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a = 1 AND b = ''1'' AND c = 1'); - estimated | actual ------------+-------- - 1 | 1 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1'... + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' AND c = 1 +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement -- 100 distinct combinations, all in the MCV list TRUNCATE mcv_lists; DROP STATISTICS mcv_lists_stats; @@ -461,80 +461,80 @@ INSERT INTO mcv_lists (a, b, c, filler1) SELECT mod(i,100), mod(i,50), mod(i,25), i FROM generate_series(1,5000) s(i); ANALYZE mcv_lists; SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a = 1 AND b = ''1'''); - estimated | actual ------------+-------- - 1 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a < 1 AND b < ''1'''); - estimated | actual ------------+-------- - 1 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a < 1 AND b < '1' + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a < 1 AND b < '1' +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a <= 0 AND b <= ''0'''); - estimated | actual ------------+-------- - 1 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a <= 0 AND b <= '... + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a <= 0 AND b <= '0' +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a = 1 AND b = ''1'' AND c = 1'); - estimated | actual ------------+-------- - 1 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1'... + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' AND c = 1 +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a < 5 AND b < ''1'' AND c < 5'); - estimated | actual ------------+-------- - 1 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a < 5 AND b < '1'... + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a < 5 AND b < '1' AND c < 5 +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a <= 4 AND b <= ''0'' AND c <= 4'); - estimated | actual ------------+-------- - 1 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a <= 4 AND b <= '... + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a <= 4 AND b <= '0' AND c <= 4 +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement -- create statistics CREATE STATISTICS mcv_lists_stats (mcv) ON a, b, c FROM mcv_lists; ANALYZE mcv_lists; SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a = 1 AND b = ''1'''); - estimated | actual ------------+-------- - 50 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a < 1 AND b < ''1'''); - estimated | actual ------------+-------- - 50 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a < 1 AND b < '1' + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a < 1 AND b < '1' +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a <= 0 AND b <= ''0'''); - estimated | actual ------------+-------- - 50 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a <= 0 AND b <= '... + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a <= 0 AND b <= '0' +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a = 1 AND b = ''1'' AND c = 1'); - estimated | actual ------------+-------- - 50 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1'... + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' AND c = 1 +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a < 5 AND b < ''1'' AND c < 5'); - estimated | actual ------------+-------- - 50 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a < 5 AND b < '1'... + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a < 5 AND b < '1' AND c < 5 +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a <= 4 AND b <= ''0'' AND c <= 4'); - estimated | actual ------------+-------- - 50 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a <= 4 AND b <= '... + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a <= 4 AND b <= '0' AND c <= 4 +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement -- check change of unrelated column type does not reset the MCV statistics ALTER TABLE mcv_lists ALTER COLUMN d TYPE VARCHAR(64); SELECT stxmcv IS NOT NULL FROM pg_statistic_ext WHERE stxname = 'mcv_lists_stats'; @@ -546,18 +546,18 @@ SELECT stxmcv IS NOT NULL FROM pg_statistic_ext WHERE stxname = 'mcv_lists_stats -- check change of column type resets the MCV statistics ALTER TABLE mcv_lists ALTER COLUMN c TYPE numeric; SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a = 1 AND b = ''1'''); - estimated | actual ------------+-------- - 1 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement ANALYZE mcv_lists; SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a = 1 AND b = ''1'''); - estimated | actual ------------+-------- - 50 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a = 1 AND b = '1' +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement -- 100 distinct combinations with NULL values, all in the MCV list TRUNCATE mcv_lists; DROP STATISTICS mcv_lists_stats; @@ -570,32 +570,32 @@ INSERT INTO mcv_lists (a, b, c, filler1) FROM generate_series(1,5000) s(i); ANALYZE mcv_lists; SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a IS NULL AND b IS NULL'); - estimated | actual ------------+-------- - 1 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a IS NULL AND b I... + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a IS NULL AND b IS NULL +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a IS NULL AND b IS NULL AND c IS NULL'); - estimated | actual ------------+-------- - 1 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a IS NULL AND b I... + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a IS NULL AND b IS NULL AND c IS NULL +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement -- create statistics CREATE STATISTICS mcv_lists_stats (mcv) ON a, b, c FROM mcv_lists; ANALYZE mcv_lists; SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a IS NULL AND b IS NULL'); - estimated | actual ------------+-------- - 50 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a IS NULL AND b I... + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a IS NULL AND b IS NULL +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a IS NULL AND b IS NULL AND c IS NULL'); - estimated | actual ------------+-------- - 50 | 50 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists WHERE a IS NULL AND b I... + ^ +QUERY: explain exec SELECT * FROM mcv_lists WHERE a IS NULL AND b IS NULL AND c IS NULL +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement -- test pg_mcv_list_items with a very simple (single item) MCV list TRUNCATE mcv_lists; INSERT INTO mcv_lists (a, b, c) SELECT 1, 2, 3 FROM generate_series(1,1000) s(i); @@ -634,53 +634,53 @@ INSERT INTO mcv_lists_bool (a, b, c) FROM generate_series(1,10000) s(i); ANALYZE mcv_lists_bool; SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists_bool WHERE a AND b AND c'); - estimated | actual ------------+-------- - 156 | 1250 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists_bool WHERE a AND b AND ... + ^ +QUERY: explain exec SELECT * FROM mcv_lists_bool WHERE a AND b AND c +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists_bool WHERE NOT a AND b AND c'); - estimated | actual ------------+-------- - 156 | 0 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists_bool WHERE NOT a AND b ... + ^ +QUERY: explain exec SELECT * FROM mcv_lists_bool WHERE NOT a AND b AND c +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists_bool WHERE NOT a AND NOT b AND c'); - estimated | actual ------------+-------- - 469 | 0 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists_bool WHERE NOT a AND NO... + ^ +QUERY: explain exec SELECT * FROM mcv_lists_bool WHERE NOT a AND NOT b AND c +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists_bool WHERE NOT a AND b AND NOT c'); - estimated | actual ------------+-------- - 1094 | 0 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists_bool WHERE NOT a AND b ... + ^ +QUERY: explain exec SELECT * FROM mcv_lists_bool WHERE NOT a AND b AND NOT c +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement CREATE STATISTICS mcv_lists_bool_stats (mcv) ON a, b, c FROM mcv_lists_bool; ANALYZE mcv_lists_bool; SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists_bool WHERE a AND b AND c'); - estimated | actual ------------+-------- - 1250 | 1250 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists_bool WHERE a AND b AND ... + ^ +QUERY: explain exec SELECT * FROM mcv_lists_bool WHERE a AND b AND c +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists_bool WHERE NOT a AND b AND c'); - estimated | actual ------------+-------- - 1 | 0 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists_bool WHERE NOT a AND b ... + ^ +QUERY: explain exec SELECT * FROM mcv_lists_bool WHERE NOT a AND b AND c +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists_bool WHERE NOT a AND NOT b AND c'); - estimated | actual ------------+-------- - 1 | 0 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists_bool WHERE NOT a AND NO... + ^ +QUERY: explain exec SELECT * FROM mcv_lists_bool WHERE NOT a AND NOT b AND c +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists_bool WHERE NOT a AND b AND NOT c'); - estimated | actual ------------+-------- - 1 | 0 -(1 row) - +ERROR: syntax error at or near "exec" +LINE 1: explain exec SELECT * FROM mcv_lists_bool WHERE NOT a AND b ... + ^ +QUERY: explain exec SELECT * FROM mcv_lists_bool WHERE NOT a AND b AND NOT c +CONTEXT: PL/pgSQL function check_estimated_rows(text) line 7 at FOR over EXECUTE statement diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out index 2d1963d12a..fcbffe71f5 100644 --- a/src/test/regress/expected/subselect.out +++ b/src/test/regress/expected/subselect.out @@ -1120,8 +1120,8 @@ drop function tattle(x int, y int); -- -- Test that LIMIT can be pushed to SORT through a subquery that just projects -- columns. We check for that having happened by looking to see if EXPLAIN --- ANALYZE shows that a top-N sort was used. We must suppress or filter away --- all the non-invariant parts of the EXPLAIN ANALYZE output. +-- EXEC shows that a top-N sort was used. We must suppress or filter away +-- all the non-invariant parts of the EXPLAIN EXEC output. -- create table sq_limit (pk int primary key, c1 int, c2 int); insert into sq_limit values @@ -1138,7 +1138,7 @@ $$ declare ln text; begin for ln in - explain (analyze, summary off, timing off, costs off) + explain (exec, summary off, timing off, costs off) select * from (select pk,c2 from sq_limit order by c1,pk) as x limit 3 loop ln := regexp_replace(ln, 'Memory: \S*', 'Memory: xxx'); @@ -1152,12 +1152,16 @@ select * from explain_sq_limit(); explain_sq_limit ---------------------------------------------------------------- Limit (actual rows=3 loops=1) + Buffers: shared hit=1 -> Subquery Scan on x (actual rows=3 loops=1) + Buffers: shared hit=1 -> Sort (actual rows=3 loops=1) Sort Key: sq_limit.c1, sq_limit.pk Sort Method: top-N heapsort Memory: xxx + Buffers: shared hit=1 -> Seq Scan on sq_limit (actual rows=8 loops=1) -(6 rows) + Buffers: shared hit=1 +(10 rows) select * from (select pk,c2 from sq_limit order by c1,pk) as x limit 3; pk | c2 diff --git a/src/test/regress/expected/tidscan.out b/src/test/regress/expected/tidscan.out index 9b5eb04bfd..b19516e39b 100644 --- a/src/test/regress/expected/tidscan.out +++ b/src/test/regress/expected/tidscan.out @@ -120,7 +120,8 @@ FROM tidscan t1 JOIN tidscan t2 ON t1.ctid = t2.ctid WHERE t1.id = 1; Filter: (id = 1) -> Tid Scan on tidscan t2 TID Cond: (ctid = t1.ctid) -(5 rows) + Settings: enable_hashjoin = 'off' +(6 rows) SELECT t1.ctid, t1.*, t2.ctid, t2.* FROM tidscan t1 JOIN tidscan t2 ON t1.ctid = t2.ctid WHERE t1.id = 1; @@ -139,7 +140,8 @@ FROM tidscan t1 LEFT JOIN tidscan t2 ON t1.ctid = t2.ctid WHERE t1.id = 1; Filter: (id = 1) -> Tid Scan on tidscan t2 TID Cond: (t1.ctid = ctid) -(5 rows) + Settings: enable_hashjoin = 'off' +(6 rows) SELECT t1.ctid, t1.*, t2.ctid, t2.* FROM tidscan t1 LEFT JOIN tidscan t2 ON t1.ctid = t2.ctid WHERE t1.id = 1; @@ -189,14 +191,16 @@ FETCH NEXT FROM c; (1 row) -- perform update -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; QUERY PLAN --------------------------------------------------- Update on tidscan (actual rows=1 loops=1) + Buffers: shared hit=3 -> Tid Scan on tidscan (actual rows=1 loops=1) TID Cond: CURRENT OF c -(3 rows) + Buffers: shared hit=2 +(5 rows) FETCH NEXT FROM c; ctid | id @@ -205,14 +209,16 @@ FETCH NEXT FROM c; (1 row) -- perform update -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; QUERY PLAN --------------------------------------------------- Update on tidscan (actual rows=1 loops=1) + Buffers: shared hit=3 -> Tid Scan on tidscan (actual rows=1 loops=1) TID Cond: CURRENT OF c -(3 rows) + Buffers: shared hit=2 +(5 rows) SELECT * FROM tidscan; id @@ -229,7 +235,7 @@ FETCH NEXT FROM c; (0 rows) -- should error out -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; ERROR: cursor "c" is not positioned on a row ROLLBACK; @@ -268,7 +274,8 @@ SELECT count(*) FROM tenk1 t1 JOIN tenk1 t2 ON t1.ctid = t2.ctid; -> Sort Sort Key: t2.ctid -> Seq Scan on tenk1 t2 -(9 rows) + Settings: enable_hashjoin = 'off' +(10 rows) SELECT count(*) FROM tenk1 t1 JOIN tenk1 t2 ON t1.ctid = t2.ctid; count diff --git a/src/test/regress/expected/tsearch.out b/src/test/regress/expected/tsearch.out index 6f61acc1ed..b61af4bed4 100644 --- a/src/test/regress/expected/tsearch.out +++ b/src/test/regress/expected/tsearch.out @@ -121,12 +121,13 @@ SET enable_seqscan=OFF; SET enable_indexscan=ON; SET enable_bitmapscan=OFF; explain (costs off) SELECT count(*) FROM test_tsvector WHERE a @@ 'wr|qh'; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Aggregate -> Index Scan using wowidx on test_tsvector Index Cond: (a @@ '''wr'' | ''qh'''::tsquery) -(3 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(4 rows) SELECT count(*) FROM test_tsvector WHERE a @@ 'wr|qh'; count @@ -198,7 +199,8 @@ explain (costs off) SELECT count(*) FROM test_tsvector WHERE a @@ 'wr|qh'; Recheck Cond: (a @@ '''wr'' | ''qh'''::tsquery) -> Bitmap Index Scan on wowidx Index Cond: (a @@ '''wr'' | ''qh'''::tsquery) -(5 rows) + Settings: enable_indexscan = 'off', enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM test_tsvector WHERE a @@ 'wr|qh'; count @@ -275,7 +277,8 @@ explain (costs off) SELECT count(*) FROM test_tsvector WHERE a @@ 'wr|qh'; Recheck Cond: (a @@ '''wr'' | ''qh'''::tsquery) -> Bitmap Index Scan on wowidx Index Cond: (a @@ '''wr'' | ''qh'''::tsquery) -(5 rows) + Settings: enable_seqscan = 'off' +(6 rows) SELECT count(*) FROM test_tsvector WHERE a @@ 'wr|qh'; count diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.out index 7189f5bd3d..828563ad87 100644 --- a/src/test/regress/expected/union.out +++ b/src/test/regress/expected/union.out @@ -404,7 +404,8 @@ select count(*) from -> Seq Scan on tenk1 -> Subquery Scan on "*SELECT* 1" -> Index Only Scan using tenk1_unique1 on tenk1 tenk1_1 -(10 rows) + Settings: enable_hashagg = 'off' +(11 rows) select count(*) from ( select unique1 from tenk1 intersect select fivethous from tenk1 ) ss; @@ -426,7 +427,8 @@ select unique1 from tenk1 except select unique2 from tenk1 where unique2 != 10; -> Subquery Scan on "*SELECT* 2" -> Index Only Scan using tenk1_unique2 on tenk1 tenk1_1 Filter: (unique2 <> 10) -(9 rows) + Settings: enable_hashagg = 'off' +(10 rows) select unique1 from tenk1 except select unique2 from tenk1 where unique2 != 10; unique1 @@ -578,7 +580,8 @@ select from generate_series(1,5) union select from generate_series(1,3); -> Append -> Function Scan on generate_series -> Function Scan on generate_series generate_series_1 -(4 rows) + Settings: enable_sort = 'off' +(5 rows) explain (costs off) select from generate_series(1,5) intersect select from generate_series(1,3); @@ -590,7 +593,8 @@ select from generate_series(1,5) intersect select from generate_series(1,3); -> Function Scan on generate_series -> Subquery Scan on "*SELECT* 2" -> Function Scan on generate_series generate_series_1 -(6 rows) + Settings: enable_sort = 'off' +(7 rows) select from generate_series(1,5) union select from generate_series(1,3); -- @@ -627,7 +631,8 @@ select from generate_series(1,5) union select from generate_series(1,3); -> Append -> Function Scan on generate_series -> Function Scan on generate_series generate_series_1 -(4 rows) + Settings: enable_hashagg = 'off' +(5 rows) explain (costs off) select from generate_series(1,5) intersect select from generate_series(1,3); @@ -639,7 +644,8 @@ select from generate_series(1,5) intersect select from generate_series(1,3); -> Function Scan on generate_series -> Subquery Scan on "*SELECT* 2" -> Function Scan on generate_series generate_series_1 -(6 rows) + Settings: enable_hashagg = 'off' +(7 rows) select from generate_series(1,5) union select from generate_series(1,3); -- @@ -707,14 +713,15 @@ explain (costs off) UNION ALL SELECT * FROM t2) t WHERE ab = 'ab'; - QUERY PLAN ---------------------------------------------- + QUERY PLAN +------------------------------------------------------------- Append -> Index Scan using t1_ab_idx on t1 Index Cond: ((a || b) = 'ab'::text) -> Index Only Scan using t2_pkey on t2 Index Cond: (ab = 'ab'::text) -(5 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(6 rows) explain (costs off) SELECT * FROM @@ -722,8 +729,8 @@ explain (costs off) UNION SELECT * FROM t2) t WHERE ab = 'ab'; - QUERY PLAN ---------------------------------------------------- + QUERY PLAN +------------------------------------------------------------- HashAggregate Group Key: ((t1.a || t1.b)) -> Append @@ -731,7 +738,8 @@ explain (costs off) Index Cond: ((a || b) = 'ab'::text) -> Index Only Scan using t2_pkey on t2 Index Cond: (ab = 'ab'::text) -(7 rows) + Settings: enable_bitmapscan = 'off', enable_seqscan = 'off' +(8 rows) -- -- Test that ORDER BY for UNION ALL can be pushed down to inheritance @@ -751,8 +759,8 @@ explain (costs off) UNION ALL SELECT ab FROM t2) t ORDER BY 1 LIMIT 8; - QUERY PLAN ------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------- Limit -> Merge Append Sort Key: ((t1.a || t1.b)) @@ -760,7 +768,8 @@ explain (costs off) -> Index Scan using t1c_ab_idx on t1c -> Index Scan using t2_pkey on t2 -> Index Scan using t2c_pkey on t2c -(7 rows) + Settings: enable_bitmapscan = 'off', enable_indexonlyscan = 'off' +(8 rows) SELECT * FROM (SELECT a || b AS ab FROM t1 @@ -801,7 +810,8 @@ select event_id Sort Key: events_child.event_id -> Seq Scan on events_child -> Index Scan using other_events_pkey on other_events -(7 rows) + Settings: enable_indexonlyscan = 'off' +(8 rows) drop table events_child, events, other_events; reset enable_indexonlyscan; diff --git a/src/test/regress/expected/write_parallel.out b/src/test/regress/expected/write_parallel.out index 0c4da2591a..51e8380cdf 100644 --- a/src/test/regress/expected/write_parallel.out +++ b/src/test/regress/expected/write_parallel.out @@ -15,8 +15,8 @@ set max_parallel_workers_per_gather=4; -- explain (costs off) create table parallel_write as select length(stringu1) from tenk1 group by length(stringu1); - QUERY PLAN ---------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Finalize HashAggregate Group Key: (length((stringu1)::text)) -> Gather @@ -24,15 +24,16 @@ explain (costs off) create table parallel_write as -> Partial HashAggregate Group Key: length((stringu1)::text) -> Parallel Seq Scan on tenk1 -(7 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(8 rows) create table parallel_write as select length(stringu1) from tenk1 group by length(stringu1); drop table parallel_write; explain (costs off) select length(stringu1) into parallel_write from tenk1 group by length(stringu1); - QUERY PLAN ---------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Finalize HashAggregate Group Key: (length((stringu1)::text)) -> Gather @@ -40,15 +41,16 @@ explain (costs off) select length(stringu1) into parallel_write -> Partial HashAggregate Group Key: length((stringu1)::text) -> Parallel Seq Scan on tenk1 -(7 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(8 rows) select length(stringu1) into parallel_write from tenk1 group by length(stringu1); drop table parallel_write; explain (costs off) create materialized view parallel_mat_view as select length(stringu1) from tenk1 group by length(stringu1); - QUERY PLAN ---------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Finalize HashAggregate Group Key: (length((stringu1)::text)) -> Gather @@ -56,15 +58,16 @@ explain (costs off) create materialized view parallel_mat_view as -> Partial HashAggregate Group Key: length((stringu1)::text) -> Parallel Seq Scan on tenk1 -(7 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(8 rows) create materialized view parallel_mat_view as select length(stringu1) from tenk1 group by length(stringu1); drop materialized view parallel_mat_view; prepare prep_stmt as select length(stringu1) from tenk1 group by length(stringu1); explain (costs off) create table parallel_write as execute prep_stmt; - QUERY PLAN ---------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Finalize HashAggregate Group Key: (length((stringu1)::text)) -> Gather @@ -72,7 +75,8 @@ explain (costs off) create table parallel_write as execute prep_stmt; -> Partial HashAggregate Group Key: length((stringu1)::text) -> Parallel Seq Scan on tenk1 -(7 rows) + Settings: max_parallel_workers_per_gather = '4', min_parallel_table_scan_size = '0', parallel_setup_cost = '0', parallel_tuple_cost = '0' +(8 rows) create table parallel_write as execute prep_stmt; drop table parallel_write; diff --git a/src/test/regress/sql/join_hash.sql b/src/test/regress/sql/join_hash.sql index ae352e9b0b..b44d705d57 100644 --- a/src/test/regress/sql/join_hash.sql +++ b/src/test/regress/sql/join_hash.sql @@ -7,7 +7,7 @@ begin; set local min_parallel_table_scan_size = 0; set local parallel_setup_cost = 0; --- Extract bucket and batch counts from an explain analyze plan. In +-- Extract bucket and batch counts from an explain exec plan. In -- general we can't make assertions about how many batches (or -- buckets) will be required because it can vary, but we can in some -- special cases and we can check for growth. @@ -42,7 +42,7 @@ declare hash_node json; begin for whole_plan in - execute 'explain (analyze, format ''json'') ' || query + execute 'explain (exec, format ''json'') ' || query loop hash_node := find_hash(json_extract_path(whole_plan, '0', 'Plan')); original := hash_node->>'Original Hash Batches'; @@ -280,7 +280,7 @@ rollback to settings; -- A couple of other hash join tests unrelated to work_mem management. --- Check that EXPLAIN ANALYZE has data even if the leader doesn't participate +-- Check that EXPLAIN EXEC has data even if the leader doesn't participate savepoint settings; set local max_parallel_workers_per_gather = 2; set local work_mem = '4MB'; diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql index 246c6274af..684aa3c464 100644 --- a/src/test/regress/sql/partition_prune.sql +++ b/src/test/regress/sql/partition_prune.sql @@ -327,7 +327,7 @@ create table ab_a3_b2 partition of ab_a3 for values in (2); create table ab_a3_b3 partition of ab_a3 for values in (3); -- Disallow index only scans as concurrent transactions may stop visibility --- bits being set causing "Heap Fetches" to be unstable in the EXPLAIN ANALYZE +-- bits being set causing "Heap Fetches" to be unstable in the EXPLAIN EXEC -- output. set enable_indexonlyscan = off; @@ -342,8 +342,8 @@ execute ab_q1 (1, 8, 3); execute ab_q1 (1, 8, 3); execute ab_q1 (1, 8, 3); -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2, 3); -explain (analyze, costs off, summary off, timing off) execute ab_q1 (1, 2, 3); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 2, 3); +explain (exec, costs off, summary off, timing off) execute ab_q1 (1, 2, 3); deallocate ab_q1; @@ -359,8 +359,8 @@ execute ab_q1 (1, 8); execute ab_q1 (1, 8); execute ab_q1 (1, 8); -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2); -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 4); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 4); -- Ensure a mix of PARAM_EXTERN and PARAM_EXEC Params work together at -- different levels of partitioning. @@ -373,7 +373,7 @@ execute ab_q2 (1, 8); execute ab_q2 (1, 8); execute ab_q2 (1, 8); -explain (analyze, costs off, summary off, timing off) execute ab_q2 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q2 (2, 2); -- As above, but swap the PARAM_EXEC Param to the first partition level prepare ab_q3 (int, int) as @@ -385,7 +385,7 @@ execute ab_q3 (1, 8); execute ab_q3 (1, 8); execute ab_q3 (1, 8); -explain (analyze, costs off, summary off, timing off) execute ab_q3 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q3 (2, 2); -- Test a backwards Append scan create table list_part (a int) partition by list (a); @@ -416,13 +416,13 @@ begin; create function list_part_fn(int) returns int as $$ begin return $1; end;$$ language plpgsql stable; -- Ensure pruning works using a stable function containing no Vars -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1); +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1); -- Ensure pruning does not take place when the function has a Var parameter -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(a); +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(a); -- Ensure pruning does not take place when the expression contains a Var. -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1) + a; +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1) + a; rollback; @@ -440,7 +440,7 @@ declare ln text; begin for ln in - execute format('explain (analyze, costs off, summary off, timing off) %s', + execute format('explain (exec, costs off, summary off, timing off) %s', $1) loop if ln like '%Parallel%' then @@ -537,15 +537,15 @@ reset min_parallel_table_scan_size; reset max_parallel_workers_per_gather; -- Test run-time partition pruning with an initplan -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from ab where a = (select max(a) from lprt_a) and b = (select max(a)-1 from lprt_a); -- Test run-time partition pruning with UNION ALL parents -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from (select * from ab where a = 1 union all select * from ab) ab where b = (select 1); -- A case containing a UNION ALL with a non-partitioned child. -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from (select * from ab where a = 1 union all (values(10,5)) union all select * from ab) ab where b = (select 1); -- Another UNION ALL test, but containing a mix of exec init and exec run-time pruning. @@ -566,7 +566,7 @@ union all ) ab where a = $1 and b = (select -10); -- Ensure the xy_1 subplan is not pruned. -explain (analyze, costs off, summary off, timing off) execute ab_q6(1); +explain (exec, costs off, summary off, timing off) execute ab_q6(1); -- Ensure we see just the xy_1 row. execute ab_q6(100); @@ -584,14 +584,14 @@ deallocate ab_q6; -- UPDATE on a partition subtree has been seen to have problems. insert into ab values (1,2); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a; table ab; -- Test UPDATE where source relation has run-time pruning enabled truncate ab; insert into ab values (1, 1), (1, 2), (1, 3), (2, 1); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) update ab_a1 set b = 3 from ab_a2 where ab_a2.b = (select 1); select tableoid::regclass, * from ab; @@ -622,10 +622,10 @@ insert into tprt values (10), (20), (501), (502), (505), (1001), (4500); set enable_hashjoin = off; set enable_mergejoin = off; -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 > tprt.col1; -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -638,10 +638,10 @@ order by tbl1.col1, tprt.col1; -- Multiple partitions insert into tbl1 values (1001), (1010), (1011); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 inner join tprt on tbl1.col1 > tprt.col1; -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 inner join tprt on tbl1.col1 = tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -655,7 +655,7 @@ order by tbl1.col1, tprt.col1; -- Last partition delete from tbl1; insert into tbl1 values (4400); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 < tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -665,7 +665,7 @@ order by tbl1.col1, tprt.col1; -- No matching partition delete from tbl1; insert into tbl1 values (10000); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -696,7 +696,7 @@ execute part_abc_q1 (1, 2, 3); execute part_abc_q1 (1, 2, 3); -- Single partition should be scanned. -explain (analyze, costs off, summary off, timing off) execute part_abc_q1 (1, 2, 3); +explain (exec, costs off, summary off, timing off) execute part_abc_q1 (1, 2, 3); deallocate part_abc_q1; @@ -722,13 +722,13 @@ execute q1 (1,2); execute q1 (1,2); execute q1 (1,2); -explain (analyze, costs off, summary off, timing off) execute q1 (1,1); +explain (exec, costs off, summary off, timing off) execute q1 (1,1); -explain (analyze, costs off, summary off, timing off) execute q1 (2,2); +explain (exec, costs off, summary off, timing off) execute q1 (2,2); -- Try with no matching partitions. One subplan should remain in this case, -- but it shouldn't be executed. -explain (analyze, costs off, summary off, timing off) execute q1 (0,0); +explain (exec, costs off, summary off, timing off) execute q1 (0,0); deallocate q1; @@ -742,14 +742,14 @@ execute q1 (1,2,3,4); execute q1 (1,2,3,4); -- Both partitions allowed by IN clause, but one disallowed by <> clause -explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,0); +explain (exec, costs off, summary off, timing off) execute q1 (1,2,2,0); -- Both partitions allowed by IN clause, then both excluded again by <> clauses. -- One subplan will remain in this case, but it should not be executed. -explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,1); +explain (exec, costs off, summary off, timing off) execute q1 (1,2,2,1); -- Ensure Params that evaluate to NULL properly prune away all partitions -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from listp where a = (select null::int); drop table listp; @@ -762,10 +762,10 @@ create table boolp (a bool) partition by list (a); create table boolp_t partition of boolp for values in('t'); create table boolp_f partition of boolp for values in('f'); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from boolp where a = (select value from boolvalues where value); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from boolp where a = (select value from boolvalues where not value); drop table boolp; @@ -793,18 +793,18 @@ execute mt_q1(0); execute mt_q1(0); execute mt_q1(0); -explain (analyze, costs off, summary off, timing off) execute mt_q1(15); +explain (exec, costs off, summary off, timing off) execute mt_q1(15); execute mt_q1(15); -explain (analyze, costs off, summary off, timing off) execute mt_q1(25); +explain (exec, costs off, summary off, timing off) execute mt_q1(25); execute mt_q1(25); -- Ensure MergeAppend behaves correctly when no subplans match -explain (analyze, costs off, summary off, timing off) execute mt_q1(35); +explain (exec, costs off, summary off, timing off) execute mt_q1(35); execute mt_q1(35); deallocate mt_q1; -- ensure initplan params properly prune partitions -explain (analyze, costs off, summary off, timing off) select * from ma_test where a >= (select min(b) from ma_test_p2) order by b; +explain (exec, costs off, summary off, timing off) select * from ma_test where a >= (select min(b) from ma_test_p2) order by b; reset enable_seqscan; reset enable_sort; @@ -987,7 +987,7 @@ create table listp1 partition of listp for values in(1); create table listp2 partition of listp for values in(2) partition by list(b); create table listp2_10 partition of listp2 for values in (10); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from listp where a = (select 2) and b <> 10; -- diff --git a/src/test/regress/sql/select.sql b/src/test/regress/sql/select.sql index b5929b2eca..f573dfa921 100644 --- a/src/test/regress/sql/select.sql +++ b/src/test/regress/sql/select.sql @@ -196,7 +196,7 @@ explain (costs off) select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; -- actually run the query with an analyze to use the partial index -explain (costs off, analyze on, timing off, summary off) +explain (costs off, exec on, timing off, summary off) select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; explain (costs off) select unique2 from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; diff --git a/src/test/regress/sql/select_into.sql b/src/test/regress/sql/select_into.sql index a708fef0ea..bd2f918294 100644 --- a/src/test/regress/sql/select_into.sql +++ b/src/test/regress/sql/select_into.sql @@ -85,12 +85,12 @@ SELECT make_table(); SELECT * FROM created_table; --- Try EXPLAIN ANALYZE SELECT INTO and EXPLAIN ANALYZE CREATE TABLE AS +-- Try EXPLAIN EXEC SELECT INTO and EXPLAIN EXEC CREATE TABLE AS -- WITH NO DATA, but hide the outputs since they won't be stable. DO $$ BEGIN - EXECUTE 'EXPLAIN ANALYZE SELECT * INTO TABLE easi FROM int8_tbl'; - EXECUTE 'EXPLAIN ANALYZE CREATE TABLE easi2 AS SELECT * FROM int8_tbl WITH NO DATA'; + EXECUTE 'EXPLAIN EXEC SELECT * INTO TABLE easi FROM int8_tbl'; + EXECUTE 'EXPLAIN EXEC CREATE TABLE easi2 AS SELECT * FROM int8_tbl WITH NO DATA'; END$$; DROP TABLE created_table; diff --git a/src/test/regress/sql/select_parallel.sql b/src/test/regress/sql/select_parallel.sql index 03c056b8b7..de8ef80ecf 100644 --- a/src/test/regress/sql/select_parallel.sql +++ b/src/test/regress/sql/select_parallel.sql @@ -197,7 +197,7 @@ select count(*) from bmscantest where a>1; -- test accumulation of stats for parallel nodes reset enable_seqscan; alter table tenk2 set (parallel_workers = 0); -explain (analyze, timing off, summary off, costs off) +explain (exec, timing off, summary off, costs off) select count(*) from tenk1, tenk2 where tenk1.hundred > 1 and tenk2.thousand=0; alter table tenk2 reset (parallel_workers); @@ -209,7 +209,7 @@ $$ declare ln text; begin for ln in - explain (analyze, timing off, summary off, costs off) + explain (exec, timing off, summary off, costs off) select * from (select ten from tenk1 where ten < 100 order by ten) ss right join (values (1),(2),(3)) v(x) on true @@ -376,7 +376,7 @@ explain (costs off) -- to increase the parallel query test coverage SAVEPOINT settings; SET LOCAL force_parallel_mode = 1; -EXPLAIN (analyze, timing off, summary off, costs off) SELECT * FROM tenk1; +EXPLAIN (exec, timing off, summary off, costs off) SELECT * FROM tenk1; ROLLBACK TO SAVEPOINT settings; -- provoke error in worker diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql index c6a5776120..6492cd7c37 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -14,7 +14,7 @@ declare first_row bool := true; begin for ln in - execute format('explain analyze %s', $1) + execute format('explain exec %s', $1) loop if first_row then first_row := false; diff --git a/src/test/regress/sql/subselect.sql b/src/test/regress/sql/subselect.sql index 99ca69791e..b1d89228d2 100644 --- a/src/test/regress/sql/subselect.sql +++ b/src/test/regress/sql/subselect.sql @@ -598,8 +598,8 @@ drop function tattle(x int, y int); -- -- Test that LIMIT can be pushed to SORT through a subquery that just projects -- columns. We check for that having happened by looking to see if EXPLAIN --- ANALYZE shows that a top-N sort was used. We must suppress or filter away --- all the non-invariant parts of the EXPLAIN ANALYZE output. +-- EXEC shows that a top-N sort was used. We must suppress or filter away +-- all the non-invariant parts of the EXPLAIN EXEC output. -- create table sq_limit (pk int primary key, c1 int, c2 int); insert into sq_limit values @@ -617,7 +617,7 @@ $$ declare ln text; begin for ln in - explain (analyze, summary off, timing off, costs off) + explain (exec, summary off, timing off, costs off) select * from (select pk,c2 from sq_limit order by c1,pk) as x limit 3 loop ln := regexp_replace(ln, 'Memory: \S*', 'Memory: xxx'); diff --git a/src/test/regress/sql/tidscan.sql b/src/test/regress/sql/tidscan.sql index ef05c09842..65e222681e 100644 --- a/src/test/regress/sql/tidscan.sql +++ b/src/test/regress/sql/tidscan.sql @@ -68,17 +68,17 @@ DECLARE c CURSOR FOR SELECT ctid, * FROM tidscan; FETCH NEXT FROM c; -- skip one row FETCH NEXT FROM c; -- perform update -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; FETCH NEXT FROM c; -- perform update -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; SELECT * FROM tidscan; -- position cursor past any rows FETCH NEXT FROM c; -- should error out -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; ROLLBACK; --------------2.21.0--
v4-0007-Propagate-changes-to-auto_explain.patch (text/x-diff, 3.2K) download From 36c2806daa4fe325dc552e41b30d26ece609fe9f Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Tue, 14 May 2019 22:55:18 -0700 Subject: [PATCH v4 7/8] Propagate changes to auto_explain To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit diff --git a/contrib/auto_explain/auto_explain.c b/contrib/auto_explain/auto_explain.c index edc50f9368..1aeda40ea1 100644 --- a/contrib/auto_explain/auto_explain.c +++ b/contrib/auto_explain/auto_explain.c @@ -23,7 +23,7 @@ PG_MODULE_MAGIC; /* GUC variables */ static int auto_explain_log_min_duration = -1; /* msec or -1 */ -static bool auto_explain_log_analyze = false; +static bool auto_explain_log_exec = false; static bool auto_explain_log_verbose = false; static bool auto_explain_log_buffers = false; static bool auto_explain_log_triggers = false; @@ -102,10 +102,10 @@ _PG_init(void) NULL, NULL); - DefineCustomBoolVariable("auto_explain.log_analyze", - "Use EXPLAIN ANALYZE for plan logging.", + DefineCustomBoolVariable("auto_explain.log_exec", + "Use EXPLAIN EXEC for plan logging.", NULL, - &auto_explain_log_analyze, + &auto_explain_log_exec, false, PGC_SUSET, 0, @@ -148,7 +148,7 @@ _PG_init(void) DefineCustomBoolVariable("auto_explain.log_triggers", "Include trigger statistics in plans.", - "This has no effect unless log_analyze is also set.", + "This has no effect unless log_exec is also set.", &auto_explain_log_triggers, false, PGC_SUSET, @@ -258,8 +258,8 @@ explain_ExecutorStart(QueryDesc *queryDesc, int eflags) if (auto_explain_enabled() && current_query_sampled) { - /* Enable per-node instrumentation iff log_analyze is required. */ - if (auto_explain_log_analyze && (eflags & EXEC_FLAG_EXPLAIN_ONLY) == 0) + /* Enable per-node instrumentation iff log_exec is required. */ + if (auto_explain_log_exec && (eflags & EXEC_FLAG_EXPLAIN_ONLY) == 0) { if (auto_explain_log_timing) queryDesc->instrument_options |= INSTRUMENT_TIMER; @@ -362,18 +362,18 @@ explain_ExecutorEnd(QueryDesc *queryDesc) { ExplainState *es = NewExplainState(); - es->analyze = (queryDesc->instrument_options && auto_explain_log_analyze); + es->exec = (queryDesc->instrument_options && auto_explain_log_exec); es->verbose = auto_explain_log_verbose; - es->buffers = (es->analyze && auto_explain_log_buffers); - es->timing = (es->analyze && auto_explain_log_timing); - es->summary = es->analyze; + es->buffers = (es->exec && auto_explain_log_buffers); + es->timing = (es->exec && auto_explain_log_timing); + es->summary = es->exec; es->format = auto_explain_log_format; es->settings = auto_explain_log_settings; ExplainBeginOutput(es); ExplainQueryText(es, queryDesc); ExplainPrintPlan(es, queryDesc); - if (es->analyze && auto_explain_log_triggers) + if (es->exec && auto_explain_log_triggers) ExplainPrintTriggers(es, queryDesc); if (es->costs) ExplainPrintJITSummary(es, queryDesc); --------------2.21.0--
v4-0008-Mechanical-changes-in-file_fdw-and-postgres_fdw.patch (text/x-diff, 2.4K) download From 17b46b340cd8eb7a0c5df80f2ffc6450701d1c29 Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Tue, 14 May 2019 22:56:29 -0700 Subject: [PATCH v4 8/8] Mechanical changes in file_fdw and postgres_fdw To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c index 85534a3a76..58e88c9957 100644 --- a/contrib/file_fdw/file_fdw.c +++ b/contrib/file_fdw/file_fdw.c @@ -661,7 +661,7 @@ fileBeginForeignScan(ForeignScanState *node, int eflags) FileFdwExecutionState *festate; /* - * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL. + * Do nothing in EXPLAIN (no EXEC) case. node->fdw_state stays NULL. */ if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return; diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 2b6d885efe..7e739f56a9 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -1413,7 +1413,7 @@ postgresBeginForeignScan(ForeignScanState *node, int eflags) int numParams; /* - * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL. + * Do nothing in EXPLAIN (no EXEC) case. node->fdw_state stays NULL. */ if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return; @@ -1804,7 +1804,7 @@ postgresBeginForeignModify(ModifyTableState *mtstate, RangeTblEntry *rte; /* - * Do nothing in EXPLAIN (no ANALYZE) case. resultRelInfo->ri_FdwState + * Do nothing in EXPLAIN (no EXEC) case. resultRelInfo->ri_FdwState * stays NULL. */ if (eflags & EXEC_FLAG_EXPLAIN_ONLY) @@ -2345,7 +2345,7 @@ postgresBeginDirectModify(ForeignScanState *node, int eflags) int numParams; /* - * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL. + * Do nothing in EXPLAIN (no EXEC) case. node->fdw_state stays NULL. */ if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return; @@ -2477,7 +2477,7 @@ postgresIterateDirectModify(ForeignScanState *node) if (dmstate->set_processed) estate->es_processed += dmstate->num_tuples; - /* Increment the tuple count for EXPLAIN ANALYZE if necessary. */ + /* Increment the tuple count for EXPLAIN EXEC if necessary. */ if (instr) instr->tuplecount += dmstate->num_tuples; --------------2.21.0--
^ permalink raw reply [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-15 13:32  Tom Lane <tgl@sss.pgh.pa.us>
  parent: David Fetter <david@fetter.org>
  0 siblings, 2 replies; 49+ messages in thread

From: Tom Lane @ 2019-05-15 13:32 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; +Cc: Stephen Frost <sfrost@snowman.net>; Andres Freund <andres@anarazel.de>; pgsql-hackers

David Fetter <david@fetter.org> writes:
> I hope the patch is a little easier to digest as now attached.

To be blunt, I find 500K worth of changes in the regression test
outputs to be absolutely unacceptable, especially when said changes
are basically worthless from a diagnostic standpoint.  There are
at least two reasons why this won't fly:

* Such a change would be a serious obstacle to back-patching
regression test cases that involve explain output.

* Some buildfarm members use nonstandard settings (notably
force_parallel_mode, but I don't think that's the only one).
We are *not* going to maintain variant output files to try to cope
with all those combinations.  It'd be even more disastrous for
private forks that might have their own affected settings.

I don't know how to make progress towards the original goal
without having a regression-test disaster, but what we have
here is one.

			regards, tom lane





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-15 14:20  David Fetter <david@fetter.org>
  parent: Tom Lane <tgl@sss.pgh.pa.us>
  1 sibling, 1 reply; 49+ messages in thread

From: David Fetter @ 2019-05-15 14:20 UTC (permalink / raw)
  To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Stephen Frost <sfrost@snowman.net>; Andres Freund <andres@anarazel.de>; pgsql-hackers

On Wed, May 15, 2019 at 09:32:31AM -0400, Tom Lane wrote:
> David Fetter <david@fetter.org> writes:
> > I hope the patch is a little easier to digest as now attached.
> 
> To be blunt, I find 500K worth of changes in the regression test
> outputs to be absolutely unacceptable, especially when said changes
> are basically worthless from a diagnostic standpoint.

You're right, of course. The fundamental problem is that our
regression tests depend on (small sets of) fixed strings.  TAP is an
alternative, and could test the structure of the output rather than
what really should be completely inconsequential changes in its form.

> There are
> at least two reasons why this won't fly:
> 
> * Such a change would be a serious obstacle to back-patching
> regression test cases that involve explain output.
> 
> * Some buildfarm members use nonstandard settings (notably
> force_parallel_mode, but I don't think that's the only one).
> We are *not* going to maintain variant output files to try to cope
> with all those combinations.  It'd be even more disastrous for
> private forks that might have their own affected settings.

Indeed. I think we should move our regression tests to TAP and
dispense with this.

> I don't know how to make progress towards the original goal without
> having a regression-test disaster, but what we have here is one.

This just highlights a disaster already in progress. I'm volunteering
to help fix it.

Best,
David.
-- 
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-15 14:29  Andres Freund <andres@anarazel.de>
  parent: David Fetter <david@fetter.org>
  0 siblings, 1 reply; 49+ messages in thread

From: Andres Freund @ 2019-05-15 14:29 UTC (permalink / raw)
  To: pgsql-hackers@lists.postgresql.org,David Fetter <david@fetter.org>; Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Stephen Frost <sfrost@snowman.net>; pgsql-hackers

Hi,

On May 15, 2019 7:20:34 AM PDT, David Fetter <david@fetter.org> wrote:
>On Wed, May 15, 2019 at 09:32:31AM -0400, Tom Lane wrote:
>> David Fetter <david@fetter.org> writes:
>> > I hope the patch is a little easier to digest as now attached.
>> 
>> To be blunt, I find 500K worth of changes in the regression test
>> outputs to be absolutely unacceptable, especially when said changes
>> are basically worthless from a diagnostic standpoint.
>
>You're right, of course. The fundamental problem is that our
>regression tests depend on (small sets of) fixed strings.  TAP is an
>alternative, and could test the structure of the output rather than
>what really should be completely inconsequential changes in its form.
>> There are
>> at least two reasons why this won't fly:
>> 
>> * Such a change would be a serious obstacle to back-patching
>> regression test cases that involve explain output.
>> 
>> * Some buildfarm members use nonstandard settings (notably
>> force_parallel_mode, but I don't think that's the only one).
>> We are *not* going to maintain variant output files to try to cope
>> with all those combinations.  It'd be even more disastrous for
>> private forks that might have their own affected settings.
>
>Indeed. I think we should move our regression tests to TAP and
>dispense with this.

-inconceivably much

The effort to write tap tests over our main tests is much much higher. And they're usually much slower. Of course tap is more powerful, so it's good to have the option.

And it'd be many months if not years worth of work, and would make backpatching much harder.

Andres
-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-15 14:46  Tom Lane <tgl@sss.pgh.pa.us>
  parent: Andres Freund <andres@anarazel.de>
  0 siblings, 1 reply; 49+ messages in thread

From: Tom Lane @ 2019-05-15 14:46 UTC (permalink / raw)
  To: Andres Freund <andres@anarazel.de>; +Cc: pgsql-hackers@lists.postgresql.org, David Fetter <david@fetter.org>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

Andres Freund <andres@anarazel.de> writes:
> On May 15, 2019 7:20:34 AM PDT, David Fetter <david@fetter.org> wrote:
>> Indeed. I think we should move our regression tests to TAP and
>> dispense with this.

> -inconceivably much

Yeah, that's not happening.

Just eyeing the patch again, it seems like most of the test-output churn
is from a decision to make printing of planner options be on-by-default;
which is also what creates the buildfarm-variant-options hazard.  So
I suggest reconsidering that.  TBH, even without the regression test
angle, I suspect that such a change would receive a lot of pushback.
It's a pretty big delta in the verbosity of EXPLAIN, and it is frankly
of no value to a lot of people a lot of the time.

			regards, tom lane





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-15 15:05  Alvaro Herrera <alvherre@2ndquadrant.com>
  parent: David Fetter <david@fetter.org>
  1 sibling, 1 reply; 49+ messages in thread

From: Alvaro Herrera @ 2019-05-15 15:05 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; +Cc: Tom Lane <tgl@sss.pgh.pa.us>; Stephen Frost <sfrost@snowman.net>; Andres Freund <andres@anarazel.de>; pgsql-hackers

On 2019-May-13, David Fetter wrote:

> I tried changing it to EXEC (EXPLAIN EXECUTE is already a thing), but
> got a giant flock of reduce-reduce conflicts along with a few
> shift-reduce conflicts.

After eyeballing the giant patch set you sent[1], I think EXEC is a
horrible keyword to use -- IMO it should either be the complete word
EXECUTE, or we should pick some other word.  I realize that we do not
want to have different sets of keywords when using the legacy syntax (no
parens) vs.  new-style (with parens), but maybe we should just not
support the EXECUTE keyword in the legacy syntax; there's already a
number of options we don't support in the legacy syntax (BUFFERS,
TIMING), so this isn't much of a stretch.

IOW if we want to change ANALYZE to EXECUTE, I propose we change it in
the new-style syntax only and not the legacy one.  So:

EXPLAIN ANALYZE SELECT ...	-- legacy syntax
EXPLAIN (EXECUTE) SELECT ...	-- new-style
EXPLAIN (ANALYZE) SELECT ...	-- we still support ANALYZE as an alias, for compatibility

this should not cause a conflict with EXPLAIN EXECUTE, so these all
should work:

EXPLAIN ANALYZE EXECUTE ...
EXPLAIN (EXECUTE) EXECUTE ...
EXPLAIN (ANALYZE) EXECUTE ...


[1] I think if you just leave out the GUC print from the changes, it
becomes a reasonable patch series.

-- 
Álvaro Herrera                https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-15 16:26  Andres Freund <andres@anarazel.de>
  parent: Alvaro Herrera <alvherre@2ndquadrant.com>
  0 siblings, 1 reply; 49+ messages in thread

From: Andres Freund @ 2019-05-15 16:26 UTC (permalink / raw)
  To: Alvaro Herrera <alvherre@2ndquadrant.com>; +Cc: David Fetter <david@fetter.org>; Tom Lane <tgl@sss.pgh.pa.us>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

Hi,

On 2019-05-15 11:05:31 -0400, Alvaro Herrera wrote:
> After eyeballing the giant patch set you sent[1], I think EXEC is a
> horrible keyword to use -- IMO it should either be the complete word
> EXECUTE, or we should pick some other word.  I realize that we do not
> want to have different sets of keywords when using the legacy syntax (no
> parens) vs.  new-style (with parens), but maybe we should just not
> support the EXECUTE keyword in the legacy syntax; there's already a
> number of options we don't support in the legacy syntax (BUFFERS,
> TIMING), so this isn't much of a stretch.

That seems too confusing.


> [1] I think if you just leave out the GUC print from the changes, it
> becomes a reasonable patch series.

Yea, it really should be small incremental changes instead of proposals
to "just change everything".

Greetings,

Andres Freund





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-15 17:05  Alvaro Herrera <alvherre@2ndquadrant.com>
  parent: Andres Freund <andres@anarazel.de>
  0 siblings, 1 reply; 49+ messages in thread

From: Alvaro Herrera @ 2019-05-15 17:05 UTC (permalink / raw)
  To: Andres Freund <andres@anarazel.de>; +Cc: David Fetter <david@fetter.org>; Tom Lane <tgl@sss.pgh.pa.us>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

Hello,

On 2019-May-15, Andres Freund wrote:
> On 2019-05-15 11:05:31 -0400, Alvaro Herrera wrote:

> > After eyeballing the giant patch set you sent[1], I think EXEC is a
> > horrible keyword to use -- IMO it should either be the complete word
> > EXECUTE, or we should pick some other word.  I realize that we do not
> > want to have different sets of keywords when using the legacy syntax (no
> > parens) vs.  new-style (with parens), but maybe we should just not
> > support the EXECUTE keyword in the legacy syntax; there's already a
> > number of options we don't support in the legacy syntax (BUFFERS,
> > TIMING), so this isn't much of a stretch.
> 
> That seems too confusing.

Ok.  Are you voting for using EXEC as a keyword to replace ANALYZE?

-- 
Álvaro Herrera                https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-15 17:53  Tom Lane <tgl@sss.pgh.pa.us>
  parent: Alvaro Herrera <alvherre@2ndquadrant.com>
  0 siblings, 2 replies; 49+ messages in thread

From: Tom Lane @ 2019-05-15 17:53 UTC (permalink / raw)
  To: Alvaro Herrera <alvherre@2ndquadrant.com>; +Cc: Andres Freund <andres@anarazel.de>; David Fetter <david@fetter.org>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

Alvaro Herrera <alvherre@2ndquadrant.com> writes:
> On 2019-May-15, Andres Freund wrote:
>> On 2019-05-15 11:05:31 -0400, Alvaro Herrera wrote:
>>> After eyeballing the giant patch set you sent[1], I think EXEC is a
>>> horrible keyword to use -- IMO it should either be the complete word
>>> EXECUTE, or we should pick some other word.  I realize that we do not
>>> want to have different sets of keywords when using the legacy syntax (no
>>> parens) vs.  new-style (with parens), but maybe we should just not
>>> support the EXECUTE keyword in the legacy syntax; there's already a
>>> number of options we don't support in the legacy syntax (BUFFERS,
>>> TIMING), so this isn't much of a stretch.

>> That seems too confusing.

> Ok.  Are you voting for using EXEC as a keyword to replace ANALYZE?

FWIW, given the conflict against "EXPLAIN EXECUTE prepared_stmt_name",
we should probably just drop the whole idea.  It seemed like a great
idea at the time, but it's going to confuse people not just Bison.

This is such a fundamental option that it doesn't make sense to not
have it available in the simplified syntax.  It also doesn't make sense
to use different names for it in the simplified and extended syntaxes.
And "EXEC", or other weird spellings, is in the end not an improvement
on "ANALYZE".

So ... never mind that suggestion.  Can we get anywhere with the
rest of it?

			regards, tom lane





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-15 17:58  Andres Freund <andres@anarazel.de>
  parent: Tom Lane <tgl@sss.pgh.pa.us>
  1 sibling, 1 reply; 49+ messages in thread

From: Andres Freund @ 2019-05-15 17:58 UTC (permalink / raw)
  To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Alvaro Herrera <alvherre@2ndquadrant.com>; David Fetter <david@fetter.org>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

Hi,

On 2019-05-15 13:53:26 -0400, Tom Lane wrote:
> FWIW, given the conflict against "EXPLAIN EXECUTE prepared_stmt_name",
> we should probably just drop the whole idea.  It seemed like a great
> idea at the time, but it's going to confuse people not just Bison.

I'm not particularly invested in the idea of renaming ANALYZE - but I
think we might be able to come up with something less ambiguous than
EXECUTE. Even EXECUTION might be better.


> So ... never mind that suggestion.  Can we get anywhere with the
> rest of it?

Yes, please. I still think getting rid of

	if (es->buffers && !es->analyze)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("EXPLAIN option BUFFERS requires ANALYZE")));
and
	/* check that timing is used with EXPLAIN ANALYZE */
	if (es->timing && !es->analyze)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("EXPLAIN option TIMING requires ANALYZE")));

and then changing the default for BUFFERs would be good. I assume they'd
still only apply to query execution.

Althouh, in the case of BUFFERS, I more than once wished we'd track the
plan-time stats for buffers as well. But that's a significantly more
complicated change.

Greetings,

Andres Freund





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-16 06:23  Michael Paquier <michael@paquier.xyz>
  parent: Tom Lane <tgl@sss.pgh.pa.us>
  0 siblings, 0 replies; 49+ messages in thread

From: Michael Paquier @ 2019-05-16 06:23 UTC (permalink / raw)
  To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Andres Freund <andres@anarazel.de>; pgsql-hackers@lists.postgresql.org, David Fetter <david@fetter.org>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

On Wed, May 15, 2019 at 10:46:39AM -0400, Tom Lane wrote:
> Andres Freund <andres@anarazel.de> writes:
>> On May 15, 2019 7:20:34 AM PDT, David Fetter <david@fetter.org> wrote:
>>> Indeed. I think we should move our regression tests to TAP and
>>> dispense with this.
> 
>> -inconceivably much
> 
> Yeah, that's not happening.

+1 to the we-shall-not-move part.
--
Michael

Attachments:

  signature.asc (application/pgp-signature, 832B) download

^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-18 18:39  David Fetter <david@fetter.org>
  parent: Tom Lane <tgl@sss.pgh.pa.us>
  1 sibling, 1 reply; 49+ messages in thread

From: David Fetter @ 2019-05-18 18:39 UTC (permalink / raw)
  To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Stephen Frost <sfrost@snowman.net>; Andres Freund <andres@anarazel.de>; pgsql-hackers

On Wed, May 15, 2019 at 09:32:31AM -0400, Tom Lane wrote:
> David Fetter <david@fetter.org> writes:
> > I hope the patch is a little easier to digest as now attached.
> 
> To be blunt, I find 500K worth of changes in the regression test
> outputs to be absolutely unacceptable, especially when said changes
> are basically worthless from a diagnostic standpoint.  There are at
> least two reasons why this won't fly:

Here's a patch set with a much smaller change.  Will that fly?

Best,
David.
-- 
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate

Attachments: download all (8 files, .tar.gz)

v5-0001-Changed-EXPLAIN-ANALYZE-to-EXPLAIN-EXEC.patch (text/x-diff, 10.6K) download From be95e9296a95eb5e6f19fe4aacd4df4ebc3fe533 Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Sat, 18 May 2019 10:22:33 -0700 Subject: [PATCH v5 1/8] Changed EXPLAIN ANALYZE to EXPLAIN (EXEC) To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index a6c6de78f1..8088926174 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -155,8 +155,8 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, { DefElem *opt = (DefElem *) lfirst(lc); - if (strcmp(opt->defname, "analyze") == 0) - es->analyze = defGetBoolean(opt); + if (strcmp(opt->defname, "exec") == 0) + es->exec = defGetBoolean(opt); else if (strcmp(opt->defname, "verbose") == 0) es->verbose = defGetBoolean(opt); else if (strcmp(opt->defname, "costs") == 0) @@ -202,22 +202,22 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, parser_errposition(pstate, opt->location))); } - if (es->buffers && !es->analyze) + if (es->buffers && !es->exec) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("EXPLAIN option BUFFERS requires ANALYZE"))); + errmsg("EXPLAIN option BUFFERS requires EXEC"))); /* if the timing was not set explicitly, set default value */ - es->timing = (timing_set) ? es->timing : es->analyze; + es->timing = (timing_set) ? es->timing : es->exec; - /* check that timing is used with EXPLAIN ANALYZE */ - if (es->timing && !es->analyze) + /* check that timing is used with EXPLAIN EXEC */ + if (es->timing && !es->exec) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("EXPLAIN option TIMING requires ANALYZE"))); + errmsg("EXPLAIN option TIMING requires EXEC"))); /* if the summary was not set explicitly, set default value */ - es->summary = (summary_set) ? es->summary : es->analyze; + es->summary = (summary_set) ? es->summary : es->exec; /* * Parse analysis was done already, but we still have to run the rule @@ -475,9 +475,9 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, Assert(plannedstmt->commandType != CMD_UTILITY); - if (es->analyze && es->timing) + if (es->exec && es->timing) instrument_option |= INSTRUMENT_TIMER; - else if (es->analyze) + else if (es->exec) instrument_option |= INSTRUMENT_ROWS; if (es->buffers) @@ -512,7 +512,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, dest, params, queryEnv, instrument_option); /* Select execution options */ - if (es->analyze) + if (es->exec) eflags = 0; /* default run-to-completion flags */ else eflags = EXEC_FLAG_EXPLAIN_ONLY; @@ -523,7 +523,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, ExecutorStart(queryDesc, eflags); /* Execute the plan for statistics if asked for */ - if (es->analyze) + if (es->exec) { ScanDirection dir; @@ -556,7 +556,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, } /* Print info about runtime of triggers */ - if (es->analyze) + if (es->exec) ExplainPrintTriggers(es, queryDesc); /* @@ -581,7 +581,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, PopActiveSnapshot(); /* We need a CCI just in case query expanded to multiple plans */ - if (es->analyze) + if (es->exec) CommandCounterIncrement(); totaltime += elapsed_time(&starttime); @@ -592,7 +592,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, * user can set SUMMARY OFF to not have the timing information included in * the output). By default, ANALYZE sets SUMMARY to true. */ - if (es->summary && es->analyze) + if (es->summary && es->exec) ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3, es); @@ -834,7 +834,7 @@ ExplainPrintJIT(ExplainState *es, int jit_flags, "Expressions", jit_flags & PGJIT_EXPR ? "true" : "false", "Deforming", jit_flags & PGJIT_DEFORM ? "true" : "false"); - if (es->analyze && es->timing) + if (es->exec && es->timing) { appendStringInfoSpaces(es->str, es->indent * 2); appendStringInfo(es->str, @@ -860,7 +860,7 @@ ExplainPrintJIT(ExplainState *es, int jit_flags, ExplainPropertyBool("Deforming", jit_flags & PGJIT_DEFORM, es); ExplainCloseGroup("Options", "Options", true, es); - if (es->analyze && es->timing) + if (es->exec && es->timing) { ExplainOpenGroup("Timing", "Timing", true, es); @@ -1505,7 +1505,7 @@ ExplainNode(PlanState *planstate, List *ancestors, if (planstate->instrument) InstrEndLoop(planstate->instrument); - if (es->analyze && + if (es->exec && planstate->instrument && planstate->instrument->nloops > 0) { double nloops = planstate->instrument->nloops; @@ -1537,7 +1537,7 @@ ExplainNode(PlanState *planstate, List *ancestors, ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es); } } - else if (es->analyze) + else if (es->exec) { if (es->format == EXPLAIN_FORMAT_TEXT) appendStringInfoString(es->str, " (never executed)"); @@ -1606,7 +1606,7 @@ ExplainNode(PlanState *planstate, List *ancestors, if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); - if (es->analyze) + if (es->exec) ExplainPropertyFloat("Heap Fetches", NULL, planstate->instrument->ntuples2, 0, es); break; @@ -1624,7 +1624,7 @@ ExplainNode(PlanState *planstate, List *ancestors, if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); - if (es->analyze) + if (es->exec) show_tidbitmap_info((BitmapHeapScanState *) planstate, es); break; case T_SampleScan: @@ -1658,7 +1658,7 @@ ExplainNode(PlanState *planstate, List *ancestors, if (gather->initParam) show_eval_params(gather->initParam, es); - if (es->analyze) + if (es->exec) { int nworkers; @@ -1704,7 +1704,7 @@ ExplainNode(PlanState *planstate, List *ancestors, if (gm->initParam) show_eval_params(gm->initParam, es); - if (es->analyze) + if (es->exec) { int nworkers; @@ -1869,7 +1869,7 @@ ExplainNode(PlanState *planstate, List *ancestors, show_buffer_usage(es, &planstate->instrument->bufusage); /* Show worker detail */ - if (es->analyze && es->verbose && planstate->worker_instrument) + if (es->exec && es->verbose && planstate->worker_instrument) { WorkerInstrumentation *w = planstate->worker_instrument; bool opened_group = false; @@ -2531,12 +2531,12 @@ show_tablesample(TableSampleClause *tsc, PlanState *planstate, } /* - * If it's EXPLAIN ANALYZE, show tuplesort stats for a sort node + * If it's EXPLAIN (EXEC), show tuplesort stats for a sort node */ static void show_sort_info(SortState *sortstate, ExplainState *es) { - if (!es->analyze) + if (!es->exec) return; if (sortstate->sort_Done && sortstate->tuplesortstate != NULL) @@ -2716,7 +2716,7 @@ show_hash_info(HashState *hashstate, ExplainState *es) } /* - * If it's EXPLAIN ANALYZE, show exact/lossy pages for a BitmapHeapScan node + * If it's EXPLAIN (EXEC), show exact/lossy pages for a BitmapHeapScan node */ static void show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es) @@ -2744,7 +2744,7 @@ show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es) } /* - * If it's EXPLAIN ANALYZE, show instrumentation information for a plan node + * If it's EXPLAIN (EXEC), show instrumentation information for a plan node * * "which" identifies which instrumentation counter to print */ @@ -2755,7 +2755,7 @@ show_instrumentation_count(const char *qlabel, int which, double nfiltered; double nloops; - if (!es->analyze || !planstate->instrument) + if (!es->exec || !planstate->instrument) return; if (which == 2) @@ -3283,8 +3283,8 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors, show_instrumentation_count("Rows Removed by Conflict Filter", 1, &mtstate->ps, es); } - /* EXPLAIN ANALYZE display of actual outcome for each tuple proposed */ - if (es->analyze && mtstate->ps.instrument) + /* EXPLAIN (EXEC) display of actual outcome for each tuple proposed */ + if (es->exec && mtstate->ps.instrument) { double total; double insert_path; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 3dc0e8a4fb..06f1cceb37 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10632,8 +10632,9 @@ opt_vacuum_relation_list: /***************************************************************************** * * QUERY: - * EXPLAIN [ANALYZE] [VERBOSE] query * EXPLAIN ( options ) query + * Legacy syntax: + * EXPLAIN [ANALYZE] [VERBOSE] query * *****************************************************************************/ @@ -10645,11 +10646,11 @@ ExplainStmt: n->options = NIL; $$ = (Node *) n; } - | EXPLAIN analyze_keyword opt_verbose ExplainableStmt + | EXPLAIN exec_keyword opt_verbose ExplainableStmt { ExplainStmt *n = makeNode(ExplainStmt); n->query = $4; - n->options = list_make1(makeDefElem("analyze", NULL, @2)); + n->options = list_make1(makeDefElem("exec", NULL, @2)); if ($3) n->options = lappend(n->options, makeDefElem("verbose", NULL, @3)); @@ -10703,7 +10704,7 @@ explain_option_elem: explain_option_name: NonReservedWord { $$ = $1; } - | analyze_keyword { $$ = "analyze"; } + | exec_keyword { $$ = "exec"; } ; explain_option_arg: @@ -10712,6 +10713,11 @@ explain_option_arg: | /* EMPTY */ { $$ = NULL; } ; +exec_keyword: + ANALYZE /* Legacy */ {} + | ANALYSE /* British and legacy */ {} + ; + /***************************************************************************** * * QUERY: diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h index db48f29501..09cc806d7e 100644 --- a/src/include/commands/explain.h +++ b/src/include/commands/explain.h @@ -30,8 +30,8 @@ typedef struct ExplainState StringInfo str; /* output buffer */ /* options */ bool verbose; /* be verbose */ - bool analyze; /* print actual times */ bool costs; /* print estimated costs */ + bool exec; /* actually execute the query, measure it */ bool buffers; /* print buffer usage */ bool timing; /* print detailed node timing */ bool summary; /* print total planning and execution timing */ --------------2.21.0--
v5-0002-Documentation.patch (text/x-diff, 5.6K) download From 8b64bdbc488c7bbc1774485bcd43738339fadb12 Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Sat, 18 May 2019 11:07:14 -0700 Subject: [PATCH v5 2/8] Documentation To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit diff --git a/doc/src/sgml/ref/explain.sgml b/doc/src/sgml/ref/explain.sgml index 385d10411f..d79bddb68e 100644 --- a/doc/src/sgml/ref/explain.sgml +++ b/doc/src/sgml/ref/explain.sgml @@ -32,11 +32,12 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> EXPLAIN [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] <replaceable class="parameter">statement</replaceable> -EXPLAIN [ ANALYZE ] [ VERBOSE ] <replaceable class="parameter">statement</replaceable> +Legacy syntax: +EXPLAIN [ { ANALYZE | ANALYSE } ] [ VERBOSE ] <replaceable class="parameter">statement</replaceable> <phrase>where <replaceable class="parameter">option</replaceable> can be one of:</phrase> - ANALYZE [ <replaceable class="parameter">boolean</replaceable> ] + EXEC [ <replaceable class="parameter">boolean</replaceable> ] VERBOSE [ <replaceable class="parameter">boolean</replaceable> ] COSTS [ <replaceable class="parameter">boolean</replaceable> ] SETTINGS [ <replaceable class="parameter">boolean</replaceable> ] @@ -76,7 +77,7 @@ EXPLAIN [ ANALYZE ] [ VERBOSE ] <replaceable class="parameter">statement</replac </para> <para> - The <literal>ANALYZE</literal> option causes the statement to be actually + The <literal>EXEC</literal> option causes the statement to be actually executed, not only planned. Then actual run time statistics are added to the display, including the total elapsed time expended within each plan node (in milliseconds) and the total number of rows it actually returned. @@ -87,18 +88,18 @@ EXPLAIN [ ANALYZE ] [ VERBOSE ] <replaceable class="parameter">statement</replac <important> <para> Keep in mind that the statement is actually executed when - the <literal>ANALYZE</literal> option is used. Although + the <literal>EXEC</literal> option is used. Although <command>EXPLAIN</command> will discard any output that a <command>SELECT</command> would return, other side effects of the statement will happen as usual. If you wish to use - <command>EXPLAIN ANALYZE</command> on an + <command>EXPLAIN (EXEC)</command> on an <command>INSERT</command>, <command>UPDATE</command>, <command>DELETE</command>, <command>CREATE TABLE AS</command>, or <command>EXECUTE</command> statement without letting the command affect your data, use this approach: <programlisting> BEGIN; -EXPLAIN ANALYZE ...; +EXPLAIN (EXEC) ...; ROLLBACK; </programlisting> </para> @@ -118,7 +119,7 @@ ROLLBACK; <variablelist> <varlistentry> - <term><literal>ANALYZE</literal></term> + <term><literal>EXEC</literal></term> <listitem> <para> Carry out the command and show actual run times and other statistics. @@ -186,7 +187,7 @@ ROLLBACK; The number of blocks shown for an upper-level node includes those used by all its child nodes. In text format, only non-zero values are printed. This parameter may only be - used when <literal>ANALYZE</literal> is also enabled. It defaults to + used when <literal>EXEC</literal> is also enabled. It defaults to <literal>FALSE</literal>. </para> </listitem> @@ -203,7 +204,7 @@ ROLLBACK; not exact times, are needed. Run time of the entire statement is always measured, even when node-level timing is turned off with this option. - This parameter may only be used when <literal>ANALYZE</literal> is also + This parameter may only be used when <literal>EXEC</literal> is also enabled. It defaults to <literal>TRUE</literal>. </para> </listitem> @@ -215,7 +216,7 @@ ROLLBACK; <para> Include summary information (e.g., totaled timing information) after the query plan. Summary information is included by default when - <literal>ANALYZE</literal> is used but otherwise is not included by + <literal>EXEC</literal> is used but otherwise is not included by default, but can be enabled using this option. Planning time in <command>EXPLAIN EXECUTE</command> includes the time required to fetch the plan from the cache and the time required for re-planning, if @@ -295,8 +296,8 @@ ROLLBACK; <para> In order to measure the run-time cost of each node in the execution plan, the current implementation of <command>EXPLAIN - ANALYZE</command> adds profiling overhead to query execution. - As a result, running <command>EXPLAIN ANALYZE</command> + (EXEC)</command> adds profiling overhead to query execution. + As a result, running <command>EXPLAIN (EXEC)</command> on a query can sometimes take significantly longer than executing the query normally. The amount of overhead depends on the nature of the query, as well as the platform being used. The worst case occurs @@ -423,7 +424,7 @@ PREPARE query(int, int) AS SELECT sum(bar) FROM test WHERE id &gt; $1 AND id &lt; $2 GROUP BY foo; -EXPLAIN ANALYZE EXECUTE query(100, 200); +EXPLAIN (EXEC) EXECUTE query(100, 200); QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ --------------2.21.0--
v5-0003-psql-support.patch (text/x-diff, 2.2K) download From 515fe27441266beef21b0d150f1f82c4b60fb4e6 Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Sat, 18 May 2019 11:16:56 -0700 Subject: [PATCH v5 3/8] psql support To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index e4c03de221..4b7fd53135 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -2848,10 +2848,11 @@ psql_completion(const char *text, int start, int end) /* * EXPLAIN [ ( option [, ...] ) ] statement + * Legacy: * EXPLAIN [ ANALYZE ] [ VERBOSE ] statement */ else if (Matches("EXPLAIN")) - COMPLETE_WITH("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", + COMPLETE_WITH("(", "SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE"); else if (HeadMatches("EXPLAIN", "(*") && !HeadMatches("EXPLAIN", "(*)")) @@ -2862,19 +2863,21 @@ psql_completion(const char *text, int start, int end) * one word, so the above test is correct. */ if (ends_with(prev_wd, '(') || ends_with(prev_wd, ',')) - COMPLETE_WITH("ANALYZE", "VERBOSE", "COSTS", "BUFFERS", + COMPLETE_WITH("EXEC", "VERBOSE", "COSTS", "BUFFERS", "TIMING", "SUMMARY", "FORMAT"); - else if (TailMatches("ANALYZE|VERBOSE|COSTS|BUFFERS|TIMING|SUMMARY")) + else if (TailMatches("EXEC|VERBOSE|COSTS|BUFFERS|TIMING|SUMMARY")) COMPLETE_WITH("ON", "OFF"); else if (TailMatches("FORMAT")) COMPLETE_WITH("TEXT", "XML", "JSON", "YAML"); } - else if (Matches("EXPLAIN", "ANALYZE")) + else if (Matches("EXPLAIN", "ANALYZE") || + Matches("EXPLAIN", "ANALYSE")) COMPLETE_WITH("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE"); else if (Matches("EXPLAIN", "(*)") || Matches("EXPLAIN", "VERBOSE") || - Matches("EXPLAIN", "ANALYZE", "VERBOSE")) + Matches("EXPLAIN", "ANALYZE", "VERBOSE") || + Matches("EXPLAIN", "ANALYSE", "VERBOSE")) COMPLETE_WITH("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE"); /* FETCH && MOVE */ --------------2.21.0--
v5-0004-Examples-in-the-documentation-now-use-EXEC.patch (text/x-diff, 30.3K) download From 5706042a7fb66d244077b3b0d8bfa9cf2d7f4e3b Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Tue, 14 May 2019 22:51:24 -0700 Subject: [PATCH v5 4/8] Examples in the documentation now use EXEC To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit diff --git a/doc/src/sgml/auto-explain.sgml b/doc/src/sgml/auto-explain.sgml index 3d619d4a3d..3025a57232 100644 --- a/doc/src/sgml/auto-explain.sgml +++ b/doc/src/sgml/auto-explain.sgml @@ -65,14 +65,14 @@ LOAD 'auto_explain'; <varlistentry> <term> - <varname>auto_explain.log_analyze</varname> (<type>boolean</type>) + <varname>auto_explain.log_exec</varname> (<type>boolean</type>) <indexterm> - <primary><varname>auto_explain.log_analyze</varname> configuration parameter</primary> + <primary><varname>auto_explain.log_exec</varname> configuration parameter</primary> </indexterm> </term> <listitem> <para> - <varname>auto_explain.log_analyze</varname> causes <command>EXPLAIN ANALYZE</command> + <varname>auto_explain.log_exec</varname> causes <command>EXPLAIN EXEC</command> output, rather than just <command>EXPLAIN</command> output, to be printed when an execution plan is logged. This parameter is off by default. Only superusers can change this setting. @@ -102,7 +102,7 @@ LOAD 'auto_explain'; usage statistics are printed when an execution plan is logged; it's equivalent to the <literal>BUFFERS</literal> option of <command>EXPLAIN</command>. This parameter has no effect - unless <varname>auto_explain.log_analyze</varname> is enabled. + unless <varname>auto_explain.log_exec</varname> is enabled. This parameter is off by default. Only superusers can change this setting. </para> @@ -126,7 +126,7 @@ LOAD 'auto_explain'; parameter to off when only actual row counts, and not exact times, are needed. This parameter has no effect - unless <varname>auto_explain.log_analyze</varname> is enabled. + unless <varname>auto_explain.log_exec</varname> is enabled. This parameter is on by default. Only superusers can change this setting. </para> @@ -145,7 +145,7 @@ LOAD 'auto_explain'; <varname>auto_explain.log_triggers</varname> causes trigger execution statistics to be included when an execution plan is logged. This parameter has no effect - unless <varname>auto_explain.log_analyze</varname> is enabled. + unless <varname>auto_explain.log_exec</varname> is enabled. This parameter is off by default. Only superusers can change this setting. </para> @@ -283,7 +283,7 @@ auto_explain.log_min_duration = '3s' <programlisting> postgres=# LOAD 'auto_explain'; postgres=# SET auto_explain.log_min_duration = 0; -postgres=# SET auto_explain.log_analyze = true; +postgres=# SET auto_explain.log_exec = true; postgres=# SELECT count(*) FROM pg_class, pg_index WHERE oid = indrelid AND indisunique; diff --git a/doc/src/sgml/bloom.sgml b/doc/src/sgml/bloom.sgml index 6eeaddee09..5b4ede2db1 100644 --- a/doc/src/sgml/bloom.sgml +++ b/doc/src/sgml/bloom.sgml @@ -129,7 +129,7 @@ CREATE INDEX <para> A sequential scan over this large table takes a long time: <programlisting> -=# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; +=# EXPLAIN EXEC SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; QUERY PLAN ------------------------------------------------------------------------------------------------------------ Seq Scan on tbloom (cost=0.00..213694.08 rows=1 width=24) (actual time=1445.438..1445.438 rows=0 loops=1) @@ -145,7 +145,7 @@ CREATE INDEX So the planner will usually select an index scan if possible. With a btree index, we get results like this: <programlisting> -=# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; +=# EXPLAIN EXEC SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- Index Only Scan using btreeidx on tbloom (cost=0.56..298311.96 rows=1 width=24) (actual time=445.709..445.709 rows=0 loops=1) @@ -160,7 +160,7 @@ CREATE INDEX <para> Bloom is better than btree in handling this type of search: <programlisting> -=# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; +=# EXPLAIN EXEC SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------- Bitmap Heap Scan on tbloom (cost=178435.39..178439.41 rows=1 width=24) (actual time=76.698..76.698 rows=0 loops=1) @@ -187,7 +187,7 @@ CREATE INDEX A better strategy for btree is to create a separate index on each column. Then the planner will choose something like this: <programlisting> -=# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; +=# EXPLAIN EXEC SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------ Bitmap Heap Scan on tbloom (cost=9.29..13.30 rows=1 width=24) (actual time=0.148..0.148 rows=0 loops=1) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 84341a30e5..41e9a64182 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -6441,7 +6441,7 @@ log_line_prefix = '%m [%p] %q%u@%d/%a ' <command>UPDATE</command>, <command>DELETE</command>, <command>TRUNCATE</command>, and <command>COPY FROM</command>. <command>PREPARE</command>, <command>EXECUTE</command>, and - <command>EXPLAIN ANALYZE</command> statements are also logged if their + <command>EXPLAIN EXEC</command> statements are also logged if their contained command is of an appropriate type. For clients using extended query protocol, logging occurs when an Execute message is received, and values of the Bind parameters are included diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index a0a7435a03..407f94dfbe 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -4498,7 +4498,7 @@ EXPLAIN SELECT count(*) FROM measurement WHERE logdate &gt;= DATE '2008-01-01'; performed here for parameter values which are known during the initialization phase of execution. Partitions which are pruned during this stage will not show up in the query's - <command>EXPLAIN</command> or <command>EXPLAIN ANALYZE</command>. + <command>EXPLAIN</command> or <command>EXPLAIN EXEC</command>. It is possible to determine the number of partitions which were removed during this phase by observing the <quote>Subplans Removed</quote> property in the @@ -4518,7 +4518,7 @@ EXPLAIN SELECT count(*) FROM measurement WHERE logdate &gt;= DATE '2008-01-01'; execution parameters being used by partition pruning changes. Determining if partitions were pruned during this phase requires careful inspection of the <literal>loops</literal> property in - the <command>EXPLAIN ANALYZE</command> output. Subplans + the <command>EXPLAIN EXEC</command> output. Subplans corresponding to different partitions may have different values for it depending on how many times each of them was pruned during execution. Some may be shown as <literal>(never executed)</literal> diff --git a/doc/src/sgml/fdwhandler.sgml b/doc/src/sgml/fdwhandler.sgml index 27b94fb611..0f1e80b3b9 100644 --- a/doc/src/sgml/fdwhandler.sgml +++ b/doc/src/sgml/fdwhandler.sgml @@ -937,7 +937,7 @@ IterateDirectModify(ForeignScanState *node); Whether the query has the clause or not, the query's reported row count must be incremented by the FDW itself. When the query doesn't have the clause, the FDW must also increment the row count for the - <structname>ForeignScanState</structname> node in the <command>EXPLAIN ANALYZE</command> + <structname>ForeignScanState</structname> node in the <command>EXPLAIN EXEC</command> case. </para> @@ -1123,7 +1123,7 @@ ExplainForeignScan(ForeignScanState *node, The flag fields in <literal>es</literal> can be used to determine what to print, and the state of the <structname>ForeignScanState</structname> node can be inspected to provide run-time statistics in the <command>EXPLAIN - ANALYZE</command> case. + EXEC</command> case. </para> <para> @@ -1148,7 +1148,7 @@ ExplainForeignModify(ModifyTableState *mtstate, The flag fields in <literal>es</literal> can be used to determine what to print, and the state of the <structname>ModifyTableState</structname> node can be inspected to provide run-time statistics in the <command>EXPLAIN - ANALYZE</command> case. The first four arguments are the same as for + EXEC</command> case. The first four arguments are the same as for <function>BeginForeignModify</function>. </para> @@ -1172,7 +1172,7 @@ ExplainDirectModify(ForeignScanState *node, The flag fields in <literal>es</literal> can be used to determine what to print, and the state of the <structname>ForeignScanState</structname> node can be inspected to provide run-time statistics in the <command>EXPLAIN - ANALYZE</command> case. + EXEC</command> case. </para> <para> diff --git a/doc/src/sgml/indices.sgml b/doc/src/sgml/indices.sgml index 95c0a1926c..decaaa6209 100644 --- a/doc/src/sgml/indices.sgml +++ b/doc/src/sgml/indices.sgml @@ -1498,7 +1498,7 @@ CREATE INDEX test1c_content_y_index ON test1c (content COLLATE "y"); possibilities: Either the system is right and using the index is indeed not appropriate, or the cost estimates of the query plans are not reflecting reality. So you should time your query with - and without indexes. The <command>EXPLAIN ANALYZE</command> + and without indexes. The <command>EXPLAIN EXEC</command> command can be useful here. </para> </listitem> diff --git a/doc/src/sgml/jit.sgml b/doc/src/sgml/jit.sgml index a21a07ef71..cb288d8b73 100644 --- a/doc/src/sgml/jit.sgml +++ b/doc/src/sgml/jit.sgml @@ -145,7 +145,7 @@ <acronym>JIT</acronym> is used or not. As an example, here is a query that is not using <acronym>JIT</acronym>: <screen> -=# EXPLAIN ANALYZE SELECT SUM(relpages) FROM pg_class; +=# EXPLAIN EXEC SELECT SUM(relpages) FROM pg_class; QUERY PLAN ------------------------------------------------------------------------------------------------------------- Aggregate (cost=16.27..16.29 rows=1 width=8) (actual time=0.303..0.303 rows=1 loops=1) @@ -161,7 +161,7 @@ <screen> =# SET jit_above_cost = 10; SET -=# EXPLAIN ANALYZE SELECT SUM(relpages) FROM pg_class; +=# EXPLAIN EXEC SELECT SUM(relpages) FROM pg_class; QUERY PLAN ------------------------------------------------------------------------------------------------------------- Aggregate (cost=16.27..16.29 rows=1 width=8) (actual time=6.049..6.049 rows=1 loops=1) diff --git a/doc/src/sgml/parallel.sgml b/doc/src/sgml/parallel.sgml index af5d48a5c7..b3e2285f05 100644 --- a/doc/src/sgml/parallel.sgml +++ b/doc/src/sgml/parallel.sgml @@ -442,7 +442,7 @@ EXPLAIN SELECT * FROM pgbench_accounts WHERE filler LIKE '%x%'; </para> <para> - When executing a parallel plan, you can use <literal>EXPLAIN (ANALYZE, + When executing a parallel plan, you can use <literal>EXPLAIN (EXEC, VERBOSE)</literal> to display per-worker statistics for each plan node. This may be useful in determining whether the work is being evenly distributed between all plan nodes and more generally in understanding the diff --git a/doc/src/sgml/perform.sgml b/doc/src/sgml/perform.sgml index a84be85159..3a890c5a71 100644 --- a/doc/src/sgml/perform.sgml +++ b/doc/src/sgml/perform.sgml @@ -533,25 +533,25 @@ WHERE t1.unique1 &lt; 100 AND t1.unique2 = t2.unique2; which shows that the planner thinks that sorting <literal>onek</literal> by index-scanning is about 12% more expensive than sequential-scan-and-sort. Of course, the next question is whether it's right about that. - We can investigate that using <command>EXPLAIN ANALYZE</command>, as discussed + We can investigate that using <command>EXPLAIN EXEC</command>, as discussed below. </para> </sect2> - <sect2 id="using-explain-analyze"> - <title><command>EXPLAIN ANALYZE</command></title> + <sect2 id="using-explain-exec"> + <title><command>EXPLAIN EXEC</command></title> <para> It is possible to check the accuracy of the planner's estimates - by using <command>EXPLAIN</command>'s <literal>ANALYZE</literal> option. With this + by using <command>EXPLAIN</command>'s <literal>EXEC</literal> option. With this option, <command>EXPLAIN</command> actually executes the query, and then displays the true row counts and true run time accumulated within each plan node, along with the same estimates that a plain <command>EXPLAIN</command> shows. For example, we might get a result like this: <screen> -EXPLAIN ANALYZE SELECT * +EXPLAIN EXEC SELECT * FROM tenk1 t1, tenk2 t2 WHERE t1.unique1 &lt; 10 AND t1.unique2 = t2.unique2; @@ -590,12 +590,12 @@ WHERE t1.unique1 &lt; 10 AND t1.unique2 = t2.unique2; </para> <para> - In some cases <command>EXPLAIN ANALYZE</command> shows additional execution + In some cases <command>EXPLAIN EXEC</command> shows additional execution statistics beyond the plan node execution times and row counts. For example, Sort and Hash nodes provide extra information: <screen> -EXPLAIN ANALYZE SELECT * +EXPLAIN EXEC SELECT * FROM tenk1 t1, tenk2 t2 WHERE t1.unique1 &lt; 100 AND t1.unique2 = t2.unique2 ORDER BY t1.fivethous; @@ -630,7 +630,7 @@ WHERE t1.unique1 &lt; 100 AND t1.unique2 = t2.unique2 ORDER BY t1.fivethous; filter condition: <screen> -EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE ten &lt; 7; +EXPLAIN EXEC SELECT * FROM tenk1 WHERE ten &lt; 7; QUERY PLAN --------------------------------------------------------------------------------------------------------- @@ -653,7 +653,7 @@ EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE ten &lt; 7; specific point: <screen> -EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; +EXPLAIN EXEC SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; QUERY PLAN ------------------------------------------------------------------------------------------------------ @@ -672,7 +672,7 @@ EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; <screen> SET enable_seqscan TO off; -EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; +EXPLAIN EXEC SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- @@ -695,7 +695,7 @@ EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; <literal>ANALYZE</literal> to get even more run time statistics: <screen> -EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000; +EXPLAIN (EXEC, BUFFERS) SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- @@ -719,7 +719,7 @@ EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique </para> <para> - Keep in mind that because <command>EXPLAIN ANALYZE</command> actually + Keep in mind that because <command>EXPLAIN EXEC</command> actually runs the query, any side-effects will happen as usual, even though whatever results the query might output are discarded in favor of printing the <command>EXPLAIN</command> data. If you want to analyze a @@ -729,7 +729,7 @@ EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique <screen> BEGIN; -EXPLAIN ANALYZE UPDATE tenk1 SET hundred = hundred + 1 WHERE unique1 &lt; 100; +EXPLAIN EXEC UPDATE tenk1 SET hundred = hundred + 1 WHERE unique1 &lt; 100; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- @@ -795,13 +795,13 @@ EXPLAIN UPDATE parent SET f2 = f2 + 1 WHERE f1 = 101; <para> The <literal>Planning time</literal> shown by <command>EXPLAIN - ANALYZE</command> is the time it took to generate the query plan from the + EXEC</command> is the time it took to generate the query plan from the parsed query and optimize it. It does not include parsing or rewriting. </para> <para> The <literal>Execution time</literal> shown by <command>EXPLAIN - ANALYZE</command> includes executor start-up and shut-down time, as well + EXEC</command> includes executor start-up and shut-down time, as well as the time to run any triggers that are fired, but it does not include parsing, rewriting, or planning time. Time spent executing <literal>BEFORE</literal> triggers, if any, is included in @@ -812,7 +812,7 @@ EXPLAIN UPDATE parent SET f2 = f2 + 1 WHERE f1 = 101; (either <literal>BEFORE</literal> or <literal>AFTER</literal>) is also shown separately. Note that deferred constraint triggers will not be executed until end of transaction and are thus not considered at all by - <command>EXPLAIN ANALYZE</command>. + <command>EXPLAIN EXEC</command>. </para> </sect2> @@ -822,11 +822,11 @@ EXPLAIN UPDATE parent SET f2 = f2 + 1 WHERE f1 = 101; <para> There are two significant ways in which run times measured by - <command>EXPLAIN ANALYZE</command> can deviate from normal execution of + <command>EXPLAIN EXEC</command> can deviate from normal execution of the same query. First, since no output rows are delivered to the client, network transmission costs and I/O conversion costs are not included. Second, the measurement overhead added by <command>EXPLAIN - ANALYZE</command> can be significant, especially on machines with slow + EXEC</command> can be significant, especially on machines with slow <function>gettimeofday()</function> operating-system calls. You can use the <xref linkend="pgtesttiming"/> tool to measure the overhead of timing on your system. @@ -853,7 +853,7 @@ EXPLAIN UPDATE parent SET f2 = f2 + 1 WHERE f1 = 101; effect. For example, in the <literal>LIMIT</literal> query we used before, <screen> -EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000 LIMIT 2; +EXPLAIN EXEC SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000 LIMIT 2; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- @@ -883,7 +883,7 @@ EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000 of one child, with results like those mentioned for <literal>LIMIT</literal>. Also, if the outer (first) child contains rows with duplicate key values, the inner (second) child is backed up and rescanned for the portion of its - rows matching that key value. <command>EXPLAIN ANALYZE</command> counts these + rows matching that key value. <command>EXPLAIN EXEC</command> counts these repeated emissions of the same inner rows as if they were real additional rows. When there are many outer duplicates, the reported actual row count for the inner child plan node can be significantly larger than the number diff --git a/doc/src/sgml/planstats.sgml b/doc/src/sgml/planstats.sgml index 4b1d3f4952..3a4405c850 100644 --- a/doc/src/sgml/planstats.sgml +++ b/doc/src/sgml/planstats.sgml @@ -489,7 +489,7 @@ SELECT relpages, reltuples FROM pg_class WHERE relname = 't'; condition on the <structfield>a</structfield> column: <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a = 1; QUERY PLAN ------------------------------------------------------------------------------- Seq Scan on t (cost=0.00..170.00 rows=100 width=8) (actual rows=100 loops=1) @@ -506,7 +506,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1; condition on both columns, combining them with <literal>AND</literal>: <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; QUERY PLAN ----------------------------------------------------------------------------- Seq Scan on t (cost=0.00..195.00 rows=1 width=8) (actual rows=100 loops=1) @@ -530,7 +530,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; <programlisting> CREATE STATISTICS stts (dependencies) ON a, b FROM t; ANALYZE t; -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; QUERY PLAN ------------------------------------------------------------------------------- Seq Scan on t (cost=0.00..195.00 rows=100 width=8) (actual rows=100 loops=1) @@ -551,7 +551,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; estimated number of rows returned by the HashAggregate node) is very accurate: <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a; +EXPLAIN (EXEC, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a; QUERY PLAN ----------------------------------------------------------------------------------------- HashAggregate (cost=195.00..196.00 rows=100 width=12) (actual rows=100 loops=1) @@ -562,7 +562,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a; groups in a query with two columns in <command>GROUP BY</command>, as in the following example, is off by an order of magnitude: <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; +EXPLAIN (EXEC, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; QUERY PLAN -------------------------------------------------------------------------------------------- HashAggregate (cost=220.00..230.00 rows=1000 width=16) (actual rows=100 loops=1) @@ -575,7 +575,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; DROP STATISTICS stts; CREATE STATISTICS stts (dependencies, ndistinct) ON a, b FROM t; ANALYZE t; -EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; +EXPLAIN (EXEC, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; QUERY PLAN -------------------------------------------------------------------------------------------- HashAggregate (cost=220.00..221.00 rows=100 width=16) (actual rows=100 loops=1) @@ -615,7 +615,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b; DROP STATISTICS stts; CREATE STATISTICS stts2 (mcv) ON a, b FROM t; ANALYZE t; -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1; QUERY PLAN ------------------------------------------------------------------------------- Seq Scan on t (cost=0.00..195.00 rows=100 width=8) (actual rows=100 loops=1) @@ -672,7 +672,7 @@ SELECT m.* FROM pg_statistic_ext, to decide which combinations are compatible. <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 10; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 10; QUERY PLAN --------------------------------------------------------------------------- Seq Scan on t (cost=0.00..195.00 rows=1 width=8) (actual rows=0 loops=1) @@ -685,7 +685,7 @@ EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 10; example range query, presented earlier: <programlisting> -EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a &lt;= 49 AND b &gt; 49; +EXPLAIN (EXEC, TIMING OFF) SELECT * FROM t WHERE a &lt;= 49 AND b &gt; 49; QUERY PLAN --------------------------------------------------------------------------- Seq Scan on t (cost=0.00..195.00 rows=1 width=8) (actual rows=0 loops=1) diff --git a/doc/src/sgml/ref/create_statistics.sgml b/doc/src/sgml/ref/create_statistics.sgml index ae1d8024a4..18ca19fa8f 100644 --- a/doc/src/sgml/ref/create_statistics.sgml +++ b/doc/src/sgml/ref/create_statistics.sgml @@ -147,14 +147,14 @@ INSERT INTO t1 SELECT i/100, i/500 ANALYZE t1; -- the number of matching rows will be drastically underestimated: -EXPLAIN ANALYZE SELECT * FROM t1 WHERE (a = 1) AND (b = 0); +EXPLAIN EXEC SELECT * FROM t1 WHERE (a = 1) AND (b = 0); CREATE STATISTICS s1 (dependencies) ON a, b FROM t1; ANALYZE t1; -- now the row count estimate is more accurate: -EXPLAIN ANALYZE SELECT * FROM t1 WHERE (a = 1) AND (b = 0); +EXPLAIN EXEC SELECT * FROM t1 WHERE (a = 1) AND (b = 0); </programlisting> Without functional-dependency statistics, the planner would assume @@ -183,10 +183,10 @@ CREATE STATISTICS s2 (mcv) ON (a, b) FROM t2; ANALYZE t2; -- valid combination (found in MCV) -EXPLAIN ANALYZE SELECT * FROM t2 WHERE (a = 1) AND (b = 1); +EXPLAIN EXEC SELECT * FROM t2 WHERE (a = 1) AND (b = 1); -- invalid combination (not found in MCV) -EXPLAIN ANALYZE SELECT * FROM t2 WHERE (a = 1) AND (b = 2); +EXPLAIN EXEC SELECT * FROM t2 WHERE (a = 1) AND (b = 2); </programlisting> The MCV list gives the planner more detailed information about the diff --git a/doc/src/sgml/ref/pgtesttiming.sgml b/doc/src/sgml/ref/pgtesttiming.sgml index 545a934cf8..4470435dd2 100644 --- a/doc/src/sgml/ref/pgtesttiming.sgml +++ b/doc/src/sgml/ref/pgtesttiming.sgml @@ -30,7 +30,7 @@ <application>pg_test_timing</application> is a tool to measure the timing overhead on your system and confirm that the system time never moves backwards. Systems that are slow to collect timing data can give less accurate - <command>EXPLAIN ANALYZE</command> results. + <command>EXPLAIN EXEC</command> results. </para> </refsect1> @@ -120,7 +120,7 @@ Histogram of timing durations: <para> When the query executor is running a statement using - <command>EXPLAIN ANALYZE</command>, individual operations are timed as well + <command>EXPLAIN EXEC</command>, individual operations are timed as well as showing a summary. The overhead of your system can be checked by counting rows with the <application>psql</application> program: @@ -128,13 +128,13 @@ Histogram of timing durations: CREATE TABLE t AS SELECT * FROM generate_series(1,100000); \timing SELECT COUNT(*) FROM t; -EXPLAIN ANALYZE SELECT COUNT(*) FROM t; +EXPLAIN EXEC SELECT COUNT(*) FROM t; </screen> </para> <para> The i7-860 system measured runs the count query in 9.8 ms while - the <command>EXPLAIN ANALYZE</command> version takes 16.6 ms, each + the <command>EXPLAIN EXEC</command> version takes 16.6 ms, each processing just over 100,000 rows. That 6.8 ms difference means the timing overhead per row is 68 ns, about twice what pg_test_timing estimated it would be. Even that relatively small amount of overhead is making the fully @@ -169,12 +169,12 @@ Histogram of timing durations: </para> <para> - In this configuration, the sample <command>EXPLAIN ANALYZE</command> above + In this configuration, the sample <command>EXPLAIN EXEC</command> above takes 115.9 ms. That's 1061 ns of timing overhead, again a small multiple of what's measured directly by this utility. That much timing overhead means the actual query itself is only taking a tiny fraction of the accounted for time, most of it is being consumed in overhead instead. In - this configuration, any <command>EXPLAIN ANALYZE</command> totals involving + this configuration, any <command>EXPLAIN EXEC</command> totals involving many timed operations would be inflated significantly by timing overhead. </para> diff --git a/doc/src/sgml/ref/set_transaction.sgml b/doc/src/sgml/ref/set_transaction.sgml index 43b1c6c892..cef790ecd7 100644 --- a/doc/src/sgml/ref/set_transaction.sgml +++ b/doc/src/sgml/ref/set_transaction.sgml @@ -133,7 +133,7 @@ SET SESSION CHARACTERISTICS AS TRANSACTION <replaceable class="parameter">transa <literal>CREATE</literal>, <literal>ALTER</literal>, and <literal>DROP</literal> commands; <literal>COMMENT</literal>, <literal>GRANT</literal>, <literal>REVOKE</literal>, - <literal>TRUNCATE</literal>; and <literal>EXPLAIN ANALYZE</literal> + <literal>TRUNCATE</literal>; and <literal>EXPLAIN EXEC</literal> and <literal>EXECUTE</literal> if the command they would execute is among those listed. This is a high-level notion of read-only that does not prevent all writes to disk. diff --git a/doc/src/sgml/rules.sgml b/doc/src/sgml/rules.sgml index 4e20664ea1..499e6fcced 100644 --- a/doc/src/sgml/rules.sgml +++ b/doc/src/sgml/rules.sgml @@ -1030,7 +1030,7 @@ SELECT count(*) FROM words WHERE word = 'caterpiler'; (1 row) </programlisting> - With <command>EXPLAIN ANALYZE</command>, we see: + With <command>EXPLAIN EXEC</command>, we see: <programlisting> Aggregate (cost=21763.99..21764.00 rows=1 width=0) (actual time=188.180..188.181 rows=1 loops=1) --------------2.21.0--
v5-0005-Code-comments-now-use-EXPLAIN-EXEC.patch (text/x-diff, 8.6K) download From 1decc12fc4b5470115292638f011542e522ec516 Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Tue, 14 May 2019 22:53:19 -0700 Subject: [PATCH v5 5/8] Code comments now use EXPLAIN (EXEC) To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 2beb378145..8c4320df58 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -2365,7 +2365,7 @@ FindTriggerIncompatibleWithInheritance(TriggerDesc *trigdesc) * trigdata: trigger descriptor. * tgindx: trigger's index in finfo and instr arrays. * finfo: array of cached trigger function call information. - * instr: optional array of EXPLAIN ANALYZE instrumentation state. + * instr: optional array of EXPLAIN EXEC instrumentation state. * per_tuple_context: memory context to execute the function in. * * Returns the tuple (or NULL) as returned by the function. @@ -2406,7 +2406,7 @@ ExecCallTriggerFunc(TriggerData *trigdata, Assert(finfo->fn_oid == trigdata->tg_trigger->tgfoid); /* - * If doing EXPLAIN ANALYZE, start charging time to this trigger. + * If doing EXPLAIN EXEC, start charging time to this trigger. */ if (instr) InstrStartNode(instr + tgindx); @@ -2455,7 +2455,7 @@ ExecCallTriggerFunc(TriggerData *trigdata, fcinfo->flinfo->fn_oid))); /* - * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count + * If doing EXPLAIN EXEC, stop charging time to this trigger, and count * one "tuple returned" (really the number of firings). */ if (instr) @@ -4171,7 +4171,7 @@ afterTriggerDeleteHeadEventChunk(AfterTriggersQueryData *qs) * rel: open relation for event. * trigdesc: working copy of rel's trigger info. * finfo: array of fmgr lookup cache entries (one per trigger in trigdesc). - * instr: array of EXPLAIN ANALYZE instrumentation nodes (one per trigger), + * instr: array of EXPLAIN EXEC instrumentation nodes (one per trigger), * or NULL if no instrumentation is wanted. * per_tuple_context: memory context to call trigger function in. * trig_tuple_slot1: scratch slot for tg_trigtuple (foreign tables only) @@ -4216,7 +4216,7 @@ AfterTriggerExecute(EState *estate, elog(ERROR, "could not find trigger %u", tgoid); /* - * If doing EXPLAIN ANALYZE, start charging time to this trigger. We want + * If doing EXPLAIN EXEC, start charging time to this trigger. We want * to include time spent re-fetching tuples in the trigger cost. */ if (instr) @@ -4359,7 +4359,7 @@ AfterTriggerExecute(EState *estate, ExecClearTuple(LocTriggerData.tg_newslot); /* - * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count + * If doing EXPLAIN EXEC, stop charging time to this trigger, and count * one "tuple returned" (really the number of firings). */ if (instr) diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index ed7c0606bf..cbbc7e087b 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -390,7 +390,7 @@ standard_ExecutorRun(QueryDesc *queryDesc, * * This routine must be called after the last ExecutorRun call. * It performs cleanup such as firing AFTER triggers. It is - * separate from ExecutorEnd because EXPLAIN ANALYZE needs to + * separate from ExecutorEnd because EXPLAIN EXEC needs to * include these actions in the total runtime. * * We provide a function hook variable that lets loadable plugins @@ -1365,7 +1365,7 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo, * on other relations, which will be processed in the context of the outer * query. For efficiency's sake, we want to have a ResultRelInfo for those * triggers too; that can avoid repeated re-opening of the relation. (It - * also provides a way for EXPLAIN ANALYZE to report the runtimes of such + * also provides a way for EXPLAIN EXEC to report the runtimes of such * triggers.) So we make additional ResultRelInfo's as needed, and save them * in es_trig_target_relations. */ diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index 3d4b01cb4d..adcccbbdcb 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -273,11 +273,11 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e) e->pcxt); break; case T_HashState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecHashEstimate((HashState *) planstate, e->pcxt); break; case T_SortState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecSortEstimate((SortState *) planstate, e->pcxt); break; @@ -486,11 +486,11 @@ ExecParallelInitializeDSM(PlanState *planstate, d->pcxt); break; case T_HashState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecHashInitializeDSM((HashState *) planstate, d->pcxt); break; case T_SortState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecSortInitializeDSM((SortState *) planstate, d->pcxt); break; @@ -1294,11 +1294,11 @@ ExecParallelInitializeWorker(PlanState *planstate, ParallelWorkerContext *pwcxt) pwcxt); break; case T_HashState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecHashInitializeWorker((HashState *) planstate, pwcxt); break; case T_SortState: - /* even when not parallel-aware, for EXPLAIN ANALYZE */ + /* even when not parallel-aware, for EXPLAIN EXEC */ ExecSortInitializeWorker((SortState *) planstate, pwcxt); break; diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index 64eec91f8b..c6a2906db5 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -193,7 +193,7 @@ MultiExecPrivateHash(HashState *node) if (hashtable->nbuckets != hashtable->nbuckets_optimal) ExecHashIncreaseNumBuckets(hashtable); - /* Account for the buckets in spaceUsed (reported in EXPLAIN ANALYZE) */ + /* Account for the buckets in spaceUsed (reported in EXPLAIN EXEC) */ hashtable->spaceUsed += hashtable->nbuckets * sizeof(HashJoinTuple); if (hashtable->spaceUsed > hashtable->spacePeak) hashtable->spacePeak = hashtable->spaceUsed; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 92d0507949..cd5e834ae9 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -3215,19 +3215,19 @@ GetCommandLogLevel(Node *parsetree) case T_ExplainStmt: { ExplainStmt *stmt = (ExplainStmt *) parsetree; - bool analyze = false; + bool exec = false; ListCell *lc; - /* Look through an EXPLAIN ANALYZE to the contained stmt */ + /* Look through an EXPLAIN EXEC to the contained stmt */ foreach(lc, stmt->options) { DefElem *opt = (DefElem *) lfirst(lc); - if (strcmp(opt->defname, "analyze") == 0) - analyze = defGetBoolean(opt); + if (strcmp(opt->defname, "exec") == 0) + exec = defGetBoolean(opt); /* don't "break", as explain.c will use the last value */ } - if (analyze) + if (exec) return GetCommandLogLevel(stmt->query); /* Plain EXPLAIN isn't so interesting */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index eb4c8b5e79..72730fcfaf 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -52,7 +52,7 @@ * mean that the plan can't queue any AFTER triggers; just that the caller * is responsible for there being a trigger context for them to be queued in. */ -#define EXEC_FLAG_EXPLAIN_ONLY 0x0001 /* EXPLAIN, no ANALYZE */ +#define EXEC_FLAG_EXPLAIN_ONLY 0x0001 /* EXPLAIN, no EXEC */ #define EXEC_FLAG_REWIND 0x0002 /* need efficient rescan */ #define EXEC_FLAG_BACKWARD 0x0004 /* need backward scan */ #define EXEC_FLAG_MARK 0x0008 /* need mark/restore */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 4b1635eb8b..6a92fb1d6f 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -2189,7 +2189,7 @@ typedef struct GatherMergeState } GatherMergeState; /* ---------------- - * Values displayed by EXPLAIN ANALYZE + * Values displayed by EXPLAIN EXEC * ---------------- */ typedef struct HashInstrumentation --------------2.21.0--
v5-0006-Mechanical-changes-in-file_fdw-and-postgres_fdw.patch (text/x-diff, 2.4K) download From e4077aa6371b84e83c4cb4ccbd41d3e8577e105a Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Tue, 14 May 2019 22:56:29 -0700 Subject: [PATCH v5 6/8] Mechanical changes in file_fdw and postgres_fdw To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c index 85534a3a76..58e88c9957 100644 --- a/contrib/file_fdw/file_fdw.c +++ b/contrib/file_fdw/file_fdw.c @@ -661,7 +661,7 @@ fileBeginForeignScan(ForeignScanState *node, int eflags) FileFdwExecutionState *festate; /* - * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL. + * Do nothing in EXPLAIN (no EXEC) case. node->fdw_state stays NULL. */ if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return; diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 2b6d885efe..7e739f56a9 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -1413,7 +1413,7 @@ postgresBeginForeignScan(ForeignScanState *node, int eflags) int numParams; /* - * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL. + * Do nothing in EXPLAIN (no EXEC) case. node->fdw_state stays NULL. */ if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return; @@ -1804,7 +1804,7 @@ postgresBeginForeignModify(ModifyTableState *mtstate, RangeTblEntry *rte; /* - * Do nothing in EXPLAIN (no ANALYZE) case. resultRelInfo->ri_FdwState + * Do nothing in EXPLAIN (no EXEC) case. resultRelInfo->ri_FdwState * stays NULL. */ if (eflags & EXEC_FLAG_EXPLAIN_ONLY) @@ -2345,7 +2345,7 @@ postgresBeginDirectModify(ForeignScanState *node, int eflags) int numParams; /* - * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL. + * Do nothing in EXPLAIN (no EXEC) case. node->fdw_state stays NULL. */ if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return; @@ -2477,7 +2477,7 @@ postgresIterateDirectModify(ForeignScanState *node) if (dmstate->set_processed) estate->es_processed += dmstate->num_tuples; - /* Increment the tuple count for EXPLAIN ANALYZE if necessary. */ + /* Increment the tuple count for EXPLAIN EXEC if necessary. */ if (instr) instr->tuplecount += dmstate->num_tuples; --------------2.21.0--
v5-0007-Propagate-changes-to-auto_explain.patch (text/x-diff, 3.2K) download From ab85402730b48651780d873f9fefffbc184a207c Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Sat, 18 May 2019 10:48:14 -0700 Subject: [PATCH v5 7/8] Propagate changes to auto_explain To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit diff --git a/contrib/auto_explain/auto_explain.c b/contrib/auto_explain/auto_explain.c index edc50f9368..1aeda40ea1 100644 --- a/contrib/auto_explain/auto_explain.c +++ b/contrib/auto_explain/auto_explain.c @@ -23,7 +23,7 @@ PG_MODULE_MAGIC; /* GUC variables */ static int auto_explain_log_min_duration = -1; /* msec or -1 */ -static bool auto_explain_log_analyze = false; +static bool auto_explain_log_exec = false; static bool auto_explain_log_verbose = false; static bool auto_explain_log_buffers = false; static bool auto_explain_log_triggers = false; @@ -102,10 +102,10 @@ _PG_init(void) NULL, NULL); - DefineCustomBoolVariable("auto_explain.log_analyze", - "Use EXPLAIN ANALYZE for plan logging.", + DefineCustomBoolVariable("auto_explain.log_exec", + "Use EXPLAIN EXEC for plan logging.", NULL, - &auto_explain_log_analyze, + &auto_explain_log_exec, false, PGC_SUSET, 0, @@ -148,7 +148,7 @@ _PG_init(void) DefineCustomBoolVariable("auto_explain.log_triggers", "Include trigger statistics in plans.", - "This has no effect unless log_analyze is also set.", + "This has no effect unless log_exec is also set.", &auto_explain_log_triggers, false, PGC_SUSET, @@ -258,8 +258,8 @@ explain_ExecutorStart(QueryDesc *queryDesc, int eflags) if (auto_explain_enabled() && current_query_sampled) { - /* Enable per-node instrumentation iff log_analyze is required. */ - if (auto_explain_log_analyze && (eflags & EXEC_FLAG_EXPLAIN_ONLY) == 0) + /* Enable per-node instrumentation iff log_exec is required. */ + if (auto_explain_log_exec && (eflags & EXEC_FLAG_EXPLAIN_ONLY) == 0) { if (auto_explain_log_timing) queryDesc->instrument_options |= INSTRUMENT_TIMER; @@ -362,18 +362,18 @@ explain_ExecutorEnd(QueryDesc *queryDesc) { ExplainState *es = NewExplainState(); - es->analyze = (queryDesc->instrument_options && auto_explain_log_analyze); + es->exec = (queryDesc->instrument_options && auto_explain_log_exec); es->verbose = auto_explain_log_verbose; - es->buffers = (es->analyze && auto_explain_log_buffers); - es->timing = (es->analyze && auto_explain_log_timing); - es->summary = es->analyze; + es->buffers = (es->exec && auto_explain_log_buffers); + es->timing = (es->exec && auto_explain_log_timing); + es->summary = es->exec; es->format = auto_explain_log_format; es->settings = auto_explain_log_settings; ExplainBeginOutput(es); ExplainQueryText(es, queryDesc); ExplainPrintPlan(es, queryDesc); - if (es->analyze && auto_explain_log_triggers) + if (es->exec && auto_explain_log_triggers) ExplainPrintTriggers(es, queryDesc); if (es->costs) ExplainPrintJITSummary(es, queryDesc); --------------2.21.0--
v5-0008-Mechanical-changes-to-regression-tests-and-output.patch (text/x-diff, 42.2K) download From c2daea0be1e10112c8ddd4c28f32c72e46dfb3f2 Mon Sep 17 00:00:00 2001 From: David Fetter <david@fetter.org> Date: Sat, 18 May 2019 11:30:23 -0700 Subject: [PATCH v5 8/8] Mechanical changes to regression tests and output To: hackers MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.21.0" This is a multi-part message in MIME format. --------------2.21.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit diff --git a/src/test/regress/expected/join_hash.out b/src/test/regress/expected/join_hash.out index 9eee39bdd3..dccb4e82a5 100644 --- a/src/test/regress/expected/join_hash.out +++ b/src/test/regress/expected/join_hash.out @@ -4,7 +4,7 @@ begin; set local min_parallel_table_scan_size = 0; set local parallel_setup_cost = 0; --- Extract bucket and batch counts from an explain analyze plan. In +-- Extract bucket and batch counts from an explain (exec) plan. In -- general we can't make assertions about how many batches (or -- buckets) will be required because it can vary, but we can in some -- special cases and we can check for growth. @@ -39,7 +39,7 @@ declare hash_node json; begin for whole_plan in - execute 'explain (analyze, format ''json'') ' || query + execute 'explain (exec, format ''json'') ' || query loop hash_node := find_hash(json_extract_path(whole_plan, '0', 'Plan')); original := hash_node->>'Original Hash Batches'; @@ -518,7 +518,7 @@ $$); rollback to settings; -- A couple of other hash join tests unrelated to work_mem management. --- Check that EXPLAIN ANALYZE has data even if the leader doesn't participate +-- Check that EXPLAIN (EXEC) has data even if the leader doesn't participate savepoint settings; set local max_parallel_workers_per_gather = 2; set local work_mem = '4MB'; diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index 841bd8bc67..a30814ec48 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -1623,7 +1623,7 @@ create table ab_a3_b1 partition of ab_a3 for values in (1); create table ab_a3_b2 partition of ab_a3 for values in (2); create table ab_a3_b3 partition of ab_a3 for values in (3); -- Disallow index only scans as concurrent transactions may stop visibility --- bits being set causing "Heap Fetches" to be unstable in the EXPLAIN ANALYZE +-- bits being set causing "Heap Fetches" to be unstable in the EXPLAIN (EXEC) -- output. set enable_indexonlyscan = off; prepare ab_q1 (int, int, int) as @@ -1655,7 +1655,7 @@ execute ab_q1 (1, 8, 3); ---+--- (0 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2, 3); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 2, 3); QUERY PLAN --------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1668,7 +1668,7 @@ explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2, 3); Filter: ((a >= $1) AND (a <= $2) AND (b <= $3)) (8 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q1 (1, 2, 3); +explain (exec, costs off, summary off, timing off) execute ab_q1 (1, 2, 3); QUERY PLAN --------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1718,7 +1718,7 @@ execute ab_q1 (1, 8); --- (0 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 2); QUERY PLAN ------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1729,7 +1729,7 @@ explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2); Filter: ((a >= $1) AND (a <= $2) AND (b < 3)) (6 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 4); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 4); QUERY PLAN ------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1773,7 +1773,7 @@ execute ab_q2 (1, 8); --- (0 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q2 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q2 (2, 2); QUERY PLAN -------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1816,7 +1816,7 @@ execute ab_q3 (1, 8); --- (0 rows) -explain (analyze, costs off, summary off, timing off) execute ab_q3 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q3 (2, 2); QUERY PLAN -------------------------------------------------------- Append (actual rows=0 loops=1) @@ -1857,7 +1857,7 @@ begin; -- Test run-time pruning using stable functions create function list_part_fn(int) returns int as $$ begin return $1; end;$$ language plpgsql stable; -- Ensure pruning works using a stable function containing no Vars -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1); +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1); QUERY PLAN ------------------------------------------------------ Append (actual rows=1 loops=1) @@ -1867,7 +1867,7 @@ explain (analyze, costs off, summary off, timing off) select * from list_part wh (4 rows) -- Ensure pruning does not take place when the function has a Var parameter -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(a); +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(a); QUERY PLAN ------------------------------------------------------ Append (actual rows=4 loops=1) @@ -1882,7 +1882,7 @@ explain (analyze, costs off, summary off, timing off) select * from list_part wh (9 rows) -- Ensure pruning does not take place when the expression contains a Var. -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1) + a; +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1) + a; QUERY PLAN ------------------------------------------------------ Append (actual rows=0 loops=1) @@ -1913,7 +1913,7 @@ declare ln text; begin for ln in - execute format('explain (analyze, costs off, summary off, timing off) %s', + execute format('explain (exec, costs off, summary off, timing off) %s', $1) loop if ln like '%Parallel%' then @@ -2286,7 +2286,7 @@ reset parallel_tuple_cost; reset min_parallel_table_scan_size; reset max_parallel_workers_per_gather; -- Test run-time partition pruning with an initplan -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from ab where a = (select max(a) from lprt_a) and b = (select max(a)-1 from lprt_a); QUERY PLAN ------------------------------------------------------------------------- @@ -2345,7 +2345,7 @@ select * from ab where a = (select max(a) from lprt_a) and b = (select max(a)-1 (52 rows) -- Test run-time partition pruning with UNION ALL parents -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from (select * from ab where a = 1 union all select * from ab) ab where b = (select 1); QUERY PLAN ------------------------------------------------------------------------------- @@ -2389,7 +2389,7 @@ select * from (select * from ab where a = 1 union all select * from ab) ab where (37 rows) -- A case containing a UNION ALL with a non-partitioned child. -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from (select * from ab where a = 1 union all (values(10,5)) union all select * from ab) ab where b = (select 1); QUERY PLAN ------------------------------------------------------------------------------- @@ -2449,7 +2449,7 @@ union all select tableoid::regclass,a,b from ab ) ab where a = $1 and b = (select -10); -- Ensure the xy_1 subplan is not pruned. -explain (analyze, costs off, summary off, timing off) execute ab_q6(1); +explain (exec, costs off, summary off, timing off) execute ab_q6(1); QUERY PLAN -------------------------------------------------------- Append (actual rows=0 loops=1) @@ -2491,7 +2491,7 @@ deallocate ab_q5; deallocate ab_q6; -- UPDATE on a partition subtree has been seen to have problems. insert into ab values (1,2); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a; QUERY PLAN ------------------------------------------------------------------------------------- @@ -2571,7 +2571,7 @@ table ab; -- Test UPDATE where source relation has run-time pruning enabled truncate ab; insert into ab values (1, 1), (1, 2), (1, 3), (2, 1); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) update ab_a1 set b = 3 from ab_a2 where ab_a2.b = (select 1); QUERY PLAN ---------------------------------------------------------------------- @@ -2643,7 +2643,7 @@ create index tprt6_idx on tprt_6 (col1); insert into tprt values (10), (20), (501), (502), (505), (1001), (4500); set enable_hashjoin = off; set enable_mergejoin = off; -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 > tprt.col1; QUERY PLAN -------------------------------------------------------------------------- @@ -2664,7 +2664,7 @@ select * from tbl1 join tprt on tbl1.col1 > tprt.col1; Index Cond: (col1 < tbl1.col1) (15 rows) -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; QUERY PLAN -------------------------------------------------------------------------- @@ -2709,7 +2709,7 @@ order by tbl1.col1, tprt.col1; -- Multiple partitions insert into tbl1 values (1001), (1010), (1011); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 inner join tprt on tbl1.col1 > tprt.col1; QUERY PLAN -------------------------------------------------------------------------- @@ -2730,7 +2730,7 @@ select * from tbl1 inner join tprt on tbl1.col1 > tprt.col1; Index Cond: (col1 < tbl1.col1) (15 rows) -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 inner join tprt on tbl1.col1 = tprt.col1; QUERY PLAN -------------------------------------------------------------------------- @@ -2794,7 +2794,7 @@ order by tbl1.col1, tprt.col1; -- Last partition delete from tbl1; insert into tbl1 values (4400); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 < tprt.col1; QUERY PLAN -------------------------------------------------------------------------- @@ -2826,7 +2826,7 @@ order by tbl1.col1, tprt.col1; -- No matching partition delete from tbl1; insert into tbl1 values (10000); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; QUERY PLAN ------------------------------------------------------------------- @@ -2893,7 +2893,7 @@ execute part_abc_q1 (1, 2, 3); (0 rows) -- Single partition should be scanned. -explain (analyze, costs off, summary off, timing off) execute part_abc_q1 (1, 2, 3); +explain (exec, costs off, summary off, timing off) execute part_abc_q1 (1, 2, 3); QUERY PLAN ------------------------------------------------- Seq Scan on part_abc_p1 (actual rows=0 loops=1) @@ -2943,7 +2943,7 @@ execute q1 (1,2); ---+--- (0 rows) -explain (analyze, costs off, summary off, timing off) execute q1 (1,1); +explain (exec, costs off, summary off, timing off) execute q1 (1,1); QUERY PLAN ----------------------------------------------------- Append (actual rows=0 loops=1) @@ -2952,7 +2952,7 @@ explain (analyze, costs off, summary off, timing off) execute q1 (1,1); Filter: (b = ANY (ARRAY[$1, $2])) (4 rows) -explain (analyze, costs off, summary off, timing off) execute q1 (2,2); +explain (exec, costs off, summary off, timing off) execute q1 (2,2); QUERY PLAN ----------------------------------------------------- Append (actual rows=0 loops=1) @@ -2963,7 +2963,7 @@ explain (analyze, costs off, summary off, timing off) execute q1 (2,2); -- Try with no matching partitions. One subplan should remain in this case, -- but it shouldn't be executed. -explain (analyze, costs off, summary off, timing off) execute q1 (0,0); +explain (exec, costs off, summary off, timing off) execute q1 (0,0); QUERY PLAN ---------------------------------------------- Append (actual rows=0 loops=1) @@ -3001,7 +3001,7 @@ execute q1 (1,2,3,4); (0 rows) -- Both partitions allowed by IN clause, but one disallowed by <> clause -explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,0); +explain (exec, costs off, summary off, timing off) execute q1 (1,2,2,0); QUERY PLAN ------------------------------------------------------------------------- Append (actual rows=0 loops=1) @@ -3012,7 +3012,7 @@ explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,0); -- Both partitions allowed by IN clause, then both excluded again by <> clauses. -- One subplan will remain in this case, but it should not be executed. -explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,1); +explain (exec, costs off, summary off, timing off) execute q1 (1,2,2,1); QUERY PLAN ------------------------------------------------------------------------- Append (actual rows=0 loops=1) @@ -3022,7 +3022,7 @@ explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,1); (4 rows) -- Ensure Params that evaluate to NULL properly prune away all partitions -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from listp where a = (select null::int); QUERY PLAN ---------------------------------------------- @@ -3195,7 +3195,7 @@ insert into boolvalues values('t'),('f'); create table boolp (a bool) partition by list (a); create table boolp_t partition of boolp for values in('t'); create table boolp_f partition of boolp for values in('f'); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from boolp where a = (select value from boolvalues where value); QUERY PLAN -------------------------------------------------------- @@ -3210,7 +3210,7 @@ select * from boolp where a = (select value from boolvalues where value); Filter: (a = $0) (9 rows) -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from boolp where a = (select value from boolvalues where not value); QUERY PLAN -------------------------------------------------------- @@ -3281,7 +3281,7 @@ execute mt_q1(0); 25 (3 rows) -explain (analyze, costs off, summary off, timing off) execute mt_q1(15); +explain (exec, costs off, summary off, timing off) execute mt_q1(15); QUERY PLAN ------------------------------------------------------------------------------- Merge Append (actual rows=2 loops=1) @@ -3302,7 +3302,7 @@ execute mt_q1(15); 25 (2 rows) -explain (analyze, costs off, summary off, timing off) execute mt_q1(25); +explain (exec, costs off, summary off, timing off) execute mt_q1(25); QUERY PLAN ------------------------------------------------------------------------------- Merge Append (actual rows=1 loops=1) @@ -3320,7 +3320,7 @@ execute mt_q1(25); (1 row) -- Ensure MergeAppend behaves correctly when no subplans match -explain (analyze, costs off, summary off, timing off) execute mt_q1(35); +explain (exec, costs off, summary off, timing off) execute mt_q1(35); QUERY PLAN ------------------------------------------------------------------------ Merge Append (actual rows=0 loops=1) @@ -3337,7 +3337,7 @@ execute mt_q1(35); deallocate mt_q1; -- ensure initplan params properly prune partitions -explain (analyze, costs off, summary off, timing off) select * from ma_test where a >= (select min(b) from ma_test_p2) order by b; +explain (exec, costs off, summary off, timing off) select * from ma_test where a >= (select min(b) from ma_test_p2) order by b; QUERY PLAN ------------------------------------------------------------------------------------------------------------ Merge Append (actual rows=20 loops=1) @@ -3782,7 +3782,7 @@ create table listp (a int, b int) partition by list (a); create table listp1 partition of listp for values in(1); create table listp2 partition of listp for values in(2) partition by list(b); create table listp2_10 partition of listp2 for values in (10); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from listp where a = (select 2) and b <> 10; QUERY PLAN -------------------------------------------- diff --git a/src/test/regress/expected/select.out b/src/test/regress/expected/select.out index c441049f41..16ac7bdf43 100644 --- a/src/test/regress/expected/select.out +++ b/src/test/regress/expected/select.out @@ -753,7 +753,7 @@ select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; (1 row) -- actually run the query with an analyze to use the partial index -explain (costs off, analyze on, timing off, summary off) +explain (costs off, exec on, timing off, summary off) select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; QUERY PLAN ----------------------------------------------------------------- diff --git a/src/test/regress/expected/select_into.out b/src/test/regress/expected/select_into.out index f373fae679..05e07cefe6 100644 --- a/src/test/regress/expected/select_into.out +++ b/src/test/regress/expected/select_into.out @@ -112,12 +112,12 @@ SELECT * FROM created_table; 4567890123456789 | -4567890123456789 (5 rows) --- Try EXPLAIN ANALYZE SELECT INTO and EXPLAIN ANALYZE CREATE TABLE AS +-- Try EXPLAIN (EXEC) SELECT INTO and EXPLAIN (EXEC) CREATE TABLE AS -- WITH NO DATA, but hide the outputs since they won't be stable. DO $$ BEGIN - EXECUTE 'EXPLAIN ANALYZE SELECT * INTO TABLE easi FROM int8_tbl'; - EXECUTE 'EXPLAIN ANALYZE CREATE TABLE easi2 AS SELECT * FROM int8_tbl WITH NO DATA'; + EXECUTE 'EXPLAIN (EXEC) SELECT * INTO TABLE easi FROM int8_tbl'; + EXECUTE 'EXPLAIN (EXEC) CREATE TABLE easi2 AS SELECT * FROM int8_tbl WITH NO DATA'; END$$; DROP TABLE created_table; DROP TABLE easi, easi2; diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out index 0eca76cb41..c4c8f476ff 100644 --- a/src/test/regress/expected/select_parallel.out +++ b/src/test/regress/expected/select_parallel.out @@ -505,7 +505,7 @@ select count(*) from bmscantest where a>1; -- test accumulation of stats for parallel nodes reset enable_seqscan; alter table tenk2 set (parallel_workers = 0); -explain (analyze, timing off, summary off, costs off) +explain (exec, timing off, summary off, costs off) select count(*) from tenk1, tenk2 where tenk1.hundred > 1 and tenk2.thousand=0; QUERY PLAN @@ -531,7 +531,7 @@ $$ declare ln text; begin for ln in - explain (analyze, timing off, summary off, costs off) + explain (exec, timing off, summary off, costs off) select * from (select ten from tenk1 where ten < 100 order by ten) ss right join (values (1),(2),(3)) v(x) on true @@ -1006,7 +1006,7 @@ explain (costs off) -- to increase the parallel query test coverage SAVEPOINT settings; SET LOCAL force_parallel_mode = 1; -EXPLAIN (analyze, timing off, summary off, costs off) SELECT * FROM tenk1; +EXPLAIN (exec, timing off, summary off, costs off) SELECT * FROM tenk1; QUERY PLAN ------------------------------------------------------------- Gather (actual rows=10000 loops=1) diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out index 6dfca7a606..3ff69b864f 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -12,7 +12,7 @@ declare first_row bool := true; begin for ln in - execute format('explain analyze %s', $1) + execute format('explain (exec) %s', $1) loop if first_row then first_row := false; diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out index 2d1963d12a..705c953e24 100644 --- a/src/test/regress/expected/subselect.out +++ b/src/test/regress/expected/subselect.out @@ -1120,8 +1120,8 @@ drop function tattle(x int, y int); -- -- Test that LIMIT can be pushed to SORT through a subquery that just projects -- columns. We check for that having happened by looking to see if EXPLAIN --- ANALYZE shows that a top-N sort was used. We must suppress or filter away --- all the non-invariant parts of the EXPLAIN ANALYZE output. +-- (EXEC) shows that a top-N sort was used. We must suppress or filter away +-- all the non-invariant parts of the EXPLAIN (EXEC) output. -- create table sq_limit (pk int primary key, c1 int, c2 int); insert into sq_limit values @@ -1138,7 +1138,7 @@ $$ declare ln text; begin for ln in - explain (analyze, summary off, timing off, costs off) + explain (exec, summary off, timing off, costs off) select * from (select pk,c2 from sq_limit order by c1,pk) as x limit 3 loop ln := regexp_replace(ln, 'Memory: \S*', 'Memory: xxx'); diff --git a/src/test/regress/expected/tidscan.out b/src/test/regress/expected/tidscan.out index 9b5eb04bfd..8e62c9b28b 100644 --- a/src/test/regress/expected/tidscan.out +++ b/src/test/regress/expected/tidscan.out @@ -189,7 +189,7 @@ FETCH NEXT FROM c; (1 row) -- perform update -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; QUERY PLAN --------------------------------------------------- @@ -205,7 +205,7 @@ FETCH NEXT FROM c; (1 row) -- perform update -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; QUERY PLAN --------------------------------------------------- @@ -229,7 +229,7 @@ FETCH NEXT FROM c; (0 rows) -- should error out -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; ERROR: cursor "c" is not positioned on a row ROLLBACK; diff --git a/src/test/regress/sql/join_hash.sql b/src/test/regress/sql/join_hash.sql index ae352e9b0b..26bb7eeb16 100644 --- a/src/test/regress/sql/join_hash.sql +++ b/src/test/regress/sql/join_hash.sql @@ -7,7 +7,7 @@ begin; set local min_parallel_table_scan_size = 0; set local parallel_setup_cost = 0; --- Extract bucket and batch counts from an explain analyze plan. In +-- Extract bucket and batch counts from an explain (exec) plan. In -- general we can't make assertions about how many batches (or -- buckets) will be required because it can vary, but we can in some -- special cases and we can check for growth. @@ -42,7 +42,7 @@ declare hash_node json; begin for whole_plan in - execute 'explain (analyze, format ''json'') ' || query + execute 'explain (exec, format ''json'') ' || query loop hash_node := find_hash(json_extract_path(whole_plan, '0', 'Plan')); original := hash_node->>'Original Hash Batches'; @@ -280,7 +280,7 @@ rollback to settings; -- A couple of other hash join tests unrelated to work_mem management. --- Check that EXPLAIN ANALYZE has data even if the leader doesn't participate +-- Check that EXPLAIN (EXEC) has data even if the leader doesn't participate savepoint settings; set local max_parallel_workers_per_gather = 2; set local work_mem = '4MB'; diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql index 071e28dce8..553332aa5b 100644 --- a/src/test/regress/sql/partition_prune.sql +++ b/src/test/regress/sql/partition_prune.sql @@ -327,7 +327,7 @@ create table ab_a3_b2 partition of ab_a3 for values in (2); create table ab_a3_b3 partition of ab_a3 for values in (3); -- Disallow index only scans as concurrent transactions may stop visibility --- bits being set causing "Heap Fetches" to be unstable in the EXPLAIN ANALYZE +-- bits being set causing "Heap Fetches" to be unstable in the EXPLAIN (EXEC) -- output. set enable_indexonlyscan = off; @@ -342,8 +342,8 @@ execute ab_q1 (1, 8, 3); execute ab_q1 (1, 8, 3); execute ab_q1 (1, 8, 3); -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2, 3); -explain (analyze, costs off, summary off, timing off) execute ab_q1 (1, 2, 3); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 2, 3); +explain (exec, costs off, summary off, timing off) execute ab_q1 (1, 2, 3); deallocate ab_q1; @@ -359,8 +359,8 @@ execute ab_q1 (1, 8); execute ab_q1 (1, 8); execute ab_q1 (1, 8); -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2); -explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 4); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q1 (2, 4); -- Ensure a mix of PARAM_EXTERN and PARAM_EXEC Params work together at -- different levels of partitioning. @@ -373,7 +373,7 @@ execute ab_q2 (1, 8); execute ab_q2 (1, 8); execute ab_q2 (1, 8); -explain (analyze, costs off, summary off, timing off) execute ab_q2 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q2 (2, 2); -- As above, but swap the PARAM_EXEC Param to the first partition level prepare ab_q3 (int, int) as @@ -385,7 +385,7 @@ execute ab_q3 (1, 8); execute ab_q3 (1, 8); execute ab_q3 (1, 8); -explain (analyze, costs off, summary off, timing off) execute ab_q3 (2, 2); +explain (exec, costs off, summary off, timing off) execute ab_q3 (2, 2); -- Test a backwards Append scan create table list_part (a int) partition by list (a); @@ -416,13 +416,13 @@ begin; create function list_part_fn(int) returns int as $$ begin return $1; end;$$ language plpgsql stable; -- Ensure pruning works using a stable function containing no Vars -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1); +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1); -- Ensure pruning does not take place when the function has a Var parameter -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(a); +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(a); -- Ensure pruning does not take place when the expression contains a Var. -explain (analyze, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1) + a; +explain (exec, costs off, summary off, timing off) select * from list_part where a = list_part_fn(1) + a; rollback; @@ -440,7 +440,7 @@ declare ln text; begin for ln in - execute format('explain (analyze, costs off, summary off, timing off) %s', + execute format('explain (exec, costs off, summary off, timing off) %s', $1) loop if ln like '%Parallel%' then @@ -537,15 +537,15 @@ reset min_parallel_table_scan_size; reset max_parallel_workers_per_gather; -- Test run-time partition pruning with an initplan -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from ab where a = (select max(a) from lprt_a) and b = (select max(a)-1 from lprt_a); -- Test run-time partition pruning with UNION ALL parents -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from (select * from ab where a = 1 union all select * from ab) ab where b = (select 1); -- A case containing a UNION ALL with a non-partitioned child. -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from (select * from ab where a = 1 union all (values(10,5)) union all select * from ab) ab where b = (select 1); -- Another UNION ALL test, but containing a mix of exec init and exec run-time pruning. @@ -566,7 +566,7 @@ union all ) ab where a = $1 and b = (select -10); -- Ensure the xy_1 subplan is not pruned. -explain (analyze, costs off, summary off, timing off) execute ab_q6(1); +explain (exec, costs off, summary off, timing off) execute ab_q6(1); -- Ensure we see just the xy_1 row. execute ab_q6(100); @@ -584,14 +584,14 @@ deallocate ab_q6; -- UPDATE on a partition subtree has been seen to have problems. insert into ab values (1,2); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a; table ab; -- Test UPDATE where source relation has run-time pruning enabled truncate ab; insert into ab values (1, 1), (1, 2), (1, 3), (2, 1); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) update ab_a1 set b = 3 from ab_a2 where ab_a2.b = (select 1); select tableoid::regclass, * from ab; @@ -622,10 +622,10 @@ insert into tprt values (10), (20), (501), (502), (505), (1001), (4500); set enable_hashjoin = off; set enable_mergejoin = off; -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 > tprt.col1; -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -638,10 +638,10 @@ order by tbl1.col1, tprt.col1; -- Multiple partitions insert into tbl1 values (1001), (1010), (1011); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 inner join tprt on tbl1.col1 > tprt.col1; -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 inner join tprt on tbl1.col1 = tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -655,7 +655,7 @@ order by tbl1.col1, tprt.col1; -- Last partition delete from tbl1; insert into tbl1 values (4400); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 < tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -665,7 +665,7 @@ order by tbl1.col1, tprt.col1; -- No matching partition delete from tbl1; insert into tbl1 values (10000); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -696,7 +696,7 @@ execute part_abc_q1 (1, 2, 3); execute part_abc_q1 (1, 2, 3); -- Single partition should be scanned. -explain (analyze, costs off, summary off, timing off) execute part_abc_q1 (1, 2, 3); +explain (exec, costs off, summary off, timing off) execute part_abc_q1 (1, 2, 3); deallocate part_abc_q1; @@ -722,13 +722,13 @@ execute q1 (1,2); execute q1 (1,2); execute q1 (1,2); -explain (analyze, costs off, summary off, timing off) execute q1 (1,1); +explain (exec, costs off, summary off, timing off) execute q1 (1,1); -explain (analyze, costs off, summary off, timing off) execute q1 (2,2); +explain (exec, costs off, summary off, timing off) execute q1 (2,2); -- Try with no matching partitions. One subplan should remain in this case, -- but it shouldn't be executed. -explain (analyze, costs off, summary off, timing off) execute q1 (0,0); +explain (exec, costs off, summary off, timing off) execute q1 (0,0); deallocate q1; @@ -742,14 +742,14 @@ execute q1 (1,2,3,4); execute q1 (1,2,3,4); -- Both partitions allowed by IN clause, but one disallowed by <> clause -explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,0); +explain (exec, costs off, summary off, timing off) execute q1 (1,2,2,0); -- Both partitions allowed by IN clause, then both excluded again by <> clauses. -- One subplan will remain in this case, but it should not be executed. -explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,1); +explain (exec, costs off, summary off, timing off) execute q1 (1,2,2,1); -- Ensure Params that evaluate to NULL properly prune away all partitions -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from listp where a = (select null::int); drop table listp; @@ -837,10 +837,10 @@ create table boolp (a bool) partition by list (a); create table boolp_t partition of boolp for values in('t'); create table boolp_f partition of boolp for values in('f'); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from boolp where a = (select value from boolvalues where value); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from boolp where a = (select value from boolvalues where not value); drop table boolp; @@ -868,18 +868,18 @@ execute mt_q1(0); execute mt_q1(0); execute mt_q1(0); -explain (analyze, costs off, summary off, timing off) execute mt_q1(15); +explain (exec, costs off, summary off, timing off) execute mt_q1(15); execute mt_q1(15); -explain (analyze, costs off, summary off, timing off) execute mt_q1(25); +explain (exec, costs off, summary off, timing off) execute mt_q1(25); execute mt_q1(25); -- Ensure MergeAppend behaves correctly when no subplans match -explain (analyze, costs off, summary off, timing off) execute mt_q1(35); +explain (exec, costs off, summary off, timing off) execute mt_q1(35); execute mt_q1(35); deallocate mt_q1; -- ensure initplan params properly prune partitions -explain (analyze, costs off, summary off, timing off) select * from ma_test where a >= (select min(b) from ma_test_p2) order by b; +explain (exec, costs off, summary off, timing off) select * from ma_test where a >= (select min(b) from ma_test_p2) order by b; reset enable_seqscan; reset enable_sort; @@ -1062,7 +1062,7 @@ create table listp1 partition of listp for values in(1); create table listp2 partition of listp for values in(2) partition by list(b); create table listp2_10 partition of listp2 for values in (10); -explain (analyze, costs off, summary off, timing off) +explain (exec, costs off, summary off, timing off) select * from listp where a = (select 2) and b <> 10; -- diff --git a/src/test/regress/sql/select.sql b/src/test/regress/sql/select.sql index b5929b2eca..f573dfa921 100644 --- a/src/test/regress/sql/select.sql +++ b/src/test/regress/sql/select.sql @@ -196,7 +196,7 @@ explain (costs off) select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; -- actually run the query with an analyze to use the partial index -explain (costs off, analyze on, timing off, summary off) +explain (costs off, exec on, timing off, summary off) select * from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; explain (costs off) select unique2 from onek2 where unique2 = 11 and stringu1 = 'ATAAAA'; diff --git a/src/test/regress/sql/select_into.sql b/src/test/regress/sql/select_into.sql index a708fef0ea..2fd8f257a9 100644 --- a/src/test/regress/sql/select_into.sql +++ b/src/test/regress/sql/select_into.sql @@ -85,12 +85,12 @@ SELECT make_table(); SELECT * FROM created_table; --- Try EXPLAIN ANALYZE SELECT INTO and EXPLAIN ANALYZE CREATE TABLE AS +-- Try EXPLAIN (EXEC) SELECT INTO and EXPLAIN (EXEC) CREATE TABLE AS -- WITH NO DATA, but hide the outputs since they won't be stable. DO $$ BEGIN - EXECUTE 'EXPLAIN ANALYZE SELECT * INTO TABLE easi FROM int8_tbl'; - EXECUTE 'EXPLAIN ANALYZE CREATE TABLE easi2 AS SELECT * FROM int8_tbl WITH NO DATA'; + EXECUTE 'EXPLAIN (EXEC) SELECT * INTO TABLE easi FROM int8_tbl'; + EXECUTE 'EXPLAIN (EXEC) CREATE TABLE easi2 AS SELECT * FROM int8_tbl WITH NO DATA'; END$$; DROP TABLE created_table; diff --git a/src/test/regress/sql/select_parallel.sql b/src/test/regress/sql/select_parallel.sql index 03c056b8b7..de8ef80ecf 100644 --- a/src/test/regress/sql/select_parallel.sql +++ b/src/test/regress/sql/select_parallel.sql @@ -197,7 +197,7 @@ select count(*) from bmscantest where a>1; -- test accumulation of stats for parallel nodes reset enable_seqscan; alter table tenk2 set (parallel_workers = 0); -explain (analyze, timing off, summary off, costs off) +explain (exec, timing off, summary off, costs off) select count(*) from tenk1, tenk2 where tenk1.hundred > 1 and tenk2.thousand=0; alter table tenk2 reset (parallel_workers); @@ -209,7 +209,7 @@ $$ declare ln text; begin for ln in - explain (analyze, timing off, summary off, costs off) + explain (exec, timing off, summary off, costs off) select * from (select ten from tenk1 where ten < 100 order by ten) ss right join (values (1),(2),(3)) v(x) on true @@ -376,7 +376,7 @@ explain (costs off) -- to increase the parallel query test coverage SAVEPOINT settings; SET LOCAL force_parallel_mode = 1; -EXPLAIN (analyze, timing off, summary off, costs off) SELECT * FROM tenk1; +EXPLAIN (exec, timing off, summary off, costs off) SELECT * FROM tenk1; ROLLBACK TO SAVEPOINT settings; -- provoke error in worker diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql index c6a5776120..94d0b73c1f 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -14,7 +14,7 @@ declare first_row bool := true; begin for ln in - execute format('explain analyze %s', $1) + execute format('explain (exec) %s', $1) loop if first_row then first_row := false; diff --git a/src/test/regress/sql/subselect.sql b/src/test/regress/sql/subselect.sql index 99ca69791e..a9471c7ace 100644 --- a/src/test/regress/sql/subselect.sql +++ b/src/test/regress/sql/subselect.sql @@ -598,8 +598,8 @@ drop function tattle(x int, y int); -- -- Test that LIMIT can be pushed to SORT through a subquery that just projects -- columns. We check for that having happened by looking to see if EXPLAIN --- ANALYZE shows that a top-N sort was used. We must suppress or filter away --- all the non-invariant parts of the EXPLAIN ANALYZE output. +-- (EXEC) shows that a top-N sort was used. We must suppress or filter away +-- all the non-invariant parts of the EXPLAIN (EXEC) output. -- create table sq_limit (pk int primary key, c1 int, c2 int); insert into sq_limit values @@ -617,7 +617,7 @@ $$ declare ln text; begin for ln in - explain (analyze, summary off, timing off, costs off) + explain (exec, summary off, timing off, costs off) select * from (select pk,c2 from sq_limit order by c1,pk) as x limit 3 loop ln := regexp_replace(ln, 'Memory: \S*', 'Memory: xxx'); diff --git a/src/test/regress/sql/tidscan.sql b/src/test/regress/sql/tidscan.sql index ef05c09842..65e222681e 100644 --- a/src/test/regress/sql/tidscan.sql +++ b/src/test/regress/sql/tidscan.sql @@ -68,17 +68,17 @@ DECLARE c CURSOR FOR SELECT ctid, * FROM tidscan; FETCH NEXT FROM c; -- skip one row FETCH NEXT FROM c; -- perform update -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; FETCH NEXT FROM c; -- perform update -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; SELECT * FROM tidscan; -- position cursor past any rows FETCH NEXT FROM c; -- should error out -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +EXPLAIN (EXEC, COSTS OFF, SUMMARY OFF, TIMING OFF) UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *; ROLLBACK; --------------2.21.0--
^ permalink raw reply [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-21 16:32  Robert Haas <robertmhaas@gmail.com>
  parent: Tom Lane <tgl@sss.pgh.pa.us>
  1 sibling, 1 reply; 49+ messages in thread

From: Robert Haas @ 2019-05-21 16:32 UTC (permalink / raw)
  To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Alvaro Herrera <alvherre@2ndquadrant.com>; Andres Freund <andres@anarazel.de>; David Fetter <david@fetter.org>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

On Wed, May 15, 2019 at 1:53 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
> >> That seems too confusing.
>
> > Ok.  Are you voting for using EXEC as a keyword to replace ANALYZE?
>
> FWIW, given the conflict against "EXPLAIN EXECUTE prepared_stmt_name",
> we should probably just drop the whole idea.  It seemed like a great
> idea at the time, but it's going to confuse people not just Bison.

+1.  I think trying to replace ANALYZE with something else is setting
ourselves up for years, possibly decades, worth of confusion.  And
without any real benefit.

Defaulting BUFFERS to ON is probably a reasonable change, thuogh.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-21 17:38  David Fetter <david@fetter.org>
  parent: Robert Haas <robertmhaas@gmail.com>
  0 siblings, 3 replies; 49+ messages in thread

From: David Fetter @ 2019-05-21 17:38 UTC (permalink / raw)
  To: Robert Haas <robertmhaas@gmail.com>; +Cc: Tom Lane <tgl@sss.pgh.pa.us>; Alvaro Herrera <alvherre@2ndquadrant.com>; Andres Freund <andres@anarazel.de>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

On Tue, May 21, 2019 at 12:32:21PM -0400, Robert Haas wrote:
> On Wed, May 15, 2019 at 1:53 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
> > >> That seems too confusing.
> >
> > > Ok.  Are you voting for using EXEC as a keyword to replace ANALYZE?
> >
> > FWIW, given the conflict against "EXPLAIN EXECUTE prepared_stmt_name",
> > we should probably just drop the whole idea.  It seemed like a great
> > idea at the time, but it's going to confuse people not just Bison.
> 
> +1.  I think trying to replace ANALYZE with something else is setting
> ourselves up for years, possibly decades, worth of confusion.  And
> without any real benefit.
> 
> Defaulting BUFFERS to ON is probably a reasonable change, thuogh.

Would this be worth back-patching? I ask because adding it will cause
fairly large (if mechanical) churn in the regression tests.

Best,
David.
-- 
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-21 17:47  Tom Lane <tgl@sss.pgh.pa.us>
  parent: David Fetter <david@fetter.org>
  2 siblings, 0 replies; 49+ messages in thread

From: Tom Lane @ 2019-05-21 17:47 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; +Cc: Robert Haas <robertmhaas@gmail.com>; Alvaro Herrera <alvherre@2ndquadrant.com>; Andres Freund <andres@anarazel.de>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

David Fetter <david@fetter.org> writes:
> On Tue, May 21, 2019 at 12:32:21PM -0400, Robert Haas wrote:
>> Defaulting BUFFERS to ON is probably a reasonable change, thuogh.

> Would this be worth back-patching? I ask because adding it will cause
> fairly large (if mechanical) churn in the regression tests.

It really doesn't matter how much churn it causes in the regression tests.
Back-patching a significant non-bug behavioral change like that is exactly
the kind of thing we don't do, because it will cause our users pain.

			regards, tom lane





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-21 18:03  Robert Haas <robertmhaas@gmail.com>
  parent: David Fetter <david@fetter.org>
  2 siblings, 0 replies; 49+ messages in thread

From: Robert Haas @ 2019-05-21 18:03 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; +Cc: Tom Lane <tgl@sss.pgh.pa.us>; Alvaro Herrera <alvherre@2ndquadrant.com>; Andres Freund <andres@anarazel.de>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

On Tue, May 21, 2019 at 1:38 PM David Fetter <david@fetter.org> wrote:
> Would this be worth back-patching? I ask because adding it will cause
> fairly large (if mechanical) churn in the regression tests.

No.  I can't believe you're even asking that question.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-21 18:12  Andres Freund <andres@anarazel.de>
  parent: David Fetter <david@fetter.org>
  2 siblings, 1 reply; 49+ messages in thread

From: Andres Freund @ 2019-05-21 18:12 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; +Cc: Robert Haas <robertmhaas@gmail.com>; Tom Lane <tgl@sss.pgh.pa.us>; Alvaro Herrera <alvherre@2ndquadrant.com>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

Hi,

On 2019-05-21 19:38:57 +0200, David Fetter wrote:
> On Tue, May 21, 2019 at 12:32:21PM -0400, Robert Haas wrote:
> > Defaulting BUFFERS to ON is probably a reasonable change, thuogh.
> 
> Would this be worth back-patching? I ask because adding it will cause
> fairly large (if mechanical) churn in the regression tests.

This is obviously a no. But I don't even know what large mechanical
churn you're talking about? There's not that many files with EXPLAIN
(ANALYZE) in the tests - we didn't have any until recently, when we
added SUMMARY OFF, to turn off non-deterministic details (f9b1a0dd4).

$ grep -irl 'summary off' src/test/regress/{sql,input}
src/test/regress/sql/select.sql
src/test/regress/sql/partition_prune.sql
src/test/regress/sql/tidscan.sql
src/test/regress/sql/subselect.sql
src/test/regress/sql/select_parallel.sql

adding a bunch of BUFFERS OFF to those wouldn't be particularly
painful. And if we decided it somehow were painful, we could infer it
from COSTS or such.

Greetings,

Andres Freund





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-05-21 18:33  Tom Lane <tgl@sss.pgh.pa.us>
  parent: Andres Freund <andres@anarazel.de>
  0 siblings, 0 replies; 49+ messages in thread

From: Tom Lane @ 2019-05-21 18:33 UTC (permalink / raw)
  To: Andres Freund <andres@anarazel.de>; +Cc: David Fetter <david@fetter.org>; Robert Haas <robertmhaas@gmail.com>; Alvaro Herrera <alvherre@2ndquadrant.com>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

Andres Freund <andres@anarazel.de> writes:
> On 2019-05-21 19:38:57 +0200, David Fetter wrote:
>> On Tue, May 21, 2019 at 12:32:21PM -0400, Robert Haas wrote:
>>> Defaulting BUFFERS to ON is probably a reasonable change, thuogh.

>> Would this be worth back-patching? I ask because adding it will cause
>> fairly large (if mechanical) churn in the regression tests.

> This is obviously a no. But I don't even know what large mechanical
> churn you're talking about? There's not that many files with EXPLAIN
> (ANALYZE) in the tests - we didn't have any until recently, when we
> added SUMMARY OFF, to turn off non-deterministic details (f9b1a0dd4).

partition_prune.sql has got kind of a lot of them though :-(

src/test/regress/sql/tidscan.sql:3
src/test/regress/sql/partition_prune.sql:46
src/test/regress/sql/select_parallel.sql:3
src/test/regress/sql/select.sql:1
src/test/regress/sql/subselect.sql:1

Still, if we're adding BUFFERS OFF in the same places we have
SUMMARY OFF, I agree that it won't create much new hazard for
back-patching --- all those places already have a limit on
how far they can be back-patched.

			regards, tom lane





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-06-18 21:08  Peter Eisentraut <peter.eisentraut@2ndquadrant.com>
  parent: Andres Freund <andres@anarazel.de>
  0 siblings, 1 reply; 49+ messages in thread

From: Peter Eisentraut @ 2019-06-18 21:08 UTC (permalink / raw)
  To: Andres Freund <andres@anarazel.de>; Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Alvaro Herrera <alvherre@2ndquadrant.com>; David Fetter <david@fetter.org>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

On 2019-05-15 19:58, Andres Freund wrote:
> On 2019-05-15 13:53:26 -0400, Tom Lane wrote:
>> FWIW, given the conflict against "EXPLAIN EXECUTE prepared_stmt_name",
>> we should probably just drop the whole idea.  It seemed like a great
>> idea at the time, but it's going to confuse people not just Bison.
> I'm not particularly invested in the idea of renaming ANALYZE - but I
> think we might be able to come up with something less ambiguous than
> EXECUTE. Even EXECUTION might be better.

The GQL draft uses PROFILE as a separate top-level command, so it would be

    PROFILE SELECT ...

That seems nice and clear.

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-06-18 21:15  David Fetter <david@fetter.org>
  parent: Peter Eisentraut <peter.eisentraut@2ndquadrant.com>
  0 siblings, 1 reply; 49+ messages in thread

From: David Fetter @ 2019-06-18 21:15 UTC (permalink / raw)
  To: Peter Eisentraut <peter.eisentraut@2ndquadrant.com>; +Cc: Andres Freund <andres@anarazel.de>; Tom Lane <tgl@sss.pgh.pa.us>; Alvaro Herrera <alvherre@2ndquadrant.com>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

On Tue, Jun 18, 2019 at 11:08:31PM +0200, Peter Eisentraut wrote:
> On 2019-05-15 19:58, Andres Freund wrote:
> > On 2019-05-15 13:53:26 -0400, Tom Lane wrote:
> >> FWIW, given the conflict against "EXPLAIN EXECUTE prepared_stmt_name",
> >> we should probably just drop the whole idea.  It seemed like a great
> >> idea at the time, but it's going to confuse people not just Bison.
> > I'm not particularly invested in the idea of renaming ANALYZE - but I
> > think we might be able to come up with something less ambiguous than
> > EXECUTE. Even EXECUTION might be better.
> 
> The GQL draft uses PROFILE as a separate top-level command, so it would be
> 
>     PROFILE SELECT ...
> 
> That seems nice and clear.

Are you proposing something along the lines of this?

PROFILE [statement]; /* Shows the plan */
PROFILE RUN [statement]; /* Actually executes the query */

Best,
David.
-- 
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-06-19 06:15  Peter Eisentraut <peter.eisentraut@2ndquadrant.com>
  parent: David Fetter <david@fetter.org>
  0 siblings, 2 replies; 49+ messages in thread

From: Peter Eisentraut @ 2019-06-19 06:15 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; +Cc: Andres Freund <andres@anarazel.de>; Tom Lane <tgl@sss.pgh.pa.us>; Alvaro Herrera <alvherre@2ndquadrant.com>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

On 2019-06-18 23:15, David Fetter wrote:
> Are you proposing something along the lines of this?
> 
> PROFILE [statement]; /* Shows the plan */
> PROFILE RUN [statement]; /* Actually executes the query */

No, it would be

EXPLAIN statement; /* Shows the plan */
PROFILE statement; /* Actually executes the query */

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-06-19 08:18  Gavin Flower <GavinFlower@archidevsys.co.nz>
  parent: Peter Eisentraut <peter.eisentraut@2ndquadrant.com>
  1 sibling, 0 replies; 49+ messages in thread

From: Gavin Flower @ 2019-06-19 08:18 UTC (permalink / raw)
  To: pgsql-hackers@lists.postgresql.org

On 19/06/2019 18:15, Peter Eisentraut wrote:
> On 2019-06-18 23:15, David Fetter wrote:
>> Are you proposing something along the lines of this?
>>
>> PROFILE [statement]; /* Shows the plan */
>> PROFILE RUN [statement]; /* Actually executes the query */
> No, it would be
>
> EXPLAIN statement; /* Shows the plan */
> PROFILE statement; /* Actually executes the query */
>
I think that looks good, and the verbs seem well appropriate. IMnsHO






^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-06-19 12:08  Daniel Gustafsson <daniel@yesql.se>
  parent: Peter Eisentraut <peter.eisentraut@2ndquadrant.com>
  1 sibling, 1 reply; 49+ messages in thread

From: Daniel Gustafsson @ 2019-06-19 12:08 UTC (permalink / raw)
  To: Peter Eisentraut <peter.eisentraut@2ndquadrant.com>; +Cc: David Fetter <david@fetter.org>; Andres Freund <andres@anarazel.de>; Tom Lane <tgl@sss.pgh.pa.us>; Alvaro Herrera <alvherre@2ndquadrant.com>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

> On 19 Jun 2019, at 08:15, Peter Eisentraut <peter.eisentraut@2ndquadrant.com> wrote:
> 
> On 2019-06-18 23:15, David Fetter wrote:
>> Are you proposing something along the lines of this?
>> 
>> PROFILE [statement]; /* Shows the plan */
>> PROFILE RUN [statement]; /* Actually executes the query */
> 
> No, it would be
> 
> EXPLAIN statement; /* Shows the plan */
> PROFILE statement; /* Actually executes the query */

That makes a lot of sense.

cheers ./daniel




^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-06-19 14:53  David Fetter <david@fetter.org>
  parent: Daniel Gustafsson <daniel@yesql.se>
  0 siblings, 0 replies; 49+ messages in thread

From: David Fetter @ 2019-06-19 14:53 UTC (permalink / raw)
  To: Daniel Gustafsson <daniel@yesql.se>; +Cc: Peter Eisentraut <peter.eisentraut@2ndquadrant.com>; Andres Freund <andres@anarazel.de>; Tom Lane <tgl@sss.pgh.pa.us>; Alvaro Herrera <alvherre@2ndquadrant.com>; Stephen Frost <sfrost@snowman.net>; pgsql-hackers

On Wed, Jun 19, 2019 at 02:08:21PM +0200, Daniel Gustafsson wrote:
> > On 19 Jun 2019, at 08:15, Peter Eisentraut <peter.eisentraut@2ndquadrant.com> wrote:
> > 
> > On 2019-06-18 23:15, David Fetter wrote:
> >> Are you proposing something along the lines of this?
> >> 
> >> PROFILE [statement]; /* Shows the plan */
> >> PROFILE RUN [statement]; /* Actually executes the query */
> > 
> > No, it would be
> > 
> > EXPLAIN statement; /* Shows the plan */
> > PROFILE statement; /* Actually executes the query */
> 
> That makes a lot of sense.
> 
> cheers ./daniel

+1

Thanks for clarifying.

Best,
David.
-- 
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-07-02 14:06  Peter Eisentraut <peter.eisentraut@2ndquadrant.com>
  parent: David Fetter <david@fetter.org>
  0 siblings, 1 reply; 49+ messages in thread

From: Peter Eisentraut @ 2019-07-02 14:06 UTC (permalink / raw)
  To: David Fetter <david@fetter.org>; Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Stephen Frost <sfrost@snowman.net>; Andres Freund <andres@anarazel.de>; pgsql-hackers

On 2019-05-18 19:39, David Fetter wrote:
> On Wed, May 15, 2019 at 09:32:31AM -0400, Tom Lane wrote:
>> David Fetter <david@fetter.org> writes:
>>> I hope the patch is a little easier to digest as now attached.
>>
>> To be blunt, I find 500K worth of changes in the regression test
>> outputs to be absolutely unacceptable, especially when said changes
>> are basically worthless from a diagnostic standpoint.  There are at
>> least two reasons why this won't fly:
> 
> Here's a patch set with a much smaller change.  Will that fly?

This appears to be the patch of record for this commit fest.

I don't sense much enthusiasm for this change.  What is the exact
rationale for this proposal?

I think using a new keyword EXEC that is similar to an existing one
EXECUTE will likely just introduce a new class of confusion.  (ANALYZE
EXEC EXECUTE ...?)

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services





^ permalink  raw  reply  [nested|flat] 49+ messages in thread

* Re: New EXPLAIN option: ALL
@ 2019-07-02 18:06  David Fetter <david@fetter.org>
  parent: Peter Eisentraut <peter.eisentraut@2ndquadrant.com>
  0 siblings, 0 replies; 49+ messages in thread

From: David Fetter @ 2019-07-02 18:06 UTC (permalink / raw)
  To: Peter Eisentraut <peter.eisentraut@2ndquadrant.com>; +Cc: Tom Lane <tgl@sss.pgh.pa.us>; Stephen Frost <sfrost@snowman.net>; Andres Freund <andres@anarazel.de>; pgsql-hackers

On Tue, Jul 02, 2019 at 03:06:52PM +0100, Peter Eisentraut wrote:
> On 2019-05-18 19:39, David Fetter wrote:
> > On Wed, May 15, 2019 at 09:32:31AM -0400, Tom Lane wrote:
> >> David Fetter <david@fetter.org> writes:
> >>> I hope the patch is a little easier to digest as now attached.
> >>
> >> To be blunt, I find 500K worth of changes in the regression test
> >> outputs to be absolutely unacceptable, especially when said changes
> >> are basically worthless from a diagnostic standpoint.  There are at
> >> least two reasons why this won't fly:
> > 
> > Here's a patch set with a much smaller change.  Will that fly?
> 
> This appears to be the patch of record for this commit fest.
> 
> I don't sense much enthusiasm for this change.

Neither do I, so withdrawn.

I do hope we can go with EXPLAIN and PROFILE, as opposed to
EXPLAIN/EXPLAIN ANALYZE.

Best,
David.
-- 
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate





^ permalink  raw  reply  [nested|flat] 49+ messages in thread


end of thread, other threads:[~2019-07-02 18:06 UTC | newest]

Thread overview: 49+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2019-05-07 07:30 New EXPLAIN option: ALL David Fetter <david@fetter.org>
2019-05-07 07:50 ` David Fetter <david@fetter.org>
2019-05-07 08:13   ` Sergei Kornilov <sk@zsrv.org>
2019-05-07 16:28     ` David Fetter <david@fetter.org>
2019-05-07 09:03 ` Rafia Sabih <rafia.pghackers@gmail.com>
2019-05-07 16:31   ` David Fetter <david@fetter.org>
2019-05-07 21:45     ` Peter Geoghegan <pg@bowt.ie>
2019-05-08 20:09     ` Robert Haas <robertmhaas@gmail.com>
2019-05-07 15:41 ` Andres Freund <andres@anarazel.de>
2019-05-07 16:34   ` David Fetter <david@fetter.org>
2019-05-07 16:44     ` Andres Freund <andres@anarazel.de>
2019-05-07 21:23       ` David Fetter <david@fetter.org>
2019-05-07 21:54         ` Andres Freund <andres@anarazel.de>
2019-05-07 22:06           ` Tom Lane <tgl@sss.pgh.pa.us>
2019-05-07 22:12             ` Stephen Frost <sfrost@snowman.net>
2019-05-07 22:25               ` Tom Lane <tgl@sss.pgh.pa.us>
2019-05-07 22:51                 ` Stephen Frost <sfrost@snowman.net>
2019-05-08 20:03                 ` Robert Haas <robertmhaas@gmail.com>
2019-05-13 05:51                 ` David Fetter <david@fetter.org>
2019-05-15 06:02                   ` David Fetter <david@fetter.org>
2019-05-15 13:32                     ` Tom Lane <tgl@sss.pgh.pa.us>
2019-05-15 14:20                       ` David Fetter <david@fetter.org>
2019-05-15 14:29                         ` Andres Freund <andres@anarazel.de>
2019-05-15 14:46                           ` Tom Lane <tgl@sss.pgh.pa.us>
2019-05-16 06:23                             ` Michael Paquier <michael@paquier.xyz>
2019-05-18 18:39                       ` David Fetter <david@fetter.org>
2019-07-02 14:06                         ` Peter Eisentraut <peter.eisentraut@2ndquadrant.com>
2019-07-02 18:06                           ` David Fetter <david@fetter.org>
2019-05-15 15:05                   ` Alvaro Herrera <alvherre@2ndquadrant.com>
2019-05-15 16:26                     ` Andres Freund <andres@anarazel.de>
2019-05-15 17:05                       ` Alvaro Herrera <alvherre@2ndquadrant.com>
2019-05-15 17:53                         ` Tom Lane <tgl@sss.pgh.pa.us>
2019-05-15 17:58                           ` Andres Freund <andres@anarazel.de>
2019-06-18 21:08                             ` Peter Eisentraut <peter.eisentraut@2ndquadrant.com>
2019-06-18 21:15                               ` David Fetter <david@fetter.org>
2019-06-19 06:15                                 ` Peter Eisentraut <peter.eisentraut@2ndquadrant.com>
2019-06-19 08:18                                   ` Gavin Flower <GavinFlower@archidevsys.co.nz>
2019-06-19 12:08                                   ` Daniel Gustafsson <daniel@yesql.se>
2019-06-19 14:53                                     ` David Fetter <david@fetter.org>
2019-05-21 16:32                           ` Robert Haas <robertmhaas@gmail.com>
2019-05-21 17:38                             ` David Fetter <david@fetter.org>
2019-05-21 17:47                               ` Tom Lane <tgl@sss.pgh.pa.us>
2019-05-21 18:03                               ` Robert Haas <robertmhaas@gmail.com>
2019-05-21 18:12                               ` Andres Freund <andres@anarazel.de>
2019-05-21 18:33                                 ` Tom Lane <tgl@sss.pgh.pa.us>
2019-05-07 22:39               ` David Fetter <david@fetter.org>
2019-05-07 22:58                 ` Stephen Frost <sfrost@snowman.net>
2019-05-08 21:22 ` Vik Fearing <vik.fearing@2ndquadrant.com>
2019-05-08 22:31   ` Nasby, Jim <nasbyj@amazon.com>

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox