Commit 5f86cbd7 authored by Tom Lane's avatar Tom Lane

Rename EXPLAIN ANALYZE's "total runtime" output to "execution time".

Now that EXPLAIN also outputs a "planning time" measurement, the use of
"total" here seems rather confusing: it sounds like it might include the
planning time which of course it doesn't.  Majority opinion was that
"execution time" is a better label, so we'll call it that.

This should be noted as a backwards incompatibility for tools that examine
EXPLAIN ANALYZE output.

In passing, I failed to resist the temptation to do a little editing on the
materialized-view example affected by this change.
parent e183d112
...@@ -584,7 +584,7 @@ WHERE t1.unique1 < 10 AND t1.unique2 = t2.unique2; ...@@ -584,7 +584,7 @@ WHERE t1.unique1 < 10 AND t1.unique2 = t2.unique2;
-> Index Scan using tenk2_unique2 on tenk2 t2 (cost=0.29..7.91 rows=1 width=244) (actual time=0.021..0.022 rows=1 loops=10) -> Index Scan using tenk2_unique2 on tenk2 t2 (cost=0.29..7.91 rows=1 width=244) (actual time=0.021..0.022 rows=1 loops=10)
Index Cond: (unique2 = t1.unique2) Index Cond: (unique2 = t1.unique2)
Planning time: 0.181 ms Planning time: 0.181 ms
Total runtime: 0.501 ms Execution time: 0.501 ms
</screen> </screen>
Note that the <quote>actual time</quote> values are in milliseconds of Note that the <quote>actual time</quote> values are in milliseconds of
...@@ -633,7 +633,7 @@ WHERE t1.unique1 &lt; 100 AND t1.unique2 = t2.unique2 ORDER BY t1.fivethous; ...@@ -633,7 +633,7 @@ WHERE t1.unique1 &lt; 100 AND t1.unique2 = t2.unique2 ORDER BY t1.fivethous;
-&gt; Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=101 width=0) (actual time=0.049..0.049 rows=100 loops=1) -&gt; Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=101 width=0) (actual time=0.049..0.049 rows=100 loops=1)
Index Cond: (unique1 &lt; 100) Index Cond: (unique1 &lt; 100)
Planning time: 0.194 ms Planning time: 0.194 ms
Total runtime: 8.008 ms Execution time: 8.008 ms
</screen> </screen>
The Sort node shows the sort method used (in particular, whether the sort The Sort node shows the sort method used (in particular, whether the sort
...@@ -657,7 +657,7 @@ EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE ten &lt; 7; ...@@ -657,7 +657,7 @@ EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE ten &lt; 7;
Filter: (ten &lt; 7) Filter: (ten &lt; 7)
Rows Removed by Filter: 3000 Rows Removed by Filter: 3000
Planning time: 0.083 ms Planning time: 0.083 ms
Total runtime: 5.905 ms Execution time: 5.905 ms
</screen> </screen>
These counts can be particularly valuable for filter conditions applied at These counts can be particularly valuable for filter conditions applied at
...@@ -680,7 +680,7 @@ EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; ...@@ -680,7 +680,7 @@ EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)';
Filter: (f1 @&gt; '((0.5,2))'::polygon) Filter: (f1 @&gt; '((0.5,2))'::polygon)
Rows Removed by Filter: 4 Rows Removed by Filter: 4
Planning time: 0.040 ms Planning time: 0.040 ms
Total runtime: 0.083 ms Execution time: 0.083 ms
</screen> </screen>
The planner thinks (quite correctly) that this sample table is too small The planner thinks (quite correctly) that this sample table is too small
...@@ -699,7 +699,7 @@ EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)'; ...@@ -699,7 +699,7 @@ EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @&gt; polygon '(0.5,2.0)';
Index Cond: (f1 @&gt; '((0.5,2))'::polygon) Index Cond: (f1 @&gt; '((0.5,2))'::polygon)
Rows Removed by Index Recheck: 1 Rows Removed by Index Recheck: 1
Planning time: 0.034 ms Planning time: 0.034 ms
Total runtime: 0.144 ms Execution time: 0.144 ms
</screen> </screen>
Here we can see that the index returned one candidate row, which was Here we can see that the index returned one candidate row, which was
...@@ -730,7 +730,7 @@ EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique ...@@ -730,7 +730,7 @@ EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique
Index Cond: (unique2 &gt; 9000) Index Cond: (unique2 &gt; 9000)
Buffers: shared hit=5 Buffers: shared hit=5
Planning time: 0.088 ms Planning time: 0.088 ms
Total runtime: 0.423 ms Execution time: 0.423 ms
</screen> </screen>
The numbers provided by <literal>BUFFERS</> help to identify which parts The numbers provided by <literal>BUFFERS</> help to identify which parts
...@@ -758,7 +758,7 @@ EXPLAIN ANALYZE UPDATE tenk1 SET hundred = hundred + 1 WHERE unique1 &lt; 100; ...@@ -758,7 +758,7 @@ EXPLAIN ANALYZE UPDATE tenk1 SET hundred = hundred + 1 WHERE unique1 &lt; 100;
-&gt; Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=101 width=0) (actual time=0.043..0.043 rows=100 loops=1) -&gt; Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=101 width=0) (actual time=0.043..0.043 rows=100 loops=1)
Index Cond: (unique1 &lt; 100) Index Cond: (unique1 &lt; 100)
Planning time: 0.079 ms Planning time: 0.079 ms
Total runtime: 14.727 ms Execution time: 14.727 ms
ROLLBACK; ROLLBACK;
</screen> </screen>
...@@ -781,7 +781,7 @@ ROLLBACK; ...@@ -781,7 +781,7 @@ ROLLBACK;
</para> </para>
<para> <para>
The <literal>Total runtime</literal> shown by <command>EXPLAIN The <literal>Execution time</literal> shown by <command>EXPLAIN
ANALYZE</command> includes executor start-up and shut-down time, as well ANALYZE</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 as the time to run any triggers that are fired, but it does not include
parsing, rewriting, or planning time. parsing, rewriting, or planning time.
...@@ -792,7 +792,7 @@ ROLLBACK; ...@@ -792,7 +792,7 @@ ROLLBACK;
The total time spent in each trigger The total time spent in each trigger
(either <literal>BEFORE</> or <literal>AFTER</>) is also shown separately. (either <literal>BEFORE</> or <literal>AFTER</>) is also shown separately.
Note that deferred constraint triggers will not be executed Note that deferred constraint triggers will not be executed
until end of transaction and are thus not shown at all by until end of transaction and are thus not considered at all by
<command>EXPLAIN ANALYZE</command>. <command>EXPLAIN ANALYZE</command>.
</para> </para>
...@@ -844,7 +844,7 @@ EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000 ...@@ -844,7 +844,7 @@ EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000
Filter: (unique1 &lt; 100) Filter: (unique1 &lt; 100)
Rows Removed by Filter: 287 Rows Removed by Filter: 287
Planning time: 0.096 ms Planning time: 0.096 ms
Total runtime: 0.336 ms Execution time: 0.336 ms
</screen> </screen>
the estimated cost and row count for the Index Scan node are shown as the estimated cost and row count for the Index Scan node are shown as
......
...@@ -408,7 +408,7 @@ EXPLAIN ANALYZE EXECUTE query(100, 200); ...@@ -408,7 +408,7 @@ EXPLAIN ANALYZE EXECUTE query(100, 200);
-&gt; Index Scan using test_pkey on test (cost=0.29..9.29 rows=50 width=8) (actual time=0.039..0.091 rows=99 loops=1) -&gt; Index Scan using test_pkey on test (cost=0.29..9.29 rows=50 width=8) (actual time=0.039..0.091 rows=99 loops=1)
Index Cond: ((id &gt; $1) AND (id &lt; $2)) Index Cond: ((id &gt; $1) AND (id &lt; $2))
Planning time: 0.197 ms Planning time: 0.197 ms
Total runtime: 0.225 ms Execution time: 0.225 ms
(5 rows) (5 rows)
</programlisting> </programlisting>
</para> </para>
......
...@@ -993,11 +993,17 @@ REFRESH MATERIALIZED VIEW sales_summary; ...@@ -993,11 +993,17 @@ REFRESH MATERIALIZED VIEW sales_summary;
<para> <para>
Another use for a materialized view is to allow faster access to data Another use for a materialized view is to allow faster access to data
brought across from a remote system, through a foreign data wrapper. brought across from a remote system through a foreign data wrapper.
A simple example using <literal>file_fdw</literal> is below, with timings, A simple example using <literal>file_fdw</literal> is below, with timings,
but since this is using cache on the local system the performance but since this is using cache on the local system the performance
difference on a foreign data wrapper to a remote system could be greater. difference compared to access to a remote system would usually be greater
than shown here. Notice we are also exploiting the ability to put an
index on the materialized view, whereas <literal>file_fdw</literal> does
not support indexes; this advantage might not apply for other sorts of
foreign data access.
</para>
<para>
Setup: Setup:
<programlisting> <programlisting>
...@@ -1005,7 +1011,7 @@ CREATE EXTENSION file_fdw; ...@@ -1005,7 +1011,7 @@ CREATE EXTENSION file_fdw;
CREATE SERVER local_file FOREIGN DATA WRAPPER file_fdw; CREATE SERVER local_file FOREIGN DATA WRAPPER file_fdw;
CREATE FOREIGN TABLE words (word text NOT NULL) CREATE FOREIGN TABLE words (word text NOT NULL)
SERVER local_file SERVER local_file
OPTIONS (filename '/etc/dictionaries-common/words'); OPTIONS (filename '/usr/share/dict/words');
CREATE MATERIALIZED VIEW wrd AS SELECT * FROM words; CREATE MATERIALIZED VIEW wrd AS SELECT * FROM words;
CREATE UNIQUE INDEX wrd_word ON wrd (word); CREATE UNIQUE INDEX wrd_word ON wrd (word);
CREATE EXTENSION pg_trgm; CREATE EXTENSION pg_trgm;
...@@ -1024,26 +1030,28 @@ SELECT count(*) FROM words WHERE word = 'caterpiler'; ...@@ -1024,26 +1030,28 @@ SELECT count(*) FROM words WHERE word = 'caterpiler';
(1 row) (1 row)
</programlisting> </programlisting>
The plan is: With <command>EXPLAIN ANALYZE</>, we see:
<programlisting> <programlisting>
Aggregate (cost=4125.19..4125.20 rows=1 width=0) (actual time=26.013..26.014 rows=1 loops=1) Aggregate (cost=21763.99..21764.00 rows=1 width=0) (actual time=188.180..188.181 rows=1 loops=1)
-> Foreign Scan on words (cost=0.00..4124.70 rows=196 width=0) (actual time=26.011..26.011 rows=0 loops=1) -&gt; Foreign Scan on words (cost=0.00..21761.41 rows=1032 width=0) (actual time=188.177..188.177 rows=0 loops=1)
Filter: (word = 'caterpiler'::text) Filter: (word = 'caterpiler'::text)
Rows Removed by Filter: 99171 Rows Removed by Filter: 479829
Foreign File: /etc/dictionaries-common/words Foreign File: /usr/share/dict/words
Foreign File Size: 938848 Foreign File Size: 4953699
Total runtime: 26.081 ms Planning time: 0.118 ms
Execution time: 188.273 ms
</programlisting> </programlisting>
If the materialized view is used instead, the query is much faster: If the materialized view is used instead, the query is much faster:
<programlisting> <programlisting>
Aggregate (cost=4.44..4.45 rows=1 width=0) (actual time=0.074..0.074 rows=1 loops=1) Aggregate (cost=4.44..4.45 rows=1 width=0) (actual time=0.042..0.042 rows=1 loops=1)
-> Index Only Scan using wrd_word on wrd (cost=0.42..4.44 rows=1 width=0) (actual time=0.071..0.071 rows=0 loops=1) -&gt; Index Only Scan using wrd_word on wrd (cost=0.42..4.44 rows=1 width=0) (actual time=0.039..0.039 rows=0 loops=1)
Index Cond: (word = 'caterpiler'::text) Index Cond: (word = 'caterpiler'::text)
Heap Fetches: 0 Heap Fetches: 0
Total runtime: 0.119 ms Planning time: 0.164 ms
Execution time: 0.117 ms
</programlisting> </programlisting>
Either way, the word is spelled wrong, so let's look for what we might Either way, the word is spelled wrong, so let's look for what we might
...@@ -1068,23 +1076,25 @@ SELECT word FROM words ORDER BY word <-> 'caterpiler' LIMIT 10; ...@@ -1068,23 +1076,25 @@ SELECT word FROM words ORDER BY word <-> 'caterpiler' LIMIT 10;
</programlisting> </programlisting>
<programlisting> <programlisting>
Limit (cost=2195.70..2195.72 rows=10 width=32) (actual time=218.904..218.906 rows=10 loops=1) Limit (cost=11583.61..11583.64 rows=10 width=32) (actual time=1431.591..1431.594 rows=10 loops=1)
-> Sort (cost=2195.70..2237.61 rows=16765 width=32) (actual time=218.902..218.904 rows=10 loops=1) -&gt; Sort (cost=11583.61..11804.76 rows=88459 width=32) (actual time=1431.589..1431.591 rows=10 loops=1)
Sort Key: ((word <-> 'caterpiler'::text)) Sort Key: ((word &lt;-&gt; 'caterpiler'::text))
Sort Method: top-N heapsort Memory: 25kB Sort Method: top-N heapsort Memory: 25kB
-> Foreign Scan on words (cost=0.00..1833.41 rows=16765 width=32) (actual time=0.046..200.965 rows=99171 loops=1) -&gt; Foreign Scan on words (cost=0.00..9672.05 rows=88459 width=32) (actual time=0.057..1286.455 rows=479829 loops=1)
Foreign File: /etc/dictionaries-common/words Foreign File: /usr/share/dict/words
Foreign File Size: 938848 Foreign File Size: 4953699
Total runtime: 218.966 ms Planning time: 0.128 ms
Execution time: 1431.679 ms
</programlisting> </programlisting>
Using the materialized view: Using the materialized view:
<programlisting> <programlisting>
Limit (cost=0.28..1.02 rows=10 width=9) (actual time=24.916..25.079 rows=10 loops=1) Limit (cost=0.29..1.06 rows=10 width=10) (actual time=187.222..188.257 rows=10 loops=1)
-> Index Scan using wrd_trgm on wrd (cost=0.28..7383.70 rows=99171 width=9) (actual time=24.914..25.076 rows=10 loops=1) -&gt; Index Scan using wrd_trgm on wrd (cost=0.29..37020.87 rows=479829 width=10) (actual time=187.219..188.252 rows=10 loops=1)
Order By: (word <-> 'caterpiler'::text) Order By: (word &lt;-&gt; 'caterpiler'::text)
Total runtime: 25.884 ms Planning time: 0.196 ms
Execution time: 198.640 ms
</programlisting> </programlisting>
If you can tolerate periodic update of the remote data to the local If you can tolerate periodic update of the remote data to the local
......
...@@ -508,7 +508,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, ...@@ -508,7 +508,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
/* /*
* Close down the query and free resources. Include time for this in the * Close down the query and free resources. Include time for this in the
* total runtime (although it should be pretty minimal). * total execution time (although it should be pretty minimal).
*/ */
INSTR_TIME_SET_CURRENT(starttime); INSTR_TIME_SET_CURRENT(starttime);
...@@ -527,10 +527,10 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, ...@@ -527,10 +527,10 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
if (es->analyze) if (es->analyze)
{ {
if (es->format == EXPLAIN_FORMAT_TEXT) if (es->format == EXPLAIN_FORMAT_TEXT)
appendStringInfo(es->str, "Total runtime: %.3f ms\n", appendStringInfo(es->str, "Execution time: %.3f ms\n",
1000.0 * totaltime); 1000.0 * totaltime);
else else
ExplainPropertyFloat("Total Runtime", 1000.0 * totaltime, ExplainPropertyFloat("Execution Time", 1000.0 * totaltime,
3, es); 3, es);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment