Show number of disabled nodes in EXPLAIN ANALYZE output.
authorRobert Haas <rhaas@postgresql.org>
Wed, 21 Aug 2024 14:14:35 +0000 (10:14 -0400)
committerRobert Haas <rhaas@postgresql.org>
Wed, 21 Aug 2024 14:14:35 +0000 (10:14 -0400)
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

12 files changed:
src/backend/commands/explain.c
src/backend/optimizer/plan/createplan.c
src/include/nodes/plannodes.h
src/test/regress/expected/aggregates.out
src/test/regress/expected/btree_index.out
src/test/regress/expected/collate.icu.utf8.out
src/test/regress/expected/incremental_sort.out
src/test/regress/expected/inherit.out
src/test/regress/expected/join.out
src/test/regress/expected/memoize.out
src/test/regress/expected/select_parallel.out
src/test/regress/expected/union.out

index 5771aabf40a79e4d40bf935e566d394932558111..11df4a04d430e2d6793eaf2ea08544b7845a42ae 100644 (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)
    {
index 1960e59ef2f9a7098ff8ac621a57665700ea1cf0..8e0e5977a9fe3c8e14649b64077c16664c95f236 100644 (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;
index 1aeeaec95e14c5622f6170ba8760cf6027274ce6..62cd6a6666ebeaf9c26c34be91ba879bdd5a14a3 100644 (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) */
 
index a5596ab2106c7643b32cf72b63c401cd4c79b1fa..8ac13b562c4975fc0abd4381939c0d0030be4765 100644 (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;
index 092233cc9d0e7b206376449d925fd6195f49204d..b350efe128c7ba131d7655ec8387c3bc28210f8d 100644 (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;
index 7d59fb44316574cd27313ae16fce3873c2398ec6..31345295c11b931e4da48cf918bfa4024a0cfb93 100644 (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  
index 5fd54a10b1aaf88ee7d5ddf472adb2bbc6cdfc46..79f0d37a87ef677da4cddbdb5959258cc85ad320 100644 (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 
index ad732134148ffbfbcd92aca75c4887a9b623fa01..dbb748a2d2f8d60d734d28fa220d65411a2e7ace 100644 (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  
index 53f70d72ed64dd1e33fce87db0b4f77c471b3e19..31fb7d142eb4b4d9df7df6eca80d6dc5880a8905 100644 (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 
index 96906104d7ed378c15e6fcec28a60d69babd36aa..df2ca5ba4e3e9ee7a028159c9ac40a87873cf396 100644 (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
index bdd675319f23be20ad8a61ef75dc120dbcf7a958..c565407082c2540a9f02d6836c0beb285f210888 100644 (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 
index 0fd0e1c38b3d7c1836ef3e63db65c025ba8b8bf7..0456d48c93a53f6bcf99d6a6786edd69979042d6 100644 (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;
 --