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
{
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)
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
{
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);
"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, +
"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, +
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)
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)
) 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)
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
-> 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)
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
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)
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
-- 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)
-- 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)
-> 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
-> 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
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
$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;
-> 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)
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)
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)
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)
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)
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)
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)
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;
$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;