From dc5f82f8c74a04c55b03bc8c6d09ffd7f93f70ca Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Thu, 26 Mar 2020 01:15:04 +0100 Subject: [PATCH 3/3] split try_partitionwise_join --- src/backend/optimizer/path/joinrels.c | 146 ++++++++++++++------------ 1 file changed, 78 insertions(+), 68 deletions(-) diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 0b082fc915..314b0267c3 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -1333,71 +1333,12 @@ restriction_is_constant_false(List *restrictlist, return false; } -/* - * Assess whether join between given two partitioned relations can be broken - * down into joins between matching partitions; a technique called - * "partitionwise join" - * - * Partitionwise join is possible when a. Joining relations have same - * partitioning scheme b. There exists an equi-join between the partition keys - * of the two relations. - * - * Partitionwise join is planned as follows (details: optimizer/README.) - * - * 1. Create the RelOptInfos for joins between matching partitions i.e - * child-joins and add paths to them. - * - * 2. Construct Append or MergeAppend paths across the set of child joins. - * This second phase is implemented by generate_partitionwise_join_paths(). - * - * The RelOptInfo, SpecialJoinInfo and restrictlist for each child join are - * obtained by translating the respective parent join structures. - */ static void -try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2, - RelOptInfo *joinrel, SpecialJoinInfo *parent_sjinfo, - List *parent_restrictlist) +compute_partition_bounds(PlannerInfo *root, RelOptInfo *rel1, + RelOptInfo *rel2, RelOptInfo *joinrel, + SpecialJoinInfo *parent_sjinfo, + List **parts1, List **parts2) { - bool rel1_is_simple = IS_SIMPLE_REL(rel1); - bool rel2_is_simple = IS_SIMPLE_REL(rel2); - List *parts1 = NIL; - List *parts2 = NIL; - ListCell *lcr1 = NULL; - ListCell *lcr2 = NULL; - int cnt_parts; - - /* Guard against stack overflow due to overly deep partition hierarchy. */ - check_stack_depth(); - - /* Nothing to do, if the join relation is not partitioned. */ - if (joinrel->part_scheme == NULL || joinrel->nparts == 0) - return; - - /* The join relation should have consider_partitionwise_join set. */ - Assert(joinrel->consider_partitionwise_join); - - /* - * We can not perform partitionwise join if either of the joining relations - * is not partitioned. - */ - if (!IS_PARTITIONED_REL(rel1) || !IS_PARTITIONED_REL(rel2)) - return; - - Assert(REL_HAS_ALL_PART_PROPS(rel1) && REL_HAS_ALL_PART_PROPS(rel2)); - - /* The joining relations should have consider_partitionwise_join set. */ - Assert(rel1->consider_partitionwise_join && - rel2->consider_partitionwise_join); - - /* - * The partition scheme of the join relation should match that of the - * joining relations. - */ - Assert(joinrel->part_scheme == rel1->part_scheme && - joinrel->part_scheme == rel2->part_scheme); - - Assert(!(joinrel->merged && (joinrel->nparts <= 0))); - /* * If we don't have the partition bounds for the join rel yet, try to * compute those along with pairs of partitions to be joined. @@ -1440,13 +1381,13 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2, part_scheme->partcollation, rel1, rel2, parent_sjinfo->jointype, - &parts1, &parts2); + parts1, parts2); if (boundinfo == NULL) { joinrel->nparts = 0; return; } - nparts = list_length(parts1); + nparts = list_length(*parts1); joinrel->merged = true; } @@ -1472,11 +1413,80 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2, if (joinrel->merged) { get_matching_part_pairs(root, joinrel, rel1, rel2, - &parts1, &parts2); - Assert(list_length(parts1) == joinrel->nparts); - Assert(list_length(parts2) == joinrel->nparts); + parts1, parts2); + Assert(list_length(*parts1) == joinrel->nparts); + Assert(list_length(*parts2) == joinrel->nparts); } } +} + +/* + * Assess whether join between given two partitioned relations can be broken + * down into joins between matching partitions; a technique called + * "partitionwise join" + * + * Partitionwise join is possible when a. Joining relations have same + * partitioning scheme b. There exists an equi-join between the partition keys + * of the two relations. + * + * Partitionwise join is planned as follows (details: optimizer/README.) + * + * 1. Create the RelOptInfos for joins between matching partitions i.e + * child-joins and add paths to them. + * + * 2. Construct Append or MergeAppend paths across the set of child joins. + * This second phase is implemented by generate_partitionwise_join_paths(). + * + * The RelOptInfo, SpecialJoinInfo and restrictlist for each child join are + * obtained by translating the respective parent join structures. + */ +static void +try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2, + RelOptInfo *joinrel, SpecialJoinInfo *parent_sjinfo, + List *parent_restrictlist) +{ + bool rel1_is_simple = IS_SIMPLE_REL(rel1); + bool rel2_is_simple = IS_SIMPLE_REL(rel2); + List *parts1 = NIL; + List *parts2 = NIL; + ListCell *lcr1 = NULL; + ListCell *lcr2 = NULL; + int cnt_parts; + + /* Guard against stack overflow due to overly deep partition hierarchy. */ + check_stack_depth(); + + /* Nothing to do, if the join relation is not partitioned. */ + if (joinrel->part_scheme == NULL || joinrel->nparts == 0) + return; + + /* The join relation should have consider_partitionwise_join set. */ + Assert(joinrel->consider_partitionwise_join); + + /* + * We can not perform partitionwise join if either of the joining relations + * is not partitioned. + */ + if (!IS_PARTITIONED_REL(rel1) || !IS_PARTITIONED_REL(rel2)) + return; + + Assert(REL_HAS_ALL_PART_PROPS(rel1) && REL_HAS_ALL_PART_PROPS(rel2)); + + /* The joining relations should have consider_partitionwise_join set. */ + Assert(rel1->consider_partitionwise_join && + rel2->consider_partitionwise_join); + + /* + * The partition scheme of the join relation should match that of the + * joining relations. + */ + Assert(joinrel->part_scheme == rel1->part_scheme && + joinrel->part_scheme == rel2->part_scheme); + + Assert(!(joinrel->merged && (joinrel->nparts <= 0))); + + compute_partition_bounds(root, rel1, rel2, joinrel, parent_sjinfo, + &parts1, &parts2); if (joinrel->merged) { -- 2.21.1