} Clump;
static List *merge_clump(PlannerInfo *root, List *clumps, Clump *new_clump,
- bool force);
+ int num_gene, bool force);
static bool desirable_join(PlannerInfo *root,
RelOptInfo *outer_rel, RelOptInfo *inner_rel);
cur_clump->size = 1;
/* Merge it into the clumps list, using only desirable joins */
- clumps = merge_clump(root, clumps, cur_clump, false);
+ clumps = merge_clump(root, clumps, cur_clump, num_gene, false);
}
if (list_length(clumps) > 1)
{
Clump *clump = (Clump *) lfirst(lc);
- fclumps = merge_clump(root, fclumps, clump, true);
+ fclumps = merge_clump(root, fclumps, clump, num_gene, true);
}
clumps = fclumps;
}
* "desirable" joins.
*/
static List *
-merge_clump(PlannerInfo *root, List *clumps, Clump *new_clump, bool force)
+merge_clump(PlannerInfo *root, List *clumps, Clump *new_clump, int num_gene,
+ bool force)
{
ListCell *prev;
ListCell *lc;
/* Create paths for partitionwise joins. */
generate_partitionwise_join_paths(root, joinrel);
- /* Create GatherPaths for any useful partial paths for rel */
- generate_gather_paths(root, joinrel, false);
+ /*
+ * Except for the topmost scan/join rel, consider gathering
+ * partial paths. We'll do the same for the topmost scan/join
+ * rel once we know the final targetlist (see
+ * grouping_planner).
+ */
+ if (old_clump->size + new_clump->size < num_gene)
+ generate_gather_paths(root, joinrel, false);
/* Find and save the cheapest paths for this joinrel */
set_cheapest(joinrel);
* others. When no further merge is possible, we'll reinsert
* it into the list.
*/
- return merge_clump(root, clumps, old_clump, force);
+ return merge_clump(root, clumps, old_clump, num_gene, force);
}
}
prev = lc;
}
/*
- * If this is a baserel, consider gathering any partial paths we may have
- * created for it. (If we tried to gather inheritance children, we could
+ * If this is a baserel, we should normally consider gathering any partial
+ * paths we may have created for it.
+ *
+ * However, if this is an inheritance child, skip it. Otherwise, we could
* end up with a very large number of gather nodes, each trying to grab
- * its own pool of workers, so don't do this for otherrels. Instead,
- * we'll consider gathering partial paths for the parent appendrel.)
+ * its own pool of workers. Instead, we'll consider gathering partial
+ * paths for the parent appendrel.
+ *
+ * Also, if this is the topmost scan/join rel (that is, the only baserel),
+ * we postpone this until the final scan/join targelist is available (see
+ * grouping_planner).
*/
- if (rel->reloptkind == RELOPT_BASEREL)
+ if (rel->reloptkind == RELOPT_BASEREL &&
+ bms_membership(root->all_baserels) != BMS_SINGLETON)
generate_gather_paths(root, rel, false);
/*
/* Create paths for partitionwise joins. */
generate_partitionwise_join_paths(root, rel);
- /* Create GatherPaths for any useful partial paths for rel */
- generate_gather_paths(root, rel, false);
+ /*
+ * Except for the topmost scan/join rel, consider gathering
+ * partial paths. We'll do the same for the topmost scan/join rel
+ * once we know the final targetlist (see grouping_planner).
+ */
+ if (lev < levels_needed)
+ generate_gather_paths(root, rel, false);
/* Find and save the cheapest paths for this rel */
set_cheapest(rel);
scanjoin_targets = scanjoin_targets_contain_srfs = NIL;
}
+ /*
+ * Generate Gather or Gather Merge paths for the topmost scan/join
+ * relation. Once that's done, we must re-determine which paths are
+ * cheapest. (The previously-cheapest path might even have been
+ * pfree'd!)
+ */
+ generate_gather_paths(root, current_rel, false);
+ set_cheapest(current_rel);
+
/*
* Forcibly apply SRF-free scan/join target to all the Paths for the
* scan/join rel.