On 17.02.2025 17:19, Robert Haas wrote:
On Mon, Feb 17, 2025 at 3:08 AM Ilia Evdokimov
<ilya.evdoki...@tantorlabs.com> wrote:
You're right—floor shouldn't be used since it behaves differently across
platforms, as Tom also pointed out earlier. I like the idea of using %,
but since the compiler doesn't allow this operation with double, we need
to cast it to int64. I checked how nloops and ntuples are modified -
they are only incremented by 1. So that the casting might be safe. If I
missed anything or if there's a reason why this casting wouldn't be
safe, please let me know.
What I've been advocating for is just:
if (nloops > 1)
Instead of:
if (nloops > 1 && rows_is_fractonal)
I don't think it's really safe to just cast a double back to int64. In
practice, the number of tuples should never be large enough to
overflow int64, but if it did, this result would be nonsense. Also, if
the double ever lost precision, the result would be nonsense. If we
want to have an exact count of tuples, we ought to change ntuples and
ntuples2 to be uint64. But I don't think we should do that in this
patch, because that adds a whole bunch of new problems to worry about
and might cause us to get nothing committed. Instead, I think we
should just always show two decimal digits if there's more than one
loop.
That's simpler than what the patch currently does and avoids this
problem. Perhaps it's objectionable for some other reason, but if so,
can somebody please spell out what that reason is so we can talk about
it?
I have no objections. I agree if we are going to transition from double
to int64, it should be done properly, but definitely not in current thread.
As for documentation changes, I'll keep t1.unique > t2.unique. If we use
equality instead, we need to explicitly show rows=1.00, which would
likely raise too many questions from users what it means.
I attached patches v11 with changes.
--
Best regards,
Ilia Evdokimov,
Tantor Labs LLC.
From 766e8bf46a415cf3c4e3a4c94a2479ea91d3e93f Mon Sep 17 00:00:00 2001
From: Ilia Evdokimov <ilya.evdoki...@tantorlabs.com>
Date: Mon, 17 Feb 2025 21:22:11 +0300
Subject: [PATCH v11 2/2] Clarify display of rows as decimal fractions
When loops > 1, the average rows value is now displayed as a decimal fraction
with two digits after the decimal point in EXPLAIN ANALYZE.
Previously, the average rows value was always rounded to an integer,
which could lead to misleading results when estimating total rows
by multiplying rows by loop. This change ensures that users
get a more accurate representation of the data flow through execution nodes.
---
doc/src/sgml/perform.sgml | 39 ++++++++++++++++++++-------------------
1 file changed, 20 insertions(+), 19 deletions(-)
diff --git a/doc/src/sgml/perform.sgml b/doc/src/sgml/perform.sgml
index a502a2aaba..588ee6d5aa 100644
--- a/doc/src/sgml/perform.sgml
+++ b/doc/src/sgml/perform.sgml
@@ -717,26 +717,26 @@ FROM tenk1 t1 WHERE t1.ten = (SELECT (random() * 10)::integer);
<screen>
EXPLAIN ANALYZE SELECT *
FROM tenk1 t1, tenk2 t2
-WHERE t1.unique1 < 10 AND t1.unique2 = t2.unique2;
+WHERE t1.thousand < 10 AND t1.unique2 > t2.unique2;
- QUERY PLAN
--------------------------------------------------------------------&zwsp;--------------------------------------------------------------
- Nested Loop (cost=4.65..118.50 rows=10 width=488) (actual time=0.017..0.051 rows=10 loops=1)
- Buffers: shared hit=36 read=6
- -> Bitmap Heap Scan on tenk1 t1 (cost=4.36..39.38 rows=10 width=244) (actual time=0.009..0.017 rows=10 loops=1)
- Recheck Cond: (unique1 < 10)
- Heap Blocks: exact=10
- Buffers: shared hit=3 read=5 written=4
- -> Bitmap Index Scan on tenk1_unique1 (cost=0.00..4.36 rows=10 width=0) (actual time=0.004..0.004 rows=10 loops=1)
- Index Cond: (unique1 < 10)
+ QUERY PLAN
+-------------------------------------------------------------------&zwsp;-------------------------------------------------------------------------
+ Nested Loop (cost=5.40..11571.44 rows=356667 width=488) (actual time=0.042..117.205 rows=513832 loops=1)
+ Buffers: shared hit=19377 read=29
+ -> Bitmap Heap Scan on tenk1 t1 (cost=5.11..233.60 rows=107 width=244) (actual time=0.021..0.103 rows=100 loops=1)
+ Recheck Cond: (thousand < 10)
+ Heap Blocks: exact=90
+ Buffers: shared hit=92
+ -> Bitmap Index Scan on tenk1_thous_tenthous (cost=0.00..5.09 rows=107 width=0) (actual time=0.010..0.010 rows=100 loops=1)
+ Index Cond: (thousand < 10)
Buffers: shared hit=2
- -> Index Scan using tenk2_unique2 on tenk2 t2 (cost=0.29..7.90 rows=1 width=244) (actual time=0.003..0.003 rows=1 loops=10)
- Index Cond: (unique2 = t1.unique2)
- Buffers: shared hit=24 read=6
+ -> Index Scan using tenk2_unique2 on tenk2 t2 (cost=0.29..72.63 rows=3333 width=244) (actual time=0.006..0.410 rows=5138.32 loops=100)
+ Index Cond: (unique2 < t1.unique2)
+ Buffers: shared hit=19285 read=29
Planning:
- Buffers: shared hit=15 dirtied=9
- Planning Time: 0.485 ms
- Execution Time: 0.073 ms
+ Buffers: shared hit=258 read=9 dirtied=2
+ Planning Time: 0.519 ms
+ Execution Time: 131.378 ms
</screen>
Note that the <quote>actual time</quote> values are in milliseconds of
@@ -756,8 +756,9 @@ WHERE t1.unique1 < 10 AND t1.unique2 = t2.unique2;
values shown are averages per-execution. This is done to make the numbers
comparable with the way that the cost estimates are shown. Multiply by
the <literal>loops</literal> value to get the total time actually spent in
- the node. In the above example, we spent a total of 0.030 milliseconds
- executing the index scans on <literal>tenk2</literal>.
+ the node, and to get the total rows processed in the node. In the above example,
+ we spent a total of 41 milliseconds executing the index scans,
+ and the node processed a total of 513832 rows on <literal>tenk2</literal>.
</para>
<para>
--
2.34.1
From 7cb3f36f3fb4db0f75a72df1caa5e3218198fa84 Mon Sep 17 00:00:00 2001
From: Ilia Evdokimov <ilya.evdoki...@tantorlabs.com>
Date: Mon, 17 Feb 2025 21:20:10 +0300
Subject: [PATCH v11 1/2] Clarify display of rows as decimal fractions
When loops > 1, the average rows value is now displayed as a decimal fraction
with two digits after the decimal point in EXPLAIN ANALYZE.
Previously, the average rows value was always rounded to an integer,
which could lead to misleading results when estimating total rows
by multiplying rows by loop. This change ensures that users
get a more accurate representation of the data flow through execution nodes.
---
src/backend/commands/explain.c | 50 +++++++----
src/test/regress/expected/explain.out | 4 +-
src/test/regress/expected/memoize.out | 86 +++++++++----------
src/test/regress/expected/partition_prune.out | 42 ++++-----
src/test/regress/expected/select_parallel.out | 24 +++---
src/test/regress/sql/partition_prune.sql | 2 +-
6 files changed, 113 insertions(+), 95 deletions(-)
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index dc4bef9ab8..ea4ae60d57 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -1981,14 +1981,15 @@ ExplainNode(PlanState *planstate, List *ancestors,
if (es->format == EXPLAIN_FORMAT_TEXT)
{
+ appendStringInfo(es->str, " (actual ");
+
if (es->timing)
- appendStringInfo(es->str,
- " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
- startup_ms, total_ms, rows, nloops);
+ appendStringInfo(es->str, "time=%.3f..%.3f ", startup_ms, total_ms);
+
+ if (nloops > 1)
+ appendStringInfo(es->str, "rows=%.2f loops=%.0f)", rows, nloops);
else
- appendStringInfo(es->str,
- " (actual rows=%.0f loops=%.0f)",
- rows, nloops);
+ appendStringInfo(es->str, "rows=%.0f loops=%.0f)", rows, nloops);
}
else
{
@@ -1999,8 +2000,16 @@ ExplainNode(PlanState *planstate, List *ancestors,
ExplainPropertyFloat("Actual Total Time", "ms", total_ms,
3, es);
}
- ExplainPropertyFloat("Actual Rows", NULL, rows, 0, es);
- ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
+ if (nloops > 1)
+ {
+ ExplainPropertyFloat("Actual Rows", NULL, rows, 2, es);
+ ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
+ }
+ else
+ {
+ ExplainPropertyFloat("Actual Rows", NULL, rows, 0, es);
+ ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
+ }
}
}
else if (es->analyze)
@@ -2052,14 +2061,14 @@ ExplainNode(PlanState *planstate, List *ancestors,
if (es->format == EXPLAIN_FORMAT_TEXT)
{
ExplainIndentText(es);
+ appendStringInfo(es->str, "actual ");
if (es->timing)
- appendStringInfo(es->str,
- "actual time=%.3f..%.3f rows=%.0f loops=%.0f\n",
- startup_ms, total_ms, rows, nloops);
+ appendStringInfo(es->str, "time=%.3f..%.3f", startup_ms, total_ms);
+
+ if (nloops > 1)
+ appendStringInfo(es->str, "rows=%.2f loops=%.0f\n", rows, nloops);
else
- appendStringInfo(es->str,
- "actual rows=%.0f loops=%.0f\n",
- rows, nloops);
+ appendStringInfo(es->str, "rows=%.0f loops=%.0f\n", rows, nloops);
}
else
{
@@ -2070,8 +2079,17 @@ ExplainNode(PlanState *planstate, List *ancestors,
ExplainPropertyFloat("Actual Total Time", "ms",
total_ms, 3, es);
}
- ExplainPropertyFloat("Actual Rows", NULL, rows, 0, es);
- ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
+
+ if (nloops > 1)
+ {
+ ExplainPropertyFloat("Actual Rows", NULL, rows, 2, es);
+ ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
+ }
+ else
+ {
+ ExplainPropertyFloat("Actual Rows", NULL, rows, 0, es);
+ ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
+ }
}
ExplainCloseWorker(n, es);
diff --git a/src/test/regress/expected/explain.out b/src/test/regress/expected/explain.out
index ee31e41d50..eb187516b3 100644
--- a/src/test/regress/expected/explain.out
+++ b/src/test/regress/expected/explain.out
@@ -528,7 +528,7 @@ select jsonb_pretty(
"Plan Rows": 0, +
"Plan Width": 0, +
"Total Cost": 0.0, +
- "Actual Rows": 0, +
+ "Actual Rows": 0.0, +
"Actual Loops": 0, +
"Startup Cost": 0.0, +
"Async Capable": false, +
@@ -575,7 +575,7 @@ select jsonb_pretty(
"Plan Rows": 0, +
"Plan Width": 0, +
"Total Cost": 0.0, +
- "Actual Rows": 0, +
+ "Actual Rows": 0.0, +
"Actual Loops": 0, +
"Startup Cost": 0.0, +
"Async Capable": false, +
diff --git a/src/test/regress/expected/memoize.out b/src/test/regress/expected/memoize.out
index 5ecf971dad..dbd01066d0 100644
--- a/src/test/regress/expected/memoize.out
+++ b/src/test/regress/expected/memoize.out
@@ -35,18 +35,18 @@ SELECT explain_memoize('
SELECT COUNT(*),AVG(t1.unique1) FROM tenk1 t1
INNER JOIN tenk1 t2 ON t1.unique1 = t2.twenty
WHERE t2.unique1 < 1000;', false);
- explain_memoize
--------------------------------------------------------------------------------------------
+ explain_memoize
+----------------------------------------------------------------------------------------------
Aggregate (actual rows=1 loops=N)
-> Nested Loop (actual rows=1000 loops=N)
-> Seq Scan on tenk1 t2 (actual rows=1000 loops=N)
Filter: (unique1 < 1000)
Rows Removed by Filter: 9000
- -> Memoize (actual rows=1 loops=N)
+ -> Memoize (actual rows=1.00 loops=N)
Cache Key: t2.twenty
Cache Mode: logical
Hits: 980 Misses: 20 Evictions: Zero Overflows: 0 Memory Usage: NkB
- -> Index Only Scan using tenk1_unique1 on tenk1 t1 (actual rows=1 loops=N)
+ -> Index Only Scan using tenk1_unique1 on tenk1 t1 (actual rows=1.00 loops=N)
Index Cond: (unique1 = t2.twenty)
Heap Fetches: N
(12 rows)
@@ -66,18 +66,18 @@ SELECT COUNT(*),AVG(t2.unique1) FROM tenk1 t1,
LATERAL (SELECT t2.unique1 FROM tenk1 t2
WHERE t1.twenty = t2.unique1 OFFSET 0) t2
WHERE t1.unique1 < 1000;', false);
- explain_memoize
--------------------------------------------------------------------------------------------
+ explain_memoize
+----------------------------------------------------------------------------------------------
Aggregate (actual rows=1 loops=N)
-> Nested Loop (actual rows=1000 loops=N)
-> Seq Scan on tenk1 t1 (actual rows=1000 loops=N)
Filter: (unique1 < 1000)
Rows Removed by Filter: 9000
- -> Memoize (actual rows=1 loops=N)
+ -> Memoize (actual rows=1.00 loops=N)
Cache Key: t1.twenty
Cache Mode: binary
Hits: 980 Misses: 20 Evictions: Zero Overflows: 0 Memory Usage: NkB
- -> Index Only Scan using tenk1_unique1 on tenk1 t2 (actual rows=1 loops=N)
+ -> Index Only Scan using tenk1_unique1 on tenk1 t2 (actual rows=1.00 loops=N)
Index Cond: (unique1 = t1.twenty)
Heap Fetches: N
(12 rows)
@@ -100,20 +100,20 @@ LATERAL (
) t2
ON t1.two = t2.two
WHERE t1.unique1 < 10;', false);
- explain_memoize
-----------------------------------------------------------------------------------------------
+ explain_memoize
+-------------------------------------------------------------------------------------------------
Aggregate (actual rows=1 loops=N)
-> Nested Loop Left Join (actual rows=20 loops=N)
-> Index Scan using tenk1_unique1 on tenk1 t1 (actual rows=10 loops=N)
Index Cond: (unique1 < 10)
- -> Memoize (actual rows=2 loops=N)
+ -> Memoize (actual rows=2.00 loops=N)
Cache Key: t1.two
Cache Mode: binary
Hits: 8 Misses: 2 Evictions: Zero Overflows: 0 Memory Usage: NkB
- -> Subquery Scan on t2 (actual rows=2 loops=N)
+ -> Subquery Scan on t2 (actual rows=2.00 loops=N)
Filter: (t1.two = t2.two)
Rows Removed by Filter: 2
- -> Index Scan using tenk1_unique1 on tenk1 t2_1 (actual rows=4 loops=N)
+ -> Index Scan using tenk1_unique1 on tenk1 t2_1 (actual rows=4.00 loops=N)
Index Cond: (unique1 < 4)
(13 rows)
@@ -134,18 +134,18 @@ SELECT explain_memoize('
SELECT COUNT(*), AVG(t1.twenty) FROM tenk1 t1 LEFT JOIN
LATERAL (SELECT t1.two+1 AS c1, t2.unique1 AS c2 FROM tenk1 t2) s ON TRUE
WHERE s.c1 = s.c2 AND t1.unique1 < 1000;', false);
- explain_memoize
--------------------------------------------------------------------------------------------
+ explain_memoize
+----------------------------------------------------------------------------------------------
Aggregate (actual rows=1 loops=N)
-> Nested Loop (actual rows=1000 loops=N)
-> Seq Scan on tenk1 t1 (actual rows=1000 loops=N)
Filter: (unique1 < 1000)
Rows Removed by Filter: 9000
- -> Memoize (actual rows=1 loops=N)
+ -> Memoize (actual rows=1.00 loops=N)
Cache Key: (t1.two + 1)
Cache Mode: binary
Hits: 998 Misses: 2 Evictions: Zero Overflows: 0 Memory Usage: NkB
- -> Index Only Scan using tenk1_unique1 on tenk1 t2 (actual rows=1 loops=N)
+ -> Index Only Scan using tenk1_unique1 on tenk1 t2 (actual rows=1.00 loops=N)
Filter: ((t1.two + 1) = unique1)
Rows Removed by Filter: 9999
Heap Fetches: N
@@ -173,11 +173,11 @@ WHERE s.c1 = s.c2 AND t1.unique1 < 1000;', false);
-> Seq Scan on tenk1 t1 (actual rows=1000 loops=N)
Filter: (unique1 < 1000)
Rows Removed by Filter: 9000
- -> Memoize (actual rows=1 loops=N)
+ -> Memoize (actual rows=1.00 loops=N)
Cache Key: t1.two, t1.twenty
Cache Mode: binary
Hits: 980 Misses: 20 Evictions: Zero Overflows: 0 Memory Usage: NkB
- -> Seq Scan on tenk1 t2 (actual rows=1 loops=N)
+ -> Seq Scan on tenk1 t2 (actual rows=1.00 loops=N)
Filter: ((t1.twenty = unique1) AND (t1.two = two))
Rows Removed by Filter: 9999
(12 rows)
@@ -207,15 +207,15 @@ VACUUM ANALYZE expr_key;
SELECT explain_memoize('
SELECT * FROM expr_key t1 INNER JOIN expr_key t2
ON t1.x = t2.t::numeric AND t1.t::numeric = t2.x;', false);
- explain_memoize
--------------------------------------------------------------------------------------------
+ explain_memoize
+----------------------------------------------------------------------------------------------
Nested Loop (actual rows=80 loops=N)
-> Seq Scan on expr_key t1 (actual rows=40 loops=N)
- -> Memoize (actual rows=2 loops=N)
+ -> Memoize (actual rows=2.00 loops=N)
Cache Key: t1.x, (t1.t)::numeric
Cache Mode: logical
Hits: 20 Misses: 20 Evictions: Zero Overflows: 0 Memory Usage: NkB
- -> Index Only Scan using expr_key_idx_x_t on expr_key t2 (actual rows=2 loops=N)
+ -> Index Only Scan using expr_key_idx_x_t on expr_key t2 (actual rows=2.00 loops=N)
Index Cond: (x = (t1.t)::numeric)
Filter: (t1.x = (t)::numeric)
Heap Fetches: N
@@ -232,18 +232,18 @@ SELECT explain_memoize('
SELECT COUNT(*),AVG(t1.unique1) FROM tenk1 t1
INNER JOIN tenk1 t2 ON t1.unique1 = t2.thousand
WHERE t2.unique1 < 1200;', true);
- explain_memoize
--------------------------------------------------------------------------------------------
+ explain_memoize
+----------------------------------------------------------------------------------------------
Aggregate (actual rows=1 loops=N)
-> Nested Loop (actual rows=1200 loops=N)
-> Seq Scan on tenk1 t2 (actual rows=1200 loops=N)
Filter: (unique1 < 1200)
Rows Removed by Filter: 8800
- -> Memoize (actual rows=1 loops=N)
+ -> Memoize (actual rows=1.00 loops=N)
Cache Key: t2.thousand
Cache Mode: logical
Hits: N Misses: N Evictions: N Overflows: 0 Memory Usage: NkB
- -> Index Only Scan using tenk1_unique1 on tenk1 t1 (actual rows=1 loops=N)
+ -> Index Only Scan using tenk1_unique1 on tenk1 t1 (actual rows=1.00 loops=N)
Index Cond: (unique1 = t2.thousand)
Heap Fetches: N
(12 rows)
@@ -261,7 +261,7 @@ SELECT * FROM flt f1 INNER JOIN flt f2 ON f1.f = f2.f;', false);
Nested Loop (actual rows=4 loops=N)
-> Index Only Scan using flt_f_idx on flt f1 (actual rows=2 loops=N)
Heap Fetches: N
- -> Memoize (actual rows=2 loops=N)
+ -> Memoize (actual rows=2.00 loops=N)
Cache Key: f1.f
Cache Mode: logical
Hits: 1 Misses: 1 Evictions: Zero Overflows: 0 Memory Usage: NkB
@@ -273,16 +273,16 @@ SELECT * FROM flt f1 INNER JOIN flt f2 ON f1.f = f2.f;', false);
-- Ensure memoize operates in binary mode
SELECT explain_memoize('
SELECT * FROM flt f1 INNER JOIN flt f2 ON f1.f >= f2.f;', false);
- explain_memoize
--------------------------------------------------------------------------------
+ explain_memoize
+----------------------------------------------------------------------------------
Nested Loop (actual rows=4 loops=N)
-> Index Only Scan using flt_f_idx on flt f1 (actual rows=2 loops=N)
Heap Fetches: N
- -> Memoize (actual rows=2 loops=N)
+ -> Memoize (actual rows=2.00 loops=N)
Cache Key: f1.f
Cache Mode: binary
Hits: 0 Misses: 2 Evictions: Zero Overflows: 0 Memory Usage: NkB
- -> Index Only Scan using flt_f_idx on flt f2 (actual rows=2 loops=N)
+ -> Index Only Scan using flt_f_idx on flt f2 (actual rows=2.00 loops=N)
Index Cond: (f <= f1.f)
Heap Fetches: N
(10 rows)
@@ -300,32 +300,32 @@ ANALYZE strtest;
-- Ensure we get 3 hits and 3 misses
SELECT explain_memoize('
SELECT * FROM strtest s1 INNER JOIN strtest s2 ON s1.n >= s2.n;', false);
- explain_memoize
-----------------------------------------------------------------------------------
+ explain_memoize
+-------------------------------------------------------------------------------------
Nested Loop (actual rows=24 loops=N)
-> Seq Scan on strtest s1 (actual rows=6 loops=N)
Disabled: true
- -> Memoize (actual rows=4 loops=N)
+ -> Memoize (actual rows=4.00 loops=N)
Cache Key: s1.n
Cache Mode: binary
Hits: 3 Misses: 3 Evictions: Zero Overflows: 0 Memory Usage: NkB
- -> Index Scan using strtest_n_idx on strtest s2 (actual rows=4 loops=N)
+ -> Index Scan using strtest_n_idx on strtest s2 (actual rows=4.00 loops=N)
Index Cond: (n <= s1.n)
(9 rows)
-- Ensure we get 3 hits and 3 misses
SELECT explain_memoize('
SELECT * FROM strtest s1 INNER JOIN strtest s2 ON s1.t >= s2.t;', false);
- explain_memoize
-----------------------------------------------------------------------------------
+ explain_memoize
+-------------------------------------------------------------------------------------
Nested Loop (actual rows=24 loops=N)
-> Seq Scan on strtest s1 (actual rows=6 loops=N)
Disabled: true
- -> Memoize (actual rows=4 loops=N)
+ -> Memoize (actual rows=4.00 loops=N)
Cache Key: s1.t
Cache Mode: binary
Hits: 3 Misses: 3 Evictions: Zero Overflows: 0 Memory Usage: NkB
- -> Index Scan using strtest_t_idx on strtest s2 (actual rows=4 loops=N)
+ -> Index Scan using strtest_t_idx on strtest s2 (actual rows=4.00 loops=N)
Index Cond: (t <= s1.t)
(9 rows)
@@ -348,7 +348,7 @@ SELECT * FROM prt t1 INNER JOIN prt t2 ON t1.a = t2.a;', false);
-> Nested Loop (actual rows=16 loops=N)
-> Index Only Scan using iprt_p1_a on prt_p1 t1_1 (actual rows=4 loops=N)
Heap Fetches: N
- -> Memoize (actual rows=4 loops=N)
+ -> Memoize (actual rows=4.00 loops=N)
Cache Key: t1_1.a
Cache Mode: logical
Hits: 3 Misses: 1 Evictions: Zero Overflows: 0 Memory Usage: NkB
@@ -358,7 +358,7 @@ SELECT * FROM prt t1 INNER JOIN prt t2 ON t1.a = t2.a;', false);
-> Nested Loop (actual rows=16 loops=N)
-> Index Only Scan using iprt_p2_a on prt_p2 t1_2 (actual rows=4 loops=N)
Heap Fetches: N
- -> Memoize (actual rows=4 loops=N)
+ -> Memoize (actual rows=4.00 loops=N)
Cache Key: t1_2.a
Cache Mode: logical
Hits: 3 Misses: 1 Evictions: Zero Overflows: 0 Memory Usage: NkB
@@ -378,7 +378,7 @@ ON t1.a = t2.a;', false);
Nested Loop (actual rows=16 loops=N)
-> Index Only Scan using iprt_p1_a on prt_p1 t1 (actual rows=4 loops=N)
Heap Fetches: N
- -> Memoize (actual rows=4 loops=N)
+ -> Memoize (actual rows=4.00 loops=N)
Cache Key: t1.a
Cache Mode: logical
Hits: 3 Misses: 1 Evictions: Zero Overflows: 0 Memory Usage: NkB
diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out
index 6f80b62a3b..1dbe6ff54f 100644
--- a/src/test/regress/expected/partition_prune.out
+++ b/src/test/regress/expected/partition_prune.out
@@ -2367,7 +2367,7 @@ begin
$1)
loop
ln := regexp_replace(ln, 'Workers Launched: \d+', 'Workers Launched: N');
- ln := regexp_replace(ln, 'actual rows=\d+ loops=\d+', 'actual rows=N loops=N');
+ ln := regexp_replace(ln, 'actual rows=\d+(?:\.\d+)? loops=\d+', 'actual rows=N loops=N');
ln := regexp_replace(ln, 'Rows Removed by Filter: \d+', 'Rows Removed by Filter: N');
return next ln;
end loop;
@@ -2940,7 +2940,7 @@ update ab_a1 set b = 3 from ab_a2 where ab_a2.b = (select 1);');
-> Seq Scan on ab_a1_b1 ab_a1_1 (actual rows=1 loops=1)
-> Seq Scan on ab_a1_b2 ab_a1_2 (actual rows=1 loops=1)
-> Seq Scan on ab_a1_b3 ab_a1_3 (actual rows=1 loops=1)
- -> Materialize (actual rows=1 loops=3)
+ -> Materialize (actual rows=1.00 loops=3)
Storage: Memory Maximum Storage: NkB
-> Append (actual rows=1 loops=1)
-> Seq Scan on ab_a2_b1 ab_a2_1 (actual rows=1 loops=1)
@@ -2983,12 +2983,12 @@ set enable_hashjoin = off;
set enable_mergejoin = off;
explain (analyze, costs off, summary off, timing off, buffers off)
select * from tbl1 join tprt on tbl1.col1 > tprt.col1;
- QUERY PLAN
---------------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------------------------
Nested Loop (actual rows=6 loops=1)
-> Seq Scan on tbl1 (actual rows=2 loops=1)
- -> Append (actual rows=3 loops=2)
- -> Index Scan using tprt1_idx on tprt_1 (actual rows=2 loops=2)
+ -> Append (actual rows=3.00 loops=2)
+ -> Index Scan using tprt1_idx on tprt_1 (actual rows=2.00 loops=2)
Index Cond: (col1 < tbl1.col1)
-> Index Scan using tprt2_idx on tprt_2 (actual rows=2 loops=1)
Index Cond: (col1 < tbl1.col1)
@@ -3004,14 +3004,14 @@ select * from tbl1 join tprt on tbl1.col1 > tprt.col1;
explain (analyze, costs off, summary off, timing off, buffers off)
select * from tbl1 join tprt on tbl1.col1 = tprt.col1;
- QUERY PLAN
---------------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------------------------
Nested Loop (actual rows=2 loops=1)
-> Seq Scan on tbl1 (actual rows=2 loops=1)
- -> Append (actual rows=1 loops=2)
+ -> Append (actual rows=1.00 loops=2)
-> 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 Scan using tprt2_idx on tprt_2 (actual rows=1.00 loops=2)
Index Cond: (col1 = tbl1.col1)
-> Index Scan using tprt3_idx on tprt_3 (never executed)
Index Cond: (col1 = tbl1.col1)
@@ -3049,16 +3049,16 @@ order by tbl1.col1, tprt.col1;
insert into tbl1 values (1001), (1010), (1011);
explain (analyze, costs off, summary off, timing off, buffers off)
select * from tbl1 inner join tprt on tbl1.col1 > tprt.col1;
- QUERY PLAN
---------------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------------------------
Nested Loop (actual rows=23 loops=1)
-> Seq Scan on tbl1 (actual rows=5 loops=1)
- -> Append (actual rows=5 loops=5)
- -> Index Scan using tprt1_idx on tprt_1 (actual rows=2 loops=5)
+ -> Append (actual rows=4.60 loops=5)
+ -> Index Scan using tprt1_idx on tprt_1 (actual rows=2.00 loops=5)
Index Cond: (col1 < tbl1.col1)
- -> Index Scan using tprt2_idx on tprt_2 (actual rows=3 loops=4)
+ -> Index Scan using tprt2_idx on tprt_2 (actual rows=2.75 loops=4)
Index Cond: (col1 < tbl1.col1)
- -> Index Scan using tprt3_idx on tprt_3 (actual rows=1 loops=2)
+ -> Index Scan using tprt3_idx on tprt_3 (actual rows=1.00 loops=2)
Index Cond: (col1 < tbl1.col1)
-> Index Scan using tprt4_idx on tprt_4 (never executed)
Index Cond: (col1 < tbl1.col1)
@@ -3070,16 +3070,16 @@ select * from tbl1 inner join tprt on tbl1.col1 > tprt.col1;
explain (analyze, costs off, summary off, timing off, buffers off)
select * from tbl1 inner join tprt on tbl1.col1 = tprt.col1;
- QUERY PLAN
---------------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------------------------
Nested Loop (actual rows=3 loops=1)
-> Seq Scan on tbl1 (actual rows=5 loops=1)
- -> Append (actual rows=1 loops=5)
+ -> Append (actual rows=0.60 loops=5)
-> 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 Scan using tprt2_idx on tprt_2 (actual rows=1.00 loops=2)
Index Cond: (col1 = tbl1.col1)
- -> Index Scan using tprt3_idx on tprt_3 (actual rows=0 loops=3)
+ -> Index Scan using tprt3_idx on tprt_3 (actual rows=0.33 loops=3)
Index Cond: (col1 = tbl1.col1)
-> Index Scan using tprt4_idx on tprt_4 (never executed)
Index Cond: (col1 = tbl1.col1)
diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out
index a809036453..4732ad6bfb 100644
--- a/src/test/regress/expected/select_parallel.out
+++ b/src/test/regress/expected/select_parallel.out
@@ -583,17 +583,17 @@ alter table tenk2 set (parallel_workers = 0);
explain (analyze, timing off, summary off, costs off, buffers off)
select count(*) from tenk1, tenk2 where tenk1.hundred > 1
and tenk2.thousand=0;
- QUERY PLAN
---------------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Nested Loop (actual rows=98000 loops=1)
-> Seq Scan on tenk2 (actual rows=10 loops=1)
Filter: (thousand = 0)
Rows Removed by Filter: 9990
- -> Gather (actual rows=9800 loops=10)
+ -> Gather (actual rows=9800.00 loops=10)
Workers Planned: 4
Workers Launched: 4
- -> Parallel Seq Scan on tenk1 (actual rows=1960 loops=50)
+ -> Parallel Seq Scan on tenk1 (actual rows=1960.00 loops=50)
Filter: (hundred > 1)
Rows Removed by Filter: 40
(11 rows)
@@ -617,21 +617,21 @@ 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)
-> Values Scan on "*VALUES*" (actual rows=3 loops=1)
- -> Gather Merge (actual rows=10000 loops=3)
+ -> Gather Merge (actual rows=10000.00 loops=3)
Workers Planned: 4
Workers Launched: 4
- -> Sort (actual rows=2000 loops=15)
+ -> Sort (actual rows=2000.00 loops=15)
Sort Key: tenk1.ten
Sort Method: quicksort Memory: xxx
Worker 0: Sort Method: quicksort Memory: xxx
Worker 1: Sort Method: quicksort Memory: xxx
Worker 2: Sort Method: quicksort Memory: xxx
Worker 3: Sort Method: quicksort Memory: xxx
- -> Parallel Seq Scan on tenk1 (actual rows=2000 loops=15)
+ -> Parallel Seq Scan on tenk1 (actual rows=2000.00 loops=15)
Filter: (ten < 100)
(14 rows)
@@ -1170,12 +1170,12 @@ explain (costs off)
SAVEPOINT settings;
SET LOCAL debug_parallel_query = 1;
EXPLAIN (analyze, timing off, summary off, costs off, buffers off) SELECT * FROM tenk1;
- QUERY PLAN
--------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------------------------
Gather (actual rows=10000 loops=1)
Workers Planned: 4
Workers Launched: 4
- -> Parallel Seq Scan on tenk1 (actual rows=2000 loops=5)
+ -> Parallel Seq Scan on tenk1 (actual rows=2000.00 loops=5)
(4 rows)
ROLLBACK TO SAVEPOINT settings;
diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql
index 86621dcec0..6aad02156c 100644
--- a/src/test/regress/sql/partition_prune.sql
+++ b/src/test/regress/sql/partition_prune.sql
@@ -586,7 +586,7 @@ begin
$1)
loop
ln := regexp_replace(ln, 'Workers Launched: \d+', 'Workers Launched: N');
- ln := regexp_replace(ln, 'actual rows=\d+ loops=\d+', 'actual rows=N loops=N');
+ ln := regexp_replace(ln, 'actual rows=\d+(?:\.\d+)? loops=\d+', 'actual rows=N loops=N');
ln := regexp_replace(ln, 'Rows Removed by Filter: \d+', 'Rows Removed by Filter: N');
return next ln;
end loop;
--
2.34.1