Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 161320b

Browse files
committed
Adjust EXPLAIN's output for disabled nodes
c01743a added EXPLAIN output to display the plan node's disabled_node count whenever that count is above 0. Seemingly, there weren't many people who liked that output as each parent of a disabled node would also have a "Disabled Nodes" output due to the way disabled_nodes is accumulated towards the root plan node. It was often hard and sometimes impossible to figure out which nodes were disabled from looking at EXPLAIN. You might think it would be possible to manually add up the numbers from the "Disabled Nodes" output of a given node's children to figure out if that node has a higher disabled_nodes count than its children, but that wouldn't have worked for Append and Merge Append nodes if some disabled child nodes were run-time pruned during init plan. Those children are not displayed in EXPLAIN. Here we attempt to improve this output by only showing "Disabled: true" against only the nodes which are explicitly disabled themselves. That seems to be the output that's desired by the most people who voiced their opinion. This is done by summing up the disabled_nodes of the given node's children and checking if that number is less than the disabled_nodes of the current node. This commit also fixes a bug in make_sort() which was neglecting to set the Sort's disabled_nodes field. This should have copied what was done in cost_sort(), but it hadn't been updated. With the new output, the choice to not maintain that field properly was clearly wrong as the disabled-ness of the node was attributed to the Sort's parent instead. Reviewed-by: Laurenz Albe, Alena Rybakina Discussion: https://postgr.es/m/9e4ad616bebb103ec2084bf6f724cfc739e7fabb.camel@cybertec.at
1 parent c75c6f8 commit 161320b

17 files changed

+147
-50
lines changed

src/backend/commands/explain.c

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,96 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
13631363
return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
13641364
}
13651365

1366+
/*
1367+
* plan_is_disabled
1368+
* Checks if the given plan node type was disabled during query planning.
1369+
* This is evident by the disable_node field being higher than the sum of
1370+
* the disabled_node field from the plan's children.
1371+
*/
1372+
static bool
1373+
plan_is_disabled(Plan *plan)
1374+
{
1375+
int child_disabled_nodes;
1376+
1377+
/* The node is certainly not disabled if this is zero */
1378+
if (plan->disabled_nodes == 0)
1379+
return false;
1380+
1381+
child_disabled_nodes = 0;
1382+
1383+
/*
1384+
* Handle special nodes first. Children of BitmapOrs and BitmapAnds can't
1385+
* be disabled, so no need to handle those specifically.
1386+
*/
1387+
if (IsA(plan, Append))
1388+
{
1389+
ListCell *lc;
1390+
Append *aplan = (Append *) plan;
1391+
1392+
/*
1393+
* Sum the Append childrens' disabled_nodes. This purposefully
1394+
* includes any run-time pruned children. Ignoring those could give
1395+
* us the incorrect number of disabled nodes.
1396+
*/
1397+
foreach(lc, aplan->appendplans)
1398+
{
1399+
Plan *subplan = lfirst(lc);
1400+
1401+
child_disabled_nodes += subplan->disabled_nodes;
1402+
}
1403+
}
1404+
else if (IsA(plan, MergeAppend))
1405+
{
1406+
ListCell *lc;
1407+
MergeAppend *maplan = (MergeAppend *) plan;
1408+
1409+
/*
1410+
* Sum the MergeAppend childrens' disabled_nodes. This purposefully
1411+
* includes any run-time pruned children. Ignoring those could give
1412+
* us the incorrect number of disabled nodes.
1413+
*/
1414+
foreach(lc, maplan->mergeplans)
1415+
{
1416+
Plan *subplan = lfirst(lc);
1417+
1418+
child_disabled_nodes += subplan->disabled_nodes;
1419+
}
1420+
}
1421+
else if (IsA(plan, SubqueryScan))
1422+
child_disabled_nodes += ((SubqueryScan *) plan)->subplan->disabled_nodes;
1423+
else if (IsA(plan, CustomScan))
1424+
{
1425+
ListCell *lc;
1426+
CustomScan *cplan = (CustomScan *) plan;
1427+
1428+
foreach(lc, cplan->custom_plans)
1429+
{
1430+
Plan *subplan = lfirst(lc);
1431+
1432+
child_disabled_nodes += subplan->disabled_nodes;
1433+
}
1434+
}
1435+
else
1436+
{
1437+
/*
1438+
* Else, sum up disabled_nodes from the plan's inner and outer side.
1439+
*/
1440+
if (outerPlan(plan))
1441+
child_disabled_nodes += outerPlan(plan)->disabled_nodes;
1442+
if (innerPlan(plan))
1443+
child_disabled_nodes += innerPlan(plan)->disabled_nodes;
1444+
}
1445+
1446+
/*
1447+
* It's disabled if the plan's disable_nodes is higher than the sum of its
1448+
* child's plan disabled_nodes.
1449+
*/
1450+
if (plan->disabled_nodes > child_disabled_nodes)
1451+
return true;
1452+
1453+
return false;
1454+
}
1455+
13661456
/*
13671457
* ExplainNode -
13681458
* Appends a description of a plan tree to es->str
@@ -1399,6 +1489,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
13991489
ExplainWorkersState *save_workers_state = es->workers_state;
14001490
int save_indent = es->indent;
14011491
bool haschildren;
1492+
bool isdisabled;
14021493

14031494
/*
14041495
* Prepare per-worker output buffers, if needed. We'll append the data in
@@ -1914,9 +2005,10 @@ ExplainNode(PlanState *planstate, List *ancestors,
19142005
if (es->format == EXPLAIN_FORMAT_TEXT)
19152006
appendStringInfoChar(es->str, '\n');
19162007

1917-
if (plan->disabled_nodes != 0)
1918-
ExplainPropertyInteger("Disabled Nodes", NULL, plan->disabled_nodes,
1919-
es);
2008+
2009+
isdisabled = plan_is_disabled(plan);
2010+
if (es->format != EXPLAIN_FORMAT_TEXT || isdisabled)
2011+
ExplainPropertyBool("Disabled", isdisabled, es);
19202012

19212013
/* prepare per-worker general execution details */
19222014
if (es->workers_state && es->verbose)

src/backend/optimizer/plan/createplan.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6149,6 +6149,7 @@ make_sort(Plan *lefttree, int numCols,
61496149

61506150
plan = &node->plan;
61516151
plan->targetlist = lefttree->targetlist;
6152+
plan->disabled_nodes = lefttree->disabled_nodes + (enable_sort == false);
61526153
plan->qual = NIL;
61536154
plan->lefttree = lefttree;
61546155
plan->righttree = NULL;

src/test/regress/expected/aggregates.out

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2944,23 +2944,20 @@ GROUP BY c1.w, c1.z;
29442944
QUERY PLAN
29452945
-----------------------------------------------------
29462946
GroupAggregate
2947-
Disabled Nodes: 2
29482947
Group Key: c1.w, c1.z
29492948
-> Sort
2950-
Disabled Nodes: 2
29512949
Sort Key: c1.w, c1.z, c1.x, c1.y
29522950
-> Merge Join
2953-
Disabled Nodes: 2
29542951
Merge Cond: (c1.x = c2.x)
29552952
-> Sort
29562953
Sort Key: c1.x
29572954
-> Seq Scan on group_agg_pk c1
2958-
Disabled Nodes: 1
2955+
Disabled: true
29592956
-> Sort
29602957
Sort Key: c2.x
29612958
-> Seq Scan on group_agg_pk c2
2962-
Disabled Nodes: 1
2963-
(17 rows)
2959+
Disabled: true
2960+
(14 rows)
29642961

29652962
SELECT avg(c1.f ORDER BY c1.x, c1.y)
29662963
FROM group_agg_pk c1 JOIN group_agg_pk c2 ON c1.x = c2.x
@@ -2982,24 +2979,21 @@ GROUP BY c1.y,c1.x,c2.x;
29822979
QUERY PLAN
29832980
-----------------------------------------------------
29842981
Group
2985-
Disabled Nodes: 2
29862982
Group Key: c1.x, c1.y
29872983
-> Incremental Sort
2988-
Disabled Nodes: 2
29892984
Sort Key: c1.x, c1.y
29902985
Presorted Key: c1.x
29912986
-> Merge Join
2992-
Disabled Nodes: 2
29932987
Merge Cond: (c1.x = c2.x)
29942988
-> Sort
29952989
Sort Key: c1.x
29962990
-> Seq Scan on group_agg_pk c1
2997-
Disabled Nodes: 1
2991+
Disabled: true
29982992
-> Sort
29992993
Sort Key: c2.x
30002994
-> Seq Scan on group_agg_pk c2
3001-
Disabled Nodes: 1
3002-
(18 rows)
2995+
Disabled: true
2996+
(15 rows)
30032997

30042998
EXPLAIN (COSTS OFF)
30052999
SELECT c1.y,c1.x FROM group_agg_pk c1
@@ -3009,24 +3003,21 @@ GROUP BY c1.y,c2.x,c1.x;
30093003
QUERY PLAN
30103004
-----------------------------------------------------
30113005
Group
3012-
Disabled Nodes: 2
30133006
Group Key: c2.x, c1.y
30143007
-> Incremental Sort
3015-
Disabled Nodes: 2
30163008
Sort Key: c2.x, c1.y
30173009
Presorted Key: c2.x
30183010
-> Merge Join
3019-
Disabled Nodes: 2
30203011
Merge Cond: (c1.x = c2.x)
30213012
-> Sort
30223013
Sort Key: c1.x
30233014
-> Seq Scan on group_agg_pk c1
3024-
Disabled Nodes: 1
3015+
Disabled: true
30253016
-> Sort
30263017
Sort Key: c2.x
30273018
-> Seq Scan on group_agg_pk c2
3028-
Disabled Nodes: 1
3029-
(18 rows)
3019+
Disabled: true
3020+
(15 rows)
30303021

30313022
RESET enable_nestloop;
30323023
RESET enable_hashjoin;

src/test/regress/expected/btree_index.out

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -335,12 +335,11 @@ select proname from pg_proc where proname ilike 'ri%foo' order by 1;
335335
QUERY PLAN
336336
----------------------------------------------
337337
Sort
338-
Disabled Nodes: 1
339338
Sort Key: proname
340339
-> Seq Scan on pg_proc
341-
Disabled Nodes: 1
340+
Disabled: true
342341
Filter: (proname ~~* 'ri%foo'::text)
343-
(6 rows)
342+
(5 rows)
344343

345344
reset enable_seqscan;
346345
reset enable_indexscan;

src/test/regress/expected/collate.icu.utf8.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,7 @@ select * from collate_test1 where b ilike 'abc';
989989
QUERY PLAN
990990
-------------------------------
991991
Seq Scan on collate_test1
992-
Disabled Nodes: 1
992+
Disabled: true
993993
Filter: (b ~~* 'abc'::text)
994994
(3 rows)
995995

@@ -1005,7 +1005,7 @@ select * from collate_test1 where b ilike 'ABC';
10051005
QUERY PLAN
10061006
-------------------------------
10071007
Seq Scan on collate_test1
1008-
Disabled Nodes: 1
1008+
Disabled: true
10091009
Filter: (b ~~* 'ABC'::text)
10101010
(3 rows)
10111011

src/test/regress/expected/explain.out

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ select explain_filter('explain (analyze, buffers, format xml) select * from int8
104104
<Actual-Total-Time>N.N</Actual-Total-Time> +
105105
<Actual-Rows>N</Actual-Rows> +
106106
<Actual-Loops>N</Actual-Loops> +
107+
<Disabled>false</Disabled> +
107108
<Shared-Hit-Blocks>N</Shared-Hit-Blocks> +
108109
<Shared-Read-Blocks>N</Shared-Read-Blocks> +
109110
<Shared-Dirtied-Blocks>N</Shared-Dirtied-Blocks>+
@@ -152,6 +153,7 @@ select explain_filter('explain (analyze, serialize, buffers, format yaml) select
152153
Actual Total Time: N.N +
153154
Actual Rows: N +
154155
Actual Loops: N +
156+
Disabled: false +
155157
Shared Hit Blocks: N +
156158
Shared Read Blocks: N +
157159
Shared Dirtied Blocks: N +
@@ -213,6 +215,7 @@ select explain_filter('explain (buffers, format json) select * from int8_tbl i8'
213215
"Total Cost": N.N, +
214216
"Plan Rows": N, +
215217
"Plan Width": N, +
218+
"Disabled": false, +
216219
"Shared Hit Blocks": N, +
217220
"Shared Read Blocks": N, +
218221
"Shared Dirtied Blocks": N, +
@@ -262,6 +265,7 @@ select explain_filter('explain (analyze, buffers, format json) select * from int
262265
"Actual Total Time": N.N, +
263266
"Actual Rows": N, +
264267
"Actual Loops": N, +
268+
"Disabled": false, +
265269
"Shared Hit Blocks": N, +
266270
"Shared Read Blocks": N, +
267271
"Shared Dirtied Blocks": N, +
@@ -370,6 +374,7 @@ select explain_filter('explain (memory, summary, format yaml) select * from int8
370374
Total Cost: N.N +
371375
Plan Rows: N +
372376
Plan Width: N +
377+
Disabled: false +
373378
Planning: +
374379
Memory Used: N +
375380
Memory Allocated: N +
@@ -394,7 +399,8 @@ select explain_filter('explain (memory, analyze, format json) select * from int8
394399
"Actual Startup Time": N.N, +
395400
"Actual Total Time": N.N, +
396401
"Actual Rows": N, +
397-
"Actual Loops": N +
402+
"Actual Loops": N, +
403+
"Disabled": false +
398404
}, +
399405
"Planning": { +
400406
"Memory Used": N, +
@@ -497,6 +503,7 @@ select jsonb_pretty(
497503
"string4" +
498504
], +
499505
"Schema": "public", +
506+
"Disabled": false, +
500507
"Node Type": "Seq Scan", +
501508
"Plan Rows": 0, +
502509
"Plan Width": 0, +
@@ -540,6 +547,7 @@ select jsonb_pretty(
540547
"stringu2", +
541548
"string4" +
542549
], +
550+
"Disabled": false, +
543551
"Sort Key": [ +
544552
"tenk1.tenthous" +
545553
], +
@@ -586,6 +594,7 @@ select jsonb_pretty(
586594
"stringu2", +
587595
"string4" +
588596
], +
597+
"Disabled": false, +
589598
"Node Type": "Gather Merge", +
590599
"Plan Rows": 0, +
591600
"Plan Width": 0, +

src/test/regress/expected/incremental_sort.out

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ select jsonb_pretty(explain_analyze_inc_sort_nodes_without_memory('select * from
538538
-------------------------------------------------
539539
[ +
540540
{ +
541+
"Disabled": false, +
541542
"Sort Key": [ +
542543
"t.a", +
543544
"t.b" +
@@ -701,19 +702,17 @@ explain (costs off) select * from t left join (select * from (select * from t or
701702
QUERY PLAN
702703
------------------------------------------------
703704
Nested Loop Left Join
704-
Disabled Nodes: 1
705705
Join Filter: (t_1.a = t.a)
706706
-> Seq Scan on t
707707
Filter: (a = ANY ('{1,2}'::integer[]))
708708
-> Incremental Sort
709-
Disabled Nodes: 1
710709
Sort Key: t_1.a, t_1.b
711710
Presorted Key: t_1.a
712711
-> Sort
713-
Disabled Nodes: 1
712+
Disabled: true
714713
Sort Key: t_1.a
715714
-> Seq Scan on t t_1
716-
(13 rows)
715+
(11 rows)
717716

718717
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);
719718
a | b | a | b
@@ -744,6 +743,7 @@ select jsonb_pretty(explain_analyze_inc_sort_nodes_without_memory('select * from
744743
-------------------------------------------------
745744
[ +
746745
{ +
746+
"Disabled": false, +
747747
"Sort Key": [ +
748748
"t.a", +
749749
"t.b" +

src/test/regress/expected/inherit.out

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,7 +1614,6 @@ explain (verbose, costs off) select * from matest0 order by 1-id;
16141614
QUERY PLAN
16151615
------------------------------------------------------------------------
16161616
Merge Append
1617-
Disabled Nodes: 1
16181617
Sort Key: ((1 - matest0.id))
16191618
-> Index Scan using matest0i on public.matest0 matest0_1
16201619
Output: matest0_1.id, matest0_1.name, (1 - matest0_1.id)
@@ -1624,11 +1623,11 @@ explain (verbose, costs off) select * from matest0 order by 1-id;
16241623
Output: matest0_3.id, matest0_3.name, ((1 - matest0_3.id))
16251624
Sort Key: ((1 - matest0_3.id))
16261625
-> Seq Scan on public.matest2 matest0_3
1627-
Disabled Nodes: 1
1626+
Disabled: true
16281627
Output: matest0_3.id, matest0_3.name, (1 - matest0_3.id)
16291628
-> Index Scan using matest3i on public.matest3 matest0_4
16301629
Output: matest0_4.id, matest0_4.name, (1 - matest0_4.id)
1631-
(15 rows)
1630+
(14 rows)
16321631

16331632
select * from matest0 order by 1-id;
16341633
id | name

src/test/regress/expected/insert_conflict.out

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ explain (costs off, format json) insert into insertconflicttest values (0, 'Bilb
218218
"Async Capable": false, +
219219
"Relation Name": "insertconflicttest", +
220220
"Alias": "insertconflicttest", +
221+
"Disabled": false, +
221222
"Conflict Resolution": "UPDATE", +
222223
"Conflict Arbiter Indexes": ["key_index"], +
223224
"Conflict Filter": "(insertconflicttest.fruit <> 'Lime'::text)",+
@@ -226,7 +227,8 @@ explain (costs off, format json) insert into insertconflicttest values (0, 'Bilb
226227
"Node Type": "Result", +
227228
"Parent Relationship": "Outer", +
228229
"Parallel Aware": false, +
229-
"Async Capable": false +
230+
"Async Capable": false, +
231+
"Disabled": false +
230232
} +
231233
] +
232234
} +

0 commit comments

Comments
 (0)