Show number of disabled nodes in EXPLAIN ANALYZE output.

Now that disable_cost is not included in the cost estimate, there's
no visible sign in EXPLAIN output of which plan nodes are disabled.
Fix that by propagating the number of disabled nodes from Path to
Plan, and then showing it in the EXPLAIN output.

There is some question about whether this is a desirable change.
While I personally believe that it is, it seems best to make it a
separate commit, in case we decide to back out just this part, or
rework it.

Reviewed by Andres Freund, Heikki Linnakangas, and David Rowley.

Discussion: http://postgr.es/m/CA+TgmoZ_+MS+o6NeGK2xyBv-xM+w1AfFVuHE4f_aq6ekHv7YSQ@mail.gmail.com
This commit is contained in:
Robert Haas 2024-08-21 10:14:35 -04:00
parent e222534679
commit c01743aa48
12 changed files with 59 additions and 15 deletions

View File

@ -1894,6 +1894,10 @@ ExplainNode(PlanState *planstate, List *ancestors,
if (es->format == EXPLAIN_FORMAT_TEXT)
appendStringInfoChar(es->str, '\n');
if (plan->disabled_nodes != 0)
ExplainPropertyInteger("Disabled Nodes", NULL, plan->disabled_nodes,
es);
/* prepare per-worker general execution details */
if (es->workers_state && es->verbose)
{

View File

@ -2572,6 +2572,7 @@ create_minmaxagg_plan(PlannerInfo *root, MinMaxAggPath *best_path)
0, NULL, NULL, NULL);
/* Must apply correct cost/width data to Limit node */
plan->disabled_nodes = mminfo->path->disabled_nodes;
plan->startup_cost = mminfo->path->startup_cost;
plan->total_cost = mminfo->pathcost;
plan->plan_rows = 1;
@ -5404,6 +5405,7 @@ order_qual_clauses(PlannerInfo *root, List *clauses)
static void
copy_generic_path_info(Plan *dest, Path *src)
{
dest->disabled_nodes = src->disabled_nodes;
dest->startup_cost = src->startup_cost;
dest->total_cost = src->total_cost;
dest->plan_rows = src->rows;
@ -5419,6 +5421,7 @@ copy_generic_path_info(Plan *dest, Path *src)
static void
copy_plan_costsize(Plan *dest, Plan *src)
{
dest->disabled_nodes = src->disabled_nodes;
dest->startup_cost = src->startup_cost;
dest->total_cost = src->total_cost;
dest->plan_rows = src->plan_rows;
@ -5452,7 +5455,7 @@ label_sort_with_costsize(PlannerInfo *root, Sort *plan, double limit_tuples)
cost_sort(&sort_path, root, NIL,
lefttree->total_cost,
0, /* a Plan contains no count of disabled nodes */
plan->plan.disabled_nodes,
lefttree->plan_rows,
lefttree->plan_width,
0.0,
@ -6547,11 +6550,12 @@ materialize_finished_plan(Plan *subplan)
/* Set cost data */
cost_material(&matpath,
0, /* a Plan contains no count of disabled nodes */
subplan->disabled_nodes,
subplan->startup_cost,
subplan->total_cost,
subplan->plan_rows,
subplan->plan_width);
matplan->disabled_nodes = subplan->disabled_nodes;
matplan->startup_cost = matpath.startup_cost + initplan_cost;
matplan->total_cost = matpath.total_cost + initplan_cost;
matplan->plan_rows = subplan->plan_rows;

View File

@ -125,6 +125,7 @@ typedef struct Plan
/*
* estimated execution costs for plan (see costsize.c for more info)
*/
int disabled_nodes; /* count of disabled nodes */
Cost startup_cost; /* cost expended before fetching any tuples */
Cost total_cost; /* total cost (assuming all tuples fetched) */

View File

@ -2920,18 +2920,23 @@ GROUP BY c1.w, c1.z;
QUERY PLAN
-----------------------------------------------------
GroupAggregate
Disabled Nodes: 2
Group Key: c1.w, c1.z
-> Sort
Disabled Nodes: 2
Sort Key: c1.w, c1.z, c1.x, c1.y
-> Merge Join
Disabled Nodes: 2
Merge Cond: (c1.x = c2.x)
-> Sort
Sort Key: c1.x
-> Seq Scan on group_agg_pk c1
Disabled Nodes: 1
-> Sort
Sort Key: c2.x
-> Seq Scan on group_agg_pk c2
(12 rows)
Disabled Nodes: 1
(17 rows)
SELECT avg(c1.f ORDER BY c1.x, c1.y)
FROM group_agg_pk c1 JOIN group_agg_pk c2 ON c1.x = c2.x
@ -2953,19 +2958,24 @@ GROUP BY c1.y,c1.x,c2.x;
QUERY PLAN
-----------------------------------------------------
Group
Disabled Nodes: 2
Group Key: c1.x, c1.y
-> Incremental Sort
Disabled Nodes: 2
Sort Key: c1.x, c1.y
Presorted Key: c1.x
-> Merge Join
Disabled Nodes: 2
Merge Cond: (c1.x = c2.x)
-> Sort
Sort Key: c1.x
-> Seq Scan on group_agg_pk c1
Disabled Nodes: 1
-> Sort
Sort Key: c2.x
-> Seq Scan on group_agg_pk c2
(13 rows)
Disabled Nodes: 1
(18 rows)
EXPLAIN (COSTS OFF)
SELECT c1.y,c1.x FROM group_agg_pk c1
@ -2975,19 +2985,24 @@ GROUP BY c1.y,c2.x,c1.x;
QUERY PLAN
-----------------------------------------------------
Group
Disabled Nodes: 2
Group Key: c2.x, c1.y
-> Incremental Sort
Disabled Nodes: 2
Sort Key: c2.x, c1.y
Presorted Key: c2.x
-> Merge Join
Disabled Nodes: 2
Merge Cond: (c1.x = c2.x)
-> Sort
Sort Key: c1.x
-> Seq Scan on group_agg_pk c1
Disabled Nodes: 1
-> Sort
Sort Key: c2.x
-> Seq Scan on group_agg_pk c2
(13 rows)
Disabled Nodes: 1
(18 rows)
RESET enable_nestloop;
RESET enable_hashjoin;

View File

@ -335,10 +335,12 @@ select proname from pg_proc where proname ilike 'ri%foo' order by 1;
QUERY PLAN
----------------------------------------------
Sort
Disabled Nodes: 1
Sort Key: proname
-> Seq Scan on pg_proc
Disabled Nodes: 1
Filter: (proname ~~* 'ri%foo'::text)
(4 rows)
(6 rows)
reset enable_seqscan;
reset enable_indexscan;

View File

@ -989,8 +989,9 @@ select * from collate_test1 where b ilike 'abc';
QUERY PLAN
-------------------------------
Seq Scan on collate_test1
Disabled Nodes: 1
Filter: (b ~~* 'abc'::text)
(2 rows)
(3 rows)
select * from collate_test1 where b ilike 'abc';
a | b
@ -1004,8 +1005,9 @@ select * from collate_test1 where b ilike 'ABC';
QUERY PLAN
-------------------------------
Seq Scan on collate_test1
Disabled Nodes: 1
Filter: (b ~~* 'ABC'::text)
(2 rows)
(3 rows)
select * from collate_test1 where b ilike 'ABC';
a | b

View File

@ -701,16 +701,19 @@ explain (costs off) select * from t left join (select * from (select * from t or
QUERY PLAN
------------------------------------------------
Nested Loop Left Join
Disabled Nodes: 1
Join Filter: (t_1.a = t.a)
-> Seq Scan on t
Filter: (a = ANY ('{1,2}'::integer[]))
-> Incremental Sort
Disabled Nodes: 1
Sort Key: t_1.a, t_1.b
Presorted Key: t_1.a
-> Sort
Disabled Nodes: 1
Sort Key: t_1.a
-> Seq Scan on t t_1
(10 rows)
(13 rows)
select * from t left join (select * from (select * from t order by a) v order by a, b) s on s.a = t.a where t.a in (1, 2);
a | b | a | b

View File

@ -1614,6 +1614,7 @@ explain (verbose, costs off) select * from matest0 order by 1-id;
QUERY PLAN
------------------------------------------------------------------------
Merge Append
Disabled Nodes: 1
Sort Key: ((1 - matest0.id))
-> Index Scan using matest0i on public.matest0 matest0_1
Output: matest0_1.id, matest0_1.name, (1 - matest0_1.id)
@ -1623,10 +1624,11 @@ explain (verbose, costs off) select * from matest0 order by 1-id;
Output: matest0_3.id, matest0_3.name, ((1 - matest0_3.id))
Sort Key: ((1 - matest0_3.id))
-> Seq Scan on public.matest2 matest0_3
Disabled Nodes: 1
Output: matest0_3.id, matest0_3.name, (1 - matest0_3.id)
-> Index Scan using matest3i on public.matest3 matest0_4
Output: matest0_4.id, matest0_4.name, (1 - matest0_4.id)
(13 rows)
(15 rows)
select * from matest0 order by 1-id;
id | name

View File

@ -8000,13 +8000,15 @@ SELECT t1.a FROM skip_fetch t1 LEFT JOIN skip_fetch t2 ON t2.a = 1 WHERE t2.a IS
QUERY PLAN
---------------------------------------------------------
Nested Loop Anti Join
Disabled Nodes: 1
-> Seq Scan on skip_fetch t1
Disabled Nodes: 1
-> Materialize
-> Bitmap Heap Scan on skip_fetch t2
Recheck Cond: (a = 1)
-> Bitmap Index Scan on skip_fetch_a_idx
Index Cond: (a = 1)
(7 rows)
(9 rows)
SELECT t1.a FROM skip_fetch t1 LEFT JOIN skip_fetch t2 ON t2.a = 1 WHERE t2.a IS NULL;
a

View File

@ -333,14 +333,16 @@ SELECT * FROM strtest s1 INNER JOIN strtest s2 ON s1.n >= s2.n;', false);
explain_memoize
----------------------------------------------------------------------------------
Nested Loop (actual rows=24 loops=N)
Disabled Nodes: 1
-> Seq Scan on strtest s1 (actual rows=6 loops=N)
Disabled Nodes: 1
-> Memoize (actual rows=4 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 Cond: (n <= s1.n)
(8 rows)
(10 rows)
-- Ensure we get 3 hits and 3 misses
SELECT explain_memoize('
@ -348,14 +350,16 @@ SELECT * FROM strtest s1 INNER JOIN strtest s2 ON s1.t >= s2.t;', false);
explain_memoize
----------------------------------------------------------------------------------
Nested Loop (actual rows=24 loops=N)
Disabled Nodes: 1
-> Seq Scan on strtest s1 (actual rows=6 loops=N)
Disabled Nodes: 1
-> Memoize (actual rows=4 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 Cond: (t <= s1.t)
(8 rows)
(10 rows)
DROP TABLE strtest;
-- Ensure memoize works with partitionwise join

View File

@ -537,10 +537,14 @@ explain (costs off)
QUERY PLAN
------------------------------------------------------------
Aggregate
Disabled Nodes: 1
-> Nested Loop
Disabled Nodes: 1
-> Gather
Disabled Nodes: 1
Workers Planned: 4
-> Parallel Seq Scan on tenk2
Disabled Nodes: 1
Filter: (thousand = 0)
-> Gather
Workers Planned: 4
@ -548,7 +552,7 @@ explain (costs off)
Recheck Cond: (hundred > 1)
-> Bitmap Index Scan on tenk1_hundred
Index Cond: (hundred > 1)
(12 rows)
(16 rows)
select count(*) from tenk1, tenk2 where tenk1.hundred > 1 and tenk2.thousand=0;
count

View File

@ -822,11 +822,12 @@ explain (costs off) select '123'::xid union select '123'::xid;
QUERY PLAN
---------------------------
HashAggregate
Disabled Nodes: 1
Group Key: ('123'::xid)
-> Append
-> Result
-> Result
(5 rows)
(6 rows)
reset enable_hashagg;
--