Refactor the construction of distributed grouping paths
authorTomas Vondra <[email protected]>
Fri, 28 Jul 2017 22:34:53 +0000 (00:34 +0200)
committerTomas Vondra <[email protected]>
Mon, 31 Jul 2017 01:19:12 +0000 (03:19 +0200)
The code generating distributed grouping paths was originally structured
like this:

    if (try_distributed_aggregation)
    { ... }

    if (can_sort && try_distributed_aggregation)
    { ... }

    if (can_hash && try_distributed_aggregation)
    { ... }

It's refactored like this, to resemble the upstream part of the code:

    if (try_distributed_aggregation)
    {
        ...

        if (can_sort)
        { ... }

        if (can_hash)
        { ... }
    }

src/backend/optimizer/plan/planner.c

index 842945d84cbbf509e8c906235215d8e7e9eadc34..02baf4a0550c4266c7d906478183f647ce117ef2 100644 (file)
@@ -4511,220 +4511,220 @@ create_grouping_paths(PlannerInfo *root,
                                                                 AGGSPLIT_FINAL_DESERIAL,
                                                                 &agg_final_costs);
                }
-       }
 
-       /* Build final XL grouping paths */
-       if (can_sort && try_distributed_aggregation)
-       {
-               /*
-                * Use any available suitably-sorted path as input, and also consider
-                * sorting the cheapest-total path.
-                */
-               foreach(lc, input_rel->pathlist)
+               /* Build final XL grouping paths */
+               if (can_sort)
                {
-                       Path       *path = (Path *) lfirst(lc);
-                       bool            is_sorted;
-
-                       is_sorted = pathkeys_contained_in(root->group_pathkeys,
-                                       path->pathkeys);
-
                        /*
-                        * XL: Can it happen that the cheapest path can't be pushed down,
-                        * while some other path could be? Perhaps we should move the check
-                        * if a path can be pushed down up, and add another OR condition
-                        * to consider all paths that can be pushed down?
-                        *
-                        * if (path == cheapest_path || is_sorted || can_push_down)
+                        * Use any available suitably-sorted path as input, and also consider
+                        * sorting the cheapest-total path.
                         */
-                       if (path == cheapest_path || is_sorted)
+                       foreach(lc, input_rel->pathlist)
                        {
+                               Path       *path = (Path *) lfirst(lc);
+                               bool            is_sorted;
+
+                               is_sorted = pathkeys_contained_in(root->group_pathkeys,
+                                               path->pathkeys);
+
                                /*
-                                * We can't really beat paths that we managed to fully push
-                                * down above, so we can skip them entirely.
+                                * XL: Can it happen that the cheapest path can't be pushed down,
+                                * while some other path could be? Perhaps we should move the check
+                                * if a path can be pushed down up, and add another OR condition
+                                * to consider all paths that can be pushed down?
                                 *
-                                * XXX Not constructing any paths, so we can do this before
-                                * adding the Sort path.
+                                * if (path == cheapest_path || is_sorted || can_push_down)
                                 */
-                               if (can_push_down_grouping(root, parse, path))
-                                       continue;
-
-                               /* Sort the cheapest-total path if it isn't already sorted */
-                               if (!is_sorted)
-                                       path = (Path *) create_sort_path(root,
-                                                                                                        grouped_rel,
-                                                                                                        path,
-                                                                                                        root->group_pathkeys,
-                                                                                                        -1.0);
-
-                               /* Now decide what to stick atop it */
-                               if (parse->groupingSets)
-                               {
-                                       /*
-                                        * TODO 2-phase aggregation for grouping sets paths not
-                                        * supported yet, but this the place where such paths
-                                        * should be constructed.
-                                        */
-                               }
-                               else if (parse->hasAggs)
+                               if (path == cheapest_path || is_sorted)
                                {
                                        /*
-                                        * We have aggregation, possibly with plain GROUP BY. Make
-                                        * an AggPath.
+                                        * We can't really beat paths that we managed to fully push
+                                        * down above, so we can skip them entirely.
+                                        *
+                                        * XXX Not constructing any paths, so we can do this before
+                                        * adding the Sort path.
                                         */
+                                       if (can_push_down_grouping(root, parse, path))
+                                               continue;
 
-                                       path = (Path *) create_agg_path(root,
-                                                                                                       grouped_rel,
-                                                                                                       path,
-                                                                                                       partial_grouping_target,
-                                                                       parse->groupClause ? AGG_SORTED : AGG_PLAIN,
-                                                                                                       AGGSPLIT_INITIAL_SERIAL,
-                                                                                                       parse->groupClause,
-                                                                                                       NIL,
-                                                                                                       &agg_partial_costs,
-                                                                                                       dNumPartialGroups);
-
-                                       path = create_remotesubplan_path(root, path, NULL);
-
-                                       /*
-                                        * We generate two paths, differing in the second phase
-                                        * implementation (sort and hash).
-                                        */
+                                       /* Sort the cheapest-total path if it isn't already sorted */
+                                       if (!is_sorted)
+                                               path = (Path *) create_sort_path(root,
+                                                                                                                grouped_rel,
+                                                                                                                path,
+                                                                                                                root->group_pathkeys,
+                                                                                                                -1.0);
 
-                                       add_path(grouped_rel, (Path *)
-                                                        create_agg_path(root,
-                                                                                        grouped_rel,
-                                                                                        path,
-                                                                                        target,
-                                                                        parse->groupClause ? AGG_SORTED : AGG_PLAIN,
-                                                                                        AGGSPLIT_FINAL_DESERIAL,
-                                                                                        parse->groupClause,
-                                                                                        (List *) parse->havingQual,
-                                                                                        &agg_final_costs,
-                                                                                        dNumGroups));
+                                       /* Now decide what to stick atop it */
+                                       if (parse->groupingSets)
+                                       {
+                                               /*
+                                                * TODO 2-phase aggregation for grouping sets paths not
+                                                * supported yet, but this the place where such paths
+                                                * should be constructed.
+                                                */
+                                       }
+                                       else if (parse->hasAggs)
+                                       {
+                                               /*
+                                                * We have aggregation, possibly with plain GROUP BY. Make
+                                                * an AggPath.
+                                                */
+
+                                               path = (Path *) create_agg_path(root,
+                                                                                                               grouped_rel,
+                                                                                                               path,
+                                                                                                               partial_grouping_target,
+                                                                               parse->groupClause ? AGG_SORTED : AGG_PLAIN,
+                                                                                                               AGGSPLIT_INITIAL_SERIAL,
+                                                                                                               parse->groupClause,
+                                                                                                               NIL,
+                                                                                                               &agg_partial_costs,
+                                                                                                               dNumPartialGroups);
+
+                                               path = create_remotesubplan_path(root, path, NULL);
+
+                                               /*
+                                                * We generate two paths, differing in the second phase
+                                                * implementation (sort and hash).
+                                                */
 
-                                       if (can_hash)
                                                add_path(grouped_rel, (Path *)
                                                                 create_agg_path(root,
                                                                                                 grouped_rel,
                                                                                                 path,
                                                                                                 target,
-                                                                                                AGG_HASHED,
+                                                                                parse->groupClause ? AGG_SORTED : AGG_PLAIN,
                                                                                                 AGGSPLIT_FINAL_DESERIAL,
                                                                                                 parse->groupClause,
                                                                                                 (List *) parse->havingQual,
                                                                                                 &agg_final_costs,
                                                                                                 dNumGroups));
-                               }
-                               else if (parse->groupClause)
-                               {
-                                       /*
-                                        * We have GROUP BY without aggregation or grouping sets.
-                                        * Make a GroupPath.
-                                        */
-                                       path = (Path *) create_group_path(root,
-                                                                                                         grouped_rel,
-                                                                                                         path,
-                                                                                                         partial_grouping_target,
-                                                                                                         parse->groupClause,
-                                                                                                         NIL,
-                                                                                                         dNumPartialGroups);
 
-                                       path = create_remotesubplan_path(root, path, NULL);
+                                               if (can_hash)
+                                                       add_path(grouped_rel, (Path *)
+                                                                        create_agg_path(root,
+                                                                                                        grouped_rel,
+                                                                                                        path,
+                                                                                                        target,
+                                                                                                        AGG_HASHED,
+                                                                                                        AGGSPLIT_FINAL_DESERIAL,
+                                                                                                        parse->groupClause,
+                                                                                                        (List *) parse->havingQual,
+                                                                                                        &agg_final_costs,
+                                                                                                        dNumGroups));
+                                       }
+                                       else if (parse->groupClause)
+                                       {
+                                               /*
+                                                * We have GROUP BY without aggregation or grouping sets.
+                                                * Make a GroupPath.
+                                                */
+                                               path = (Path *) create_group_path(root,
+                                                                                                                 grouped_rel,
+                                                                                                                 path,
+                                                                                                                 partial_grouping_target,
+                                                                                                                 parse->groupClause,
+                                                                                                                 NIL,
+                                                                                                                 dNumPartialGroups);
+
+                                               path = create_remotesubplan_path(root, path, NULL);
 
-                                       add_path(grouped_rel, (Path *)
-                                                        create_group_path(root,
-                                                                                          grouped_rel,
-                                                                                          path,
-                                                                                          target,
-                                                                                          parse->groupClause,
-                                                                                          (List *) parse->havingQual,
-                                                                                          dNumGroups));
+                                               add_path(grouped_rel, (Path *)
+                                                                create_group_path(root,
+                                                                                                  grouped_rel,
+                                                                                                  path,
+                                                                                                  target,
+                                                                                                  parse->groupClause,
+                                                                                                  (List *) parse->havingQual,
+                                                                                                  dNumGroups));
 
-                               }
-                               else
-                               {
-                                       /* Other cases should have been handled above */
-                                       Assert(false);
+                                       }
+                                       else
+                                       {
+                                               /* Other cases should have been handled above */
+                                               Assert(false);
+                                       }
                                }
                        }
                }
-       }
-
-       if (can_hash && try_distributed_aggregation)
-       {
-               hashaggtablesize = estimate_hashagg_tablesize(cheapest_path,
-                                                                                                         agg_costs,
-                                                                                                         dNumGroups);
 
-               /*
-                * Provided that the estimated size of the hashtable does not exceed
-                * work_mem, we'll generate a HashAgg Path, although if we were unable
-                * to sort above, then we'd better generate a Path, so that we at
-                * least have one.
-                */
-               if (hashaggtablesize < work_mem * 1024L ||
-                       grouped_rel->pathlist == NIL)
+               if (can_hash)
                {
-                       /* If the whole aggregate was pushed down, we're done. */
-                       if (! can_push_down_grouping(root, parse, cheapest_path))
-                       {
-                               Path *path, *agg_path;
-
-                               path = (Path *) create_agg_path(root,
-                                                                          grouped_rel,
-                                                                          cheapest_path,
-                                                                          partial_grouping_target,
-                                                                          AGG_HASHED,
-                                                                          AGGSPLIT_INITIAL_SERIAL,
-                                                                          parse->groupClause,
-                                                                          NIL,
-                                                                          &agg_partial_costs,
-                                                                          dNumPartialGroups);
-
-                               /* keep partially aggregated path for the can_sort branch */
-                               agg_path = path;
-
-                               path = create_remotesubplan_path(root, path, NULL);
+                       hashaggtablesize = estimate_hashagg_tablesize(cheapest_path,
+                                                                                                                 agg_costs,
+                                                                                                                 dNumGroups);
 
-                               /* Generate paths with both hash and sort second phase. */
+                       /*
+                        * Provided that the estimated size of the hashtable does not exceed
+                        * work_mem, we'll generate a HashAgg Path, although if we were unable
+                        * to sort above, then we'd better generate a Path, so that we at
+                        * least have one.
+                        */
+                       if (hashaggtablesize < work_mem * 1024L ||
+                               grouped_rel->pathlist == NIL)
+                       {
+                               /* If the whole aggregate was pushed down, we're done. */
+                               if (! can_push_down_grouping(root, parse, cheapest_path))
+                               {
+                                       Path *path, *agg_path;
 
-                               add_path(grouped_rel, (Path *)
-                                                create_agg_path(root,
-                                                                                grouped_rel,
-                                                                                path,
-                                                                                target,
-                                                                                AGG_HASHED,
-                                                                                AGGSPLIT_FINAL_DESERIAL,
-                                                                                parse->groupClause,
-                                                                                (List *) parse->havingQual,
-                                                                                &agg_final_costs,
-                                                                                dNumGroups));
+                                       path = (Path *) create_agg_path(root,
+                                                                                  grouped_rel,
+                                                                                  cheapest_path,
+                                                                                  partial_grouping_target,
+                                                                                  AGG_HASHED,
+                                                                                  AGGSPLIT_INITIAL_SERIAL,
+                                                                                  parse->groupClause,
+                                                                                  NIL,
+                                                                                  &agg_partial_costs,
+                                                                                  dNumPartialGroups);
 
-                               if (can_sort)
-                               {
-                                       /*
-                                        * AGG_HASHED aggregate paths are always unsorted, so add
-                                        * a Sorted node for the final AGG_SORTED step.
-                                        */
-                                       path = (Path *) create_sort_path(root,
-                                                                                                        grouped_rel,
-                                                                                                        agg_path,
-                                                                                                        root->group_pathkeys,
-                                                                                                        -1.0);
+                                       /* keep partially aggregated path for the can_sort branch */
+                                       agg_path = path;
 
                                        path = create_remotesubplan_path(root, path, NULL);
 
+                                       /* Generate paths with both hash and sort second phase. */
+
                                        add_path(grouped_rel, (Path *)
                                                         create_agg_path(root,
                                                                                         grouped_rel,
                                                                                         path,
                                                                                         target,
-                                                                        parse->groupClause ? AGG_SORTED : AGG_PLAIN,
+                                                                                        AGG_HASHED,
                                                                                         AGGSPLIT_FINAL_DESERIAL,
                                                                                         parse->groupClause,
                                                                                         (List *) parse->havingQual,
                                                                                         &agg_final_costs,
                                                                                         dNumGroups));
+
+                                       if (can_sort)
+                                       {
+                                               /*
+                                                * AGG_HASHED aggregate paths are always unsorted, so add
+                                                * a Sorted node for the final AGG_SORTED step.
+                                                */
+                                               path = (Path *) create_sort_path(root,
+                                                                                                                grouped_rel,
+                                                                                                                agg_path,
+                                                                                                                root->group_pathkeys,
+                                                                                                                -1.0);
+
+                                               path = create_remotesubplan_path(root, path, NULL);
+
+                                               add_path(grouped_rel, (Path *)
+                                                                create_agg_path(root,
+                                                                                                grouped_rel,
+                                                                                                path,
+                                                                                                target,
+                                                                                parse->groupClause ? AGG_SORTED : AGG_PLAIN,
+                                                                                                AGGSPLIT_FINAL_DESERIAL,
+                                                                                                parse->groupClause,
+                                                                                                (List *) parse->havingQual,
+                                                                                                &agg_final_costs,
+                                                                                                dNumGroups));
+                                       }
                                }
                        }
                }