diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 282 | ||||
-rw-r--r-- | src/test/regress/expected/partition_join.out | 772 |
2 files changed, 566 insertions, 488 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 26c0feb9df8..359f3fc974a 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -222,9 +222,10 @@ static bool can_partial_agg(PlannerInfo *root, const AggClauseCosts *agg_costs); static void apply_scanjoin_target_to_paths(PlannerInfo *root, RelOptInfo *rel, - PathTarget *scanjoin_target, + List *scanjoin_targets, + List *scanjoin_targets_contain_srfs, bool scanjoin_target_parallel_safe, - bool modify_in_place); + bool tlist_same_exprs); static void create_partitionwise_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel, RelOptInfo *grouped_rel, @@ -1749,6 +1750,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, List *scanjoin_targets; List *scanjoin_targets_contain_srfs; bool scanjoin_target_parallel_safe; + bool scanjoin_target_same_exprs; bool have_grouping; AggClauseCosts agg_costs; WindowFuncLists *wflists = NULL; @@ -1967,34 +1969,33 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, } else { - /* initialize lists, just to keep compiler quiet */ + /* initialize lists; for most of these, dummy values are OK */ final_targets = final_targets_contain_srfs = NIL; sort_input_targets = sort_input_targets_contain_srfs = NIL; grouping_targets = grouping_targets_contain_srfs = NIL; - scanjoin_targets = scanjoin_targets_contain_srfs = NIL; + scanjoin_targets = list_make1(scanjoin_target); + 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!) + * If the final scan/join target is not parallel-safe, we must + * generate Gather paths now, since no partial paths will be generated + * with the final scan/join targetlist. Otherwise, the Gather or + * Gather Merge paths generated within apply_scanjoin_target_to_paths + * will be superior to any we might generate now in that the + * projection will be done in by each participant rather than only in + * the leader. */ - generate_gather_paths(root, current_rel, false); - set_cheapest(current_rel); + if (!scanjoin_target_parallel_safe) + generate_gather_paths(root, current_rel, false); - /* - * Forcibly apply SRF-free scan/join target to all the Paths for the - * scan/join rel. - */ - apply_scanjoin_target_to_paths(root, current_rel, scanjoin_target, - scanjoin_target_parallel_safe, true); - - /* Now fix things up if scan/join target contains SRFs */ - if (parse->hasTargetSRFs) - adjust_paths_for_srfs(root, current_rel, - scanjoin_targets, - scanjoin_targets_contain_srfs); + /* Apply scan/join target. */ + scanjoin_target_same_exprs = list_length(scanjoin_targets) == 1 + && equal(scanjoin_target->exprs, current_rel->reltarget->exprs); + apply_scanjoin_target_to_paths(root, current_rel, scanjoin_targets, + scanjoin_targets_contain_srfs, + scanjoin_target_parallel_safe, + scanjoin_target_same_exprs); /* * Save the various upper-rel PathTargets we just computed into @@ -6796,24 +6797,88 @@ can_partial_agg(PlannerInfo *root, const AggClauseCosts *agg_costs) /* * apply_scanjoin_target_to_paths * - * Applies scan/join target to all the Paths for the scan/join rel. + * Adjust the final scan/join relation, and recursively all of its children, + * to generate the final scan/join target. It would be more correct to model + * this as a separate planning step with a new RelOptInfo at the toplevel and + * for each child relation, but doing it this way is noticeably cheaper. + * Maybe that problem can be solved at some point, but for now we do this. + * + * If tlist_same_exprs is true, then the scan/join target to be applied has + * the same expressions as the existing reltarget, so we need only insert the + * appropriate sortgroupref information. By avoiding the creation of + * projection paths we save effort both immediately and at plan creation time. */ static void apply_scanjoin_target_to_paths(PlannerInfo *root, RelOptInfo *rel, - PathTarget *scanjoin_target, + List *scanjoin_targets, + List *scanjoin_targets_contain_srfs, bool scanjoin_target_parallel_safe, - bool modify_in_place) + bool tlist_same_exprs) { ListCell *lc; + PathTarget *scanjoin_target; + + check_stack_depth(); /* - * In principle we should re-run set_cheapest() here to identify the - * cheapest path, but it seems unlikely that adding the same tlist eval - * costs to all the paths would change that, so we don't bother. Instead, - * just assume that the cheapest-startup and cheapest-total paths remain - * so. (There should be no parameterized paths anymore, so we needn't - * worry about updating cheapest_parameterized_paths.) + * If the scan/join target is not parallel-safe, then the new partial + * pathlist is the empty list. + */ + if (!scanjoin_target_parallel_safe) + { + rel->partial_pathlist = NIL; + rel->consider_parallel = false; + } + + /* + * Update the reltarget. This may not be strictly necessary in all cases, + * but it is at least necessary when create_append_path() gets called + * below directly or indirectly, since that function uses the reltarget as + * the pathtarget for the resulting path. It seems like a good idea to do + * it unconditionally. + */ + rel->reltarget = llast_node(PathTarget, scanjoin_targets); + + /* Special case: handly dummy relations separately. */ + if (IS_DUMMY_REL(rel)) + { + /* + * Since this is a dummy rel, it's got a single Append path with no + * child paths. Replace it with a new path having the final scan/join + * target. (Note that since Append is not projection-capable, it + * would be bad to handle this using the general purpose code below; + * we'd end up putting a ProjectionPath on top of the existing Append + * node, which would cause this relation to stop appearing to be a + * dummy rel.) + */ + rel->pathlist = list_make1(create_append_path(rel, NIL, NIL, NULL, + 0, false, NIL, -1)); + rel->partial_pathlist = NIL; + set_cheapest(rel); + Assert(IS_DUMMY_REL(rel)); + + /* + * Forget about any child relations. There's no point in adjusting + * them and no point in using them for later planning stages (in + * particular, partitionwise aggregate). + */ + rel->nparts = 0; + rel->part_rels = NULL; + rel->boundinfo = NULL; + + return; + } + + /* Extract SRF-free scan/join target. */ + scanjoin_target = linitial_node(PathTarget, scanjoin_targets); + + /* + * Adjust each input path. If the tlist exprs are the same, we can just + * inject the sortgroupref information into the existing pathtarget. + * Otherwise, replace each path with a projection path that generates the + * SRF-free scan/join target. This can't change the ordering of paths + * within rel->pathlist, so we just modify the list in place. */ foreach(lc, rel->pathlist) { @@ -6822,52 +6887,31 @@ apply_scanjoin_target_to_paths(PlannerInfo *root, Assert(subpath->param_info == NULL); - /* - * Don't use apply_projection_to_path() when modify_in_place is false, - * because there could be other pointers to these paths, and therefore - * we mustn't modify them in place. - */ - if (modify_in_place) - newpath = apply_projection_to_path(root, rel, subpath, - scanjoin_target); + if (tlist_same_exprs) + subpath->pathtarget->sortgrouprefs = + scanjoin_target->sortgrouprefs; else + { newpath = (Path *) create_projection_path(root, rel, subpath, scanjoin_target); - - /* If we had to add a Result, newpath is different from subpath */ - if (newpath != subpath) - { lfirst(lc) = newpath; - if (subpath == rel->cheapest_startup_path) - rel->cheapest_startup_path = newpath; - if (subpath == rel->cheapest_total_path) - rel->cheapest_total_path = newpath; } } - /* - * Upper planning steps which make use of the top scan/join rel's partial - * pathlist will expect partial paths for that rel to produce the same - * output as complete paths ... and we just changed the output for the - * complete paths, so we'll need to do the same thing for partial paths. - * But only parallel-safe expressions can be computed by partial paths. - */ - if (rel->partial_pathlist && scanjoin_target_parallel_safe) + /* Same for partial paths. */ + foreach(lc, rel->partial_pathlist) { - /* Apply the scan/join target to each partial path */ - foreach(lc, rel->partial_pathlist) - { - Path *subpath = (Path *) lfirst(lc); - Path *newpath; + Path *subpath = (Path *) lfirst(lc); + Path *newpath; - /* Shouldn't have any parameterized paths anymore */ - Assert(subpath->param_info == NULL); + /* Shouldn't have any parameterized paths anymore */ + Assert(subpath->param_info == NULL); - /* - * Don't use apply_projection_to_path() here, because there could - * be other pointers to these paths, and therefore we mustn't - * modify them in place. - */ + if (tlist_same_exprs) + subpath->pathtarget->sortgrouprefs = + scanjoin_target->sortgrouprefs; + else + { newpath = (Path *) create_projection_path(root, rel, subpath, @@ -6875,16 +6919,83 @@ apply_scanjoin_target_to_paths(PlannerInfo *root, lfirst(lc) = newpath; } } - else + + /* Now fix things up if scan/join target contains SRFs */ + if (root->parse->hasTargetSRFs) + adjust_paths_for_srfs(root, rel, + scanjoin_targets, + scanjoin_targets_contain_srfs); + + /* + * If the relation is partitioned, recurseively apply the same changes to + * all partitions and generate new Append paths. Since Append is not + * projection-capable, that might save a separate Result node, and it also + * is important for partitionwise aggregate. + */ + if (rel->part_scheme && rel->part_rels) { - /* - * In the unfortunate event that scanjoin_target is not parallel-safe, - * we can't apply it to the partial paths; in that case, we'll need to - * forget about the partial paths, which aren't valid input for upper - * planning steps. - */ - rel->partial_pathlist = NIL; + int partition_idx; + List *live_children = NIL; + + /* Adjust each partition. */ + for (partition_idx = 0; partition_idx < rel->nparts; partition_idx++) + { + RelOptInfo *child_rel = rel->part_rels[partition_idx]; + ListCell *lc; + AppendRelInfo **appinfos; + int nappinfos; + List *child_scanjoin_targets = NIL; + + /* Translate scan/join targets for this child. */ + appinfos = find_appinfos_by_relids(root, child_rel->relids, + &nappinfos); + foreach(lc, scanjoin_targets) + { + PathTarget *target = lfirst_node(PathTarget, lc); + + target = copy_pathtarget(target); + target->exprs = (List *) + adjust_appendrel_attrs(root, + (Node *) target->exprs, + nappinfos, appinfos); + child_scanjoin_targets = lappend(child_scanjoin_targets, + target); + } + pfree(appinfos); + + /* Recursion does the real work. */ + apply_scanjoin_target_to_paths(root, child_rel, + child_scanjoin_targets, + scanjoin_targets_contain_srfs, + scanjoin_target_parallel_safe, + tlist_same_exprs); + + /* Save non-dummy children for Append paths. */ + if (!IS_DUMMY_REL(child_rel)) + live_children = lappend(live_children, child_rel); + } + + /* Build new paths for this relation by appending child paths. */ + if (live_children != NIL) + add_paths_to_append_rel(root, rel, live_children); } + + /* + * Consider generating Gather or Gather Merge paths. We must only do this + * if the relation is parallel safe, and we don't do it for child rels to + * avoid creating multiple Gather nodes within the same plan. We must do + * this after all paths have been generated and before set_cheapest, since + * one of the generated paths may turn out to be the cheapest one. + */ + if (rel->consider_parallel && !IS_OTHER_REL(rel)) + generate_gather_paths(root, rel, false); + + /* + * Reassess which paths are the cheapest, now that we've potentially added + * new Gather (or Gather Merge) and/or Append (or MergeAppend) paths to + * this relation. + */ + set_cheapest(rel); } /* @@ -6931,7 +7042,6 @@ create_partitionwise_grouping_paths(PlannerInfo *root, PathTarget *child_target = copy_pathtarget(target); AppendRelInfo **appinfos; int nappinfos; - PathTarget *scanjoin_target; GroupPathExtraData child_extra; RelOptInfo *child_grouped_rel; RelOptInfo *child_partially_grouped_rel; @@ -6988,26 +7098,6 @@ create_partitionwise_grouping_paths(PlannerInfo *root, continue; } - /* - * Copy pathtarget from underneath scan/join as we are modifying it - * and translate its Vars with respect to this appendrel. The input - * relation's reltarget might not be the final scanjoin_target, but - * the pathtarget any given individual path should be. - */ - scanjoin_target = - copy_pathtarget(input_rel->cheapest_startup_path->pathtarget); - scanjoin_target->exprs = (List *) - adjust_appendrel_attrs(root, - (Node *) scanjoin_target->exprs, - nappinfos, appinfos); - - /* - * Forcibly apply scan/join target to all the Paths for the scan/join - * rel. - */ - apply_scanjoin_target_to_paths(root, child_input_rel, scanjoin_target, - extra->target_parallel_safe, false); - /* Create grouping paths for this child relation. */ create_ordinary_grouping_paths(root, child_input_rel, child_grouped_rel, diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out index 4fccd9ae54f..b983f9c5065 100644 --- a/src/test/regress/expected/partition_join.out +++ b/src/test/regress/expected/partition_join.out @@ -65,31 +65,30 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = -- left outer join, with whole-row reference EXPLAIN (COSTS OFF) SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b; - QUERY PLAN --------------------------------------------------------- + QUERY PLAN +-------------------------------------------------- Sort Sort Key: t1.a, t2.b - -> Result - -> Append - -> Hash Right Join - Hash Cond: (t2.b = t1.a) - -> Seq Scan on prt2_p1 t2 - -> Hash - -> Seq Scan on prt1_p1 t1 - Filter: (b = 0) - -> Hash Right Join - Hash Cond: (t2_1.b = t1_1.a) - -> Seq Scan on prt2_p2 t2_1 - -> Hash - -> Seq Scan on prt1_p2 t1_1 - Filter: (b = 0) - -> Hash Right Join - Hash Cond: (t2_2.b = t1_2.a) - -> Seq Scan on prt2_p3 t2_2 - -> Hash - -> Seq Scan on prt1_p3 t1_2 - Filter: (b = 0) -(22 rows) + -> Append + -> Hash Right Join + Hash Cond: (t2.b = t1.a) + -> Seq Scan on prt2_p1 t2 + -> Hash + -> Seq Scan on prt1_p1 t1 + Filter: (b = 0) + -> Hash Right Join + Hash Cond: (t2_1.b = t1_1.a) + -> Seq Scan on prt2_p2 t2_1 + -> Hash + -> Seq Scan on prt1_p2 t1_1 + Filter: (b = 0) + -> Hash Right Join + Hash Cond: (t2_2.b = t1_2.a) + -> Seq Scan on prt2_p3 t2_2 + -> Hash + -> Seq Scan on prt1_p3 t1_2 + Filter: (b = 0) +(21 rows) SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b; t1 | t2 @@ -111,30 +110,29 @@ SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER -- right outer join EXPLAIN (COSTS OFF) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t1.a, t2.b; - QUERY PLAN ---------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------- Sort Sort Key: t1.a, t2.b - -> Result - -> Append - -> Hash Right Join - Hash Cond: (t1.a = t2.b) - -> Seq Scan on prt1_p1 t1 - -> Hash - -> Seq Scan on prt2_p1 t2 - Filter: (a = 0) - -> Hash Right Join - Hash Cond: (t1_1.a = t2_1.b) - -> Seq Scan on prt1_p2 t1_1 - -> Hash - -> Seq Scan on prt2_p2 t2_1 - Filter: (a = 0) - -> Nested Loop Left Join - -> Seq Scan on prt2_p3 t2_2 + -> Append + -> Hash Right Join + Hash Cond: (t1.a = t2.b) + -> Seq Scan on prt1_p1 t1 + -> Hash + -> Seq Scan on prt2_p1 t2 Filter: (a = 0) - -> Index Scan using iprt1_p3_a on prt1_p3 t1_2 - Index Cond: (a = t2_2.b) -(21 rows) + -> Hash Right Join + Hash Cond: (t1_1.a = t2_1.b) + -> Seq Scan on prt1_p2 t1_1 + -> Hash + -> Seq Scan on prt2_p2 t2_1 + Filter: (a = 0) + -> Nested Loop Left Join + -> Seq Scan on prt2_p3 t2_2 + Filter: (a = 0) + -> Index Scan using iprt1_p3_a on prt1_p3 t1_2 + Index Cond: (a = t2_2.b) +(20 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t1.a, t2.b; a | c | b | c @@ -375,37 +373,36 @@ EXPLAIN (COSTS OFF) SELECT * FROM prt1 t1 LEFT JOIN LATERAL (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.b) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss ON t1.a = ss.t2a WHERE t1.b = 0 ORDER BY t1.a; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------- Sort Sort Key: t1.a - -> Result - -> Append - -> Nested Loop Left Join - -> Seq Scan on prt1_p1 t1 - Filter: (b = 0) - -> Nested Loop - -> Index Only Scan using iprt1_p1_a on prt1_p1 t2 - Index Cond: (a = t1.a) - -> Index Scan using iprt2_p1_b on prt2_p1 t3 - Index Cond: (b = t2.a) - -> Nested Loop Left Join - -> Seq Scan on prt1_p2 t1_1 - Filter: (b = 0) - -> Nested Loop - -> Index Only Scan using iprt1_p2_a on prt1_p2 t2_1 - Index Cond: (a = t1_1.a) - -> Index Scan using iprt2_p2_b on prt2_p2 t3_1 - Index Cond: (b = t2_1.a) - -> Nested Loop Left Join - -> Seq Scan on prt1_p3 t1_2 - Filter: (b = 0) - -> Nested Loop - -> Index Only Scan using iprt1_p3_a on prt1_p3 t2_2 - Index Cond: (a = t1_2.a) - -> Index Scan using iprt2_p3_b on prt2_p3 t3_2 - Index Cond: (b = t2_2.a) -(28 rows) + -> Append + -> Nested Loop Left Join + -> Seq Scan on prt1_p1 t1 + Filter: (b = 0) + -> Nested Loop + -> Index Only Scan using iprt1_p1_a on prt1_p1 t2 + Index Cond: (a = t1.a) + -> Index Scan using iprt2_p1_b on prt2_p1 t3 + Index Cond: (b = t2.a) + -> Nested Loop Left Join + -> Seq Scan on prt1_p2 t1_1 + Filter: (b = 0) + -> Nested Loop + -> Index Only Scan using iprt1_p2_a on prt1_p2 t2_1 + Index Cond: (a = t1_1.a) + -> Index Scan using iprt2_p2_b on prt2_p2 t3_1 + Index Cond: (b = t2_1.a) + -> Nested Loop Left Join + -> Seq Scan on prt1_p3 t1_2 + Filter: (b = 0) + -> Nested Loop + -> Index Only Scan using iprt1_p3_a on prt1_p3 t2_2 + Index Cond: (a = t1_2.a) + -> Index Scan using iprt2_p3_b on prt2_p3 t3_2 + Index Cond: (b = t2_2.a) +(27 rows) SELECT * FROM prt1 t1 LEFT JOIN LATERAL (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.b) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss @@ -538,92 +535,90 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_e t1, prt2_e t2 WHERE (t1.a + t1.b)/2 = -- EXPLAIN (COSTS OFF) SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM prt1 t1, prt2 t2, prt1_e t3 WHERE t1.a = t2.b AND t1.a = (t3.a + t3.b)/2 AND t1.b = 0 ORDER BY t1.a, t2.b; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------- Sort Sort Key: t1.a - -> Result - -> Append - -> Nested Loop - Join Filter: (t1.a = ((t3.a + t3.b) / 2)) - -> Hash Join + -> Append + -> Nested Loop + Join Filter: (t1.a = ((t3.a + t3.b) / 2)) + -> Hash Join + Hash Cond: (t2.b = t1.a) + -> Seq Scan on prt2_p1 t2 + -> Hash + -> Seq Scan on prt1_p1 t1 + Filter: (b = 0) + -> Index Scan using iprt1_e_p1_ab2 on prt1_e_p1 t3 + Index Cond: (((a + b) / 2) = t2.b) + -> Nested Loop + Join Filter: (t1_1.a = ((t3_1.a + t3_1.b) / 2)) + -> Hash Join + Hash Cond: (t2_1.b = t1_1.a) + -> Seq Scan on prt2_p2 t2_1 + -> Hash + -> Seq Scan on prt1_p2 t1_1 + Filter: (b = 0) + -> Index Scan using iprt1_e_p2_ab2 on prt1_e_p2 t3_1 + Index Cond: (((a + b) / 2) = t2_1.b) + -> Nested Loop + Join Filter: (t1_2.a = ((t3_2.a + t3_2.b) / 2)) + -> Hash Join + Hash Cond: (t2_2.b = t1_2.a) + -> Seq Scan on prt2_p3 t2_2 + -> Hash + -> Seq Scan on prt1_p3 t1_2 + Filter: (b = 0) + -> Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t3_2 + Index Cond: (((a + b) / 2) = t2_2.b) +(33 rows) + +SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM prt1 t1, prt2 t2, prt1_e t3 WHERE t1.a = t2.b AND t1.a = (t3.a + t3.b)/2 AND t1.b = 0 ORDER BY t1.a, t2.b; + a | c | b | c | ?column? | c +-----+------+-----+------+----------+--- + 0 | 0000 | 0 | 0000 | 0 | 0 + 150 | 0150 | 150 | 0150 | 300 | 0 + 300 | 0300 | 300 | 0300 | 600 | 0 + 450 | 0450 | 450 | 0450 | 900 | 0 +(4 rows) + +EXPLAIN (COSTS OFF) +SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) LEFT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.b = 0 ORDER BY t1.a, t2.b, t3.a + t3.b; + QUERY PLAN +-------------------------------------------------------------- + Sort + Sort Key: t1.a, t2.b, ((t3.a + t3.b)) + -> Append + -> Hash Right Join + Hash Cond: (((t3.a + t3.b) / 2) = t1.a) + -> Seq Scan on prt1_e_p1 t3 + -> Hash + -> Hash Right Join Hash Cond: (t2.b = t1.a) -> Seq Scan on prt2_p1 t2 -> Hash -> Seq Scan on prt1_p1 t1 Filter: (b = 0) - -> Index Scan using iprt1_e_p1_ab2 on prt1_e_p1 t3 - Index Cond: (((a + b) / 2) = t2.b) - -> Nested Loop - Join Filter: (t1_1.a = ((t3_1.a + t3_1.b) / 2)) - -> Hash Join + -> Hash Right Join + Hash Cond: (((t3_1.a + t3_1.b) / 2) = t1_1.a) + -> Seq Scan on prt1_e_p2 t3_1 + -> Hash + -> Hash Right Join Hash Cond: (t2_1.b = t1_1.a) -> Seq Scan on prt2_p2 t2_1 -> Hash -> Seq Scan on prt1_p2 t1_1 Filter: (b = 0) - -> Index Scan using iprt1_e_p2_ab2 on prt1_e_p2 t3_1 - Index Cond: (((a + b) / 2) = t2_1.b) - -> Nested Loop - Join Filter: (t1_2.a = ((t3_2.a + t3_2.b) / 2)) - -> Hash Join + -> Hash Right Join + Hash Cond: (((t3_2.a + t3_2.b) / 2) = t1_2.a) + -> Seq Scan on prt1_e_p3 t3_2 + -> Hash + -> Hash Right Join Hash Cond: (t2_2.b = t1_2.a) -> Seq Scan on prt2_p3 t2_2 -> Hash -> Seq Scan on prt1_p3 t1_2 Filter: (b = 0) - -> Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t3_2 - Index Cond: (((a + b) / 2) = t2_2.b) -(34 rows) - -SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM prt1 t1, prt2 t2, prt1_e t3 WHERE t1.a = t2.b AND t1.a = (t3.a + t3.b)/2 AND t1.b = 0 ORDER BY t1.a, t2.b; - a | c | b | c | ?column? | c ------+------+-----+------+----------+--- - 0 | 0000 | 0 | 0000 | 0 | 0 - 150 | 0150 | 150 | 0150 | 300 | 0 - 300 | 0300 | 300 | 0300 | 600 | 0 - 450 | 0450 | 450 | 0450 | 900 | 0 -(4 rows) - -EXPLAIN (COSTS OFF) -SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) LEFT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.b = 0 ORDER BY t1.a, t2.b, t3.a + t3.b; - QUERY PLAN --------------------------------------------------------------------- - Sort - Sort Key: t1.a, t2.b, ((t3.a + t3.b)) - -> Result - -> Append - -> Hash Right Join - Hash Cond: (((t3.a + t3.b) / 2) = t1.a) - -> Seq Scan on prt1_e_p1 t3 - -> Hash - -> Hash Right Join - Hash Cond: (t2.b = t1.a) - -> Seq Scan on prt2_p1 t2 - -> Hash - -> Seq Scan on prt1_p1 t1 - Filter: (b = 0) - -> Hash Right Join - Hash Cond: (((t3_1.a + t3_1.b) / 2) = t1_1.a) - -> Seq Scan on prt1_e_p2 t3_1 - -> Hash - -> Hash Right Join - Hash Cond: (t2_1.b = t1_1.a) - -> Seq Scan on prt2_p2 t2_1 - -> Hash - -> Seq Scan on prt1_p2 t1_1 - Filter: (b = 0) - -> Hash Right Join - Hash Cond: (((t3_2.a + t3_2.b) / 2) = t1_2.a) - -> Seq Scan on prt1_e_p3 t3_2 - -> Hash - -> Hash Right Join - Hash Cond: (t2_2.b = t1_2.a) - -> Seq Scan on prt2_p3 t2_2 - -> Hash - -> Seq Scan on prt1_p3 t1_2 - Filter: (b = 0) -(34 rows) +(33 rows) SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) LEFT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.b = 0 ORDER BY t1.a, t2.b, t3.a + t3.b; a | c | b | c | ?column? | c @@ -644,40 +639,39 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 EXPLAIN (COSTS OFF) SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b; - QUERY PLAN -------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------- Sort Sort Key: t1.a, t2.b, ((t3.a + t3.b)) - -> Result - -> Append - -> Nested Loop Left Join - -> Hash Right Join - Hash Cond: (t1.a = ((t3.a + t3.b) / 2)) - -> Seq Scan on prt1_p1 t1 - -> Hash - -> Seq Scan on prt1_e_p1 t3 - Filter: (c = 0) - -> Index Scan using iprt2_p1_b on prt2_p1 t2 - Index Cond: (t1.a = b) - -> Nested Loop Left Join - -> Hash Right Join - Hash Cond: (t1_1.a = ((t3_1.a + t3_1.b) / 2)) - -> Seq Scan on prt1_p2 t1_1 - -> Hash - -> Seq Scan on prt1_e_p2 t3_1 - Filter: (c = 0) - -> Index Scan using iprt2_p2_b on prt2_p2 t2_1 - Index Cond: (t1_1.a = b) - -> Nested Loop Left Join - -> Hash Right Join - Hash Cond: (t1_2.a = ((t3_2.a + t3_2.b) / 2)) - -> Seq Scan on prt1_p3 t1_2 - -> Hash - -> Seq Scan on prt1_e_p3 t3_2 - Filter: (c = 0) - -> Index Scan using iprt2_p3_b on prt2_p3 t2_2 - Index Cond: (t1_2.a = b) -(31 rows) + -> Append + -> Nested Loop Left Join + -> Hash Right Join + Hash Cond: (t1.a = ((t3.a + t3.b) / 2)) + -> Seq Scan on prt1_p1 t1 + -> Hash + -> Seq Scan on prt1_e_p1 t3 + Filter: (c = 0) + -> Index Scan using iprt2_p1_b on prt2_p1 t2 + Index Cond: (t1.a = b) + -> Nested Loop Left Join + -> Hash Right Join + Hash Cond: (t1_1.a = ((t3_1.a + t3_1.b) / 2)) + -> Seq Scan on prt1_p2 t1_1 + -> Hash + -> Seq Scan on prt1_e_p2 t3_1 + Filter: (c = 0) + -> Index Scan using iprt2_p2_b on prt2_p2 t2_1 + Index Cond: (t1_1.a = b) + -> Nested Loop Left Join + -> Hash Right Join + Hash Cond: (t1_2.a = ((t3_2.a + t3_2.b) / 2)) + -> Seq Scan on prt1_p3 t1_2 + -> Hash + -> Seq Scan on prt1_e_p3 t3_2 + Filter: (c = 0) + -> Index Scan using iprt2_p3_b on prt2_p3 t2_2 + Index Cond: (t1_2.a = b) +(30 rows) SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b; a | c | b | c | ?column? | c @@ -700,52 +694,51 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 -- make sure these go to null as expected EXPLAIN (COSTS OFF) SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.a = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT 50 phv, * FROM prt1_e WHERE prt1_e.c = 0) t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a = t1.phv OR t2.b = t2.phv OR (t3.a + t3.b)/2 = t3.phv ORDER BY t1.a, t2.b, t3.a + t3.b; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------- Sort Sort Key: prt1_p1.a, prt2_p1.b, ((prt1_e_p1.a + prt1_e_p1.b)) - -> Result - -> Append + -> Append + -> Hash Full Join + Hash Cond: (prt1_p1.a = ((prt1_e_p1.a + prt1_e_p1.b) / 2)) + Filter: ((prt1_p1.a = (50)) OR (prt2_p1.b = (75)) OR (((prt1_e_p1.a + prt1_e_p1.b) / 2) = (50))) -> Hash Full Join - Hash Cond: (prt1_p1.a = ((prt1_e_p1.a + prt1_e_p1.b) / 2)) - Filter: ((prt1_p1.a = (50)) OR (prt2_p1.b = (75)) OR (((prt1_e_p1.a + prt1_e_p1.b) / 2) = (50))) - -> Hash Full Join - Hash Cond: (prt1_p1.a = prt2_p1.b) - -> Seq Scan on prt1_p1 - Filter: (b = 0) - -> Hash - -> Seq Scan on prt2_p1 - Filter: (a = 0) + Hash Cond: (prt1_p1.a = prt2_p1.b) + -> Seq Scan on prt1_p1 + Filter: (b = 0) -> Hash - -> Seq Scan on prt1_e_p1 - Filter: (c = 0) + -> Seq Scan on prt2_p1 + Filter: (a = 0) + -> Hash + -> Seq Scan on prt1_e_p1 + Filter: (c = 0) + -> Hash Full Join + Hash Cond: (prt1_p2.a = ((prt1_e_p2.a + prt1_e_p2.b) / 2)) + Filter: ((prt1_p2.a = (50)) OR (prt2_p2.b = (75)) OR (((prt1_e_p2.a + prt1_e_p2.b) / 2) = (50))) -> Hash Full Join - Hash Cond: (prt1_p2.a = ((prt1_e_p2.a + prt1_e_p2.b) / 2)) - Filter: ((prt1_p2.a = (50)) OR (prt2_p2.b = (75)) OR (((prt1_e_p2.a + prt1_e_p2.b) / 2) = (50))) - -> Hash Full Join - Hash Cond: (prt1_p2.a = prt2_p2.b) - -> Seq Scan on prt1_p2 - Filter: (b = 0) - -> Hash - -> Seq Scan on prt2_p2 - Filter: (a = 0) + Hash Cond: (prt1_p2.a = prt2_p2.b) + -> Seq Scan on prt1_p2 + Filter: (b = 0) -> Hash - -> Seq Scan on prt1_e_p2 - Filter: (c = 0) + -> Seq Scan on prt2_p2 + Filter: (a = 0) + -> Hash + -> Seq Scan on prt1_e_p2 + Filter: (c = 0) + -> Hash Full Join + Hash Cond: (prt1_p3.a = ((prt1_e_p3.a + prt1_e_p3.b) / 2)) + Filter: ((prt1_p3.a = (50)) OR (prt2_p3.b = (75)) OR (((prt1_e_p3.a + prt1_e_p3.b) / 2) = (50))) -> Hash Full Join - Hash Cond: (prt1_p3.a = ((prt1_e_p3.a + prt1_e_p3.b) / 2)) - Filter: ((prt1_p3.a = (50)) OR (prt2_p3.b = (75)) OR (((prt1_e_p3.a + prt1_e_p3.b) / 2) = (50))) - -> Hash Full Join - Hash Cond: (prt1_p3.a = prt2_p3.b) - -> Seq Scan on prt1_p3 - Filter: (b = 0) - -> Hash - -> Seq Scan on prt2_p3 - Filter: (a = 0) + Hash Cond: (prt1_p3.a = prt2_p3.b) + -> Seq Scan on prt1_p3 + Filter: (b = 0) -> Hash - -> Seq Scan on prt1_e_p3 - Filter: (c = 0) -(43 rows) + -> Seq Scan on prt2_p3 + Filter: (a = 0) + -> Hash + -> Seq Scan on prt1_e_p3 + Filter: (c = 0) +(42 rows) SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.a = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT 50 phv, * FROM prt1_e WHERE prt1_e.c = 0) t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a = t1.phv OR t2.b = t2.phv OR (t3.a + t3.b)/2 = t3.phv ORDER BY t1.a, t2.b, t3.a + t3.b; a | phv | b | phv | ?column? | phv @@ -933,61 +926,60 @@ SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN ( EXPLAIN (COSTS OFF) SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b; - QUERY PLAN ----------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------- Sort Sort Key: t1.a, t2.b, ((t3.a + t3.b)) - -> Result - -> Append - -> Merge Left Join - Merge Cond: (t1.a = t2.b) - -> Sort - Sort Key: t1.a - -> Merge Left Join - Merge Cond: ((((t3.a + t3.b) / 2)) = t1.a) - -> Sort - Sort Key: (((t3.a + t3.b) / 2)) - -> Seq Scan on prt1_e_p1 t3 - Filter: (c = 0) - -> Sort - Sort Key: t1.a - -> Seq Scan on prt1_p1 t1 - -> Sort - Sort Key: t2.b - -> Seq Scan on prt2_p1 t2 - -> Merge Left Join - Merge Cond: (t1_1.a = t2_1.b) - -> Sort - Sort Key: t1_1.a - -> Merge Left Join - Merge Cond: ((((t3_1.a + t3_1.b) / 2)) = t1_1.a) - -> Sort - Sort Key: (((t3_1.a + t3_1.b) / 2)) - -> Seq Scan on prt1_e_p2 t3_1 - Filter: (c = 0) - -> Sort - Sort Key: t1_1.a - -> Seq Scan on prt1_p2 t1_1 - -> Sort - Sort Key: t2_1.b - -> Seq Scan on prt2_p2 t2_1 - -> Merge Left Join - Merge Cond: (t1_2.a = t2_2.b) - -> Sort - Sort Key: t1_2.a - -> Merge Left Join - Merge Cond: ((((t3_2.a + t3_2.b) / 2)) = t1_2.a) - -> Sort - Sort Key: (((t3_2.a + t3_2.b) / 2)) - -> Seq Scan on prt1_e_p3 t3_2 - Filter: (c = 0) - -> Sort - Sort Key: t1_2.a - -> Seq Scan on prt1_p3 t1_2 - -> Sort - Sort Key: t2_2.b - -> Seq Scan on prt2_p3 t2_2 -(52 rows) + -> Append + -> Merge Left Join + Merge Cond: (t1.a = t2.b) + -> Sort + Sort Key: t1.a + -> Merge Left Join + Merge Cond: ((((t3.a + t3.b) / 2)) = t1.a) + -> Sort + Sort Key: (((t3.a + t3.b) / 2)) + -> Seq Scan on prt1_e_p1 t3 + Filter: (c = 0) + -> Sort + Sort Key: t1.a + -> Seq Scan on prt1_p1 t1 + -> Sort + Sort Key: t2.b + -> Seq Scan on prt2_p1 t2 + -> Merge Left Join + Merge Cond: (t1_1.a = t2_1.b) + -> Sort + Sort Key: t1_1.a + -> Merge Left Join + Merge Cond: ((((t3_1.a + t3_1.b) / 2)) = t1_1.a) + -> Sort + Sort Key: (((t3_1.a + t3_1.b) / 2)) + -> Seq Scan on prt1_e_p2 t3_1 + Filter: (c = 0) + -> Sort + Sort Key: t1_1.a + -> Seq Scan on prt1_p2 t1_1 + -> Sort + Sort Key: t2_1.b + -> Seq Scan on prt2_p2 t2_1 + -> Merge Left Join + Merge Cond: (t1_2.a = t2_2.b) + -> Sort + Sort Key: t1_2.a + -> Merge Left Join + Merge Cond: ((((t3_2.a + t3_2.b) / 2)) = t1_2.a) + -> Sort + Sort Key: (((t3_2.a + t3_2.b) / 2)) + -> Seq Scan on prt1_e_p3 t3_2 + Filter: (c = 0) + -> Sort + Sort Key: t1_2.a + -> Seq Scan on prt1_p3 t1_2 + -> Sort + Sort Key: t2_2.b + -> Seq Scan on prt2_p3 t2_2 +(51 rows) SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b; a | c | b | c | ?column? | c @@ -1145,42 +1137,41 @@ ANALYZE plt1_e; -- test partition matching with N-way join EXPLAIN (COSTS OFF) SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM plt1 t1, plt2 t2, plt1_e t3 WHERE t1.b = t2.b AND t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------- GroupAggregate Group Key: t1.c, t2.c, t3.c -> Sort Sort Key: t1.c, t3.c - -> Result - -> Append + -> Append + -> Hash Join + Hash Cond: (t1.c = ltrim(t3.c, 'A'::text)) -> Hash Join - Hash Cond: (t1.c = ltrim(t3.c, 'A'::text)) - -> Hash Join - Hash Cond: ((t1.b = t2.b) AND (t1.c = t2.c)) - -> Seq Scan on plt1_p1 t1 - -> Hash - -> Seq Scan on plt2_p1 t2 + Hash Cond: ((t1.b = t2.b) AND (t1.c = t2.c)) + -> Seq Scan on plt1_p1 t1 -> Hash - -> Seq Scan on plt1_e_p1 t3 + -> Seq Scan on plt2_p1 t2 + -> Hash + -> Seq Scan on plt1_e_p1 t3 + -> Hash Join + Hash Cond: (t1_1.c = ltrim(t3_1.c, 'A'::text)) -> Hash Join - Hash Cond: (t1_1.c = ltrim(t3_1.c, 'A'::text)) - -> Hash Join - Hash Cond: ((t1_1.b = t2_1.b) AND (t1_1.c = t2_1.c)) - -> Seq Scan on plt1_p2 t1_1 - -> Hash - -> Seq Scan on plt2_p2 t2_1 + Hash Cond: ((t1_1.b = t2_1.b) AND (t1_1.c = t2_1.c)) + -> Seq Scan on plt1_p2 t1_1 -> Hash - -> Seq Scan on plt1_e_p2 t3_1 + -> Seq Scan on plt2_p2 t2_1 + -> Hash + -> Seq Scan on plt1_e_p2 t3_1 + -> Hash Join + Hash Cond: (t1_2.c = ltrim(t3_2.c, 'A'::text)) -> Hash Join - Hash Cond: (t1_2.c = ltrim(t3_2.c, 'A'::text)) - -> Hash Join - Hash Cond: ((t1_2.b = t2_2.b) AND (t1_2.c = t2_2.c)) - -> Seq Scan on plt1_p3 t1_2 - -> Hash - -> Seq Scan on plt2_p3 t2_2 + Hash Cond: ((t1_2.b = t2_2.b) AND (t1_2.c = t2_2.c)) + -> Seq Scan on plt1_p3 t1_2 -> Hash - -> Seq Scan on plt1_e_p3 t3_2 -(33 rows) + -> Seq Scan on plt2_p3 t2_2 + -> Hash + -> Seq Scan on plt1_e_p3 t3_2 +(32 rows) SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM plt1 t1, plt2 t2, plt1_e t3 WHERE t1.b = t2.b AND t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c; avg | avg | avg | c | c | c @@ -1290,42 +1281,41 @@ ANALYZE pht1_e; -- test partition matching with N-way join EXPLAIN (COSTS OFF) SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM pht1 t1, pht2 t2, pht1_e t3 WHERE t1.b = t2.b AND t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------- GroupAggregate Group Key: t1.c, t2.c, t3.c -> Sort Sort Key: t1.c, t3.c - -> Result - -> Append + -> Append + -> Hash Join + Hash Cond: (t1.c = ltrim(t3.c, 'A'::text)) -> Hash Join - Hash Cond: (t1.c = ltrim(t3.c, 'A'::text)) - -> Hash Join - Hash Cond: ((t1.b = t2.b) AND (t1.c = t2.c)) - -> Seq Scan on pht1_p1 t1 - -> Hash - -> Seq Scan on pht2_p1 t2 + Hash Cond: ((t1.b = t2.b) AND (t1.c = t2.c)) + -> Seq Scan on pht1_p1 t1 -> Hash - -> Seq Scan on pht1_e_p1 t3 + -> Seq Scan on pht2_p1 t2 + -> Hash + -> Seq Scan on pht1_e_p1 t3 + -> Hash Join + Hash Cond: (t1_1.c = ltrim(t3_1.c, 'A'::text)) -> Hash Join - Hash Cond: (t1_1.c = ltrim(t3_1.c, 'A'::text)) - -> Hash Join - Hash Cond: ((t1_1.b = t2_1.b) AND (t1_1.c = t2_1.c)) - -> Seq Scan on pht1_p2 t1_1 - -> Hash - -> Seq Scan on pht2_p2 t2_1 + Hash Cond: ((t1_1.b = t2_1.b) AND (t1_1.c = t2_1.c)) + -> Seq Scan on pht1_p2 t1_1 -> Hash - -> Seq Scan on pht1_e_p2 t3_1 + -> Seq Scan on pht2_p2 t2_1 + -> Hash + -> Seq Scan on pht1_e_p2 t3_1 + -> Hash Join + Hash Cond: (t1_2.c = ltrim(t3_2.c, 'A'::text)) -> Hash Join - Hash Cond: (t1_2.c = ltrim(t3_2.c, 'A'::text)) - -> Hash Join - Hash Cond: ((t1_2.b = t2_2.b) AND (t1_2.c = t2_2.c)) - -> Seq Scan on pht1_p3 t1_2 - -> Hash - -> Seq Scan on pht2_p3 t2_2 + Hash Cond: ((t1_2.b = t2_2.b) AND (t1_2.c = t2_2.c)) + -> Seq Scan on pht1_p3 t1_2 -> Hash - -> Seq Scan on pht1_e_p3 t3_2 -(33 rows) + -> Seq Scan on pht2_p3 t2_2 + -> Hash + -> Seq Scan on pht1_e_p3 t3_2 +(32 rows) SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM pht1 t1, pht2 t2, pht1_e t3 WHERE t1.b = t2.b AND t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c; avg | avg | avg | c | c | c @@ -1463,40 +1453,39 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b -- right join EXPLAIN (COSTS OFF) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.a = 0 ORDER BY t1.a, t2.b; - QUERY PLAN ------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------ Sort Sort Key: t1.a, t2.b - -> Result - -> Append - -> Hash Right Join - Hash Cond: ((t1.a = t2.b) AND ((t1.c)::text = (t2.c)::text)) - -> Seq Scan on prt1_l_p1 t1 - -> Hash - -> Seq Scan on prt2_l_p1 t2 - Filter: (a = 0) - -> Hash Right Join - Hash Cond: ((t1_1.a = t2_1.b) AND ((t1_1.c)::text = (t2_1.c)::text)) - -> Seq Scan on prt1_l_p2_p1 t1_1 - -> Hash - -> Seq Scan on prt2_l_p2_p1 t2_1 - Filter: (a = 0) - -> Hash Right Join - Hash Cond: ((t1_2.a = t2_2.b) AND ((t1_2.c)::text = (t2_2.c)::text)) - -> Seq Scan on prt1_l_p2_p2 t1_2 - -> Hash - -> Seq Scan on prt2_l_p2_p2 t2_2 - Filter: (a = 0) - -> Hash Right Join - Hash Cond: ((t1_3.a = t2_3.b) AND ((t1_3.c)::text = (t2_3.c)::text)) + -> Append + -> Hash Right Join + Hash Cond: ((t1.a = t2.b) AND ((t1.c)::text = (t2.c)::text)) + -> Seq Scan on prt1_l_p1 t1 + -> Hash + -> Seq Scan on prt2_l_p1 t2 + Filter: (a = 0) + -> Hash Right Join + Hash Cond: ((t1_1.a = t2_1.b) AND ((t1_1.c)::text = (t2_1.c)::text)) + -> Seq Scan on prt1_l_p2_p1 t1_1 + -> Hash + -> Seq Scan on prt2_l_p2_p1 t2_1 + Filter: (a = 0) + -> Hash Right Join + Hash Cond: ((t1_2.a = t2_2.b) AND ((t1_2.c)::text = (t2_2.c)::text)) + -> Seq Scan on prt1_l_p2_p2 t1_2 + -> Hash + -> Seq Scan on prt2_l_p2_p2 t2_2 + Filter: (a = 0) + -> Hash Right Join + Hash Cond: ((t1_3.a = t2_3.b) AND ((t1_3.c)::text = (t2_3.c)::text)) + -> Append + -> Seq Scan on prt1_l_p3_p1 t1_3 + -> Seq Scan on prt1_l_p3_p2 t1_4 + -> Hash -> Append - -> Seq Scan on prt1_l_p3_p1 t1_3 - -> Seq Scan on prt1_l_p3_p2 t1_4 - -> Hash - -> Append - -> Seq Scan on prt2_l_p3_p1 t2_3 - Filter: (a = 0) -(31 rows) + -> Seq Scan on prt2_l_p3_p1 t2_3 + Filter: (a = 0) +(30 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.a = 0 ORDER BY t1.a, t2.b; a | c | b | c @@ -1577,55 +1566,54 @@ EXPLAIN (COSTS OFF) SELECT * FROM prt1_l t1 LEFT JOIN LATERAL (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.b AS t3b, least(t1.a,t2.a,t3.b) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.b = 0 ORDER BY t1.a; - QUERY PLAN ------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------- Sort Sort Key: t1.a - -> Result - -> Append - -> Nested Loop Left Join - -> Seq Scan on prt1_l_p1 t1 - Filter: (b = 0) - -> Hash Join - Hash Cond: ((t3.b = t2.a) AND ((t3.c)::text = (t2.c)::text)) - -> Seq Scan on prt2_l_p1 t3 - -> Hash - -> Seq Scan on prt1_l_p1 t2 - Filter: ((t1.a = a) AND ((t1.c)::text = (c)::text)) - -> Nested Loop Left Join - -> Seq Scan on prt1_l_p2_p1 t1_1 - Filter: (b = 0) - -> Hash Join - Hash Cond: ((t3_1.b = t2_1.a) AND ((t3_1.c)::text = (t2_1.c)::text)) - -> Seq Scan on prt2_l_p2_p1 t3_1 - -> Hash - -> Seq Scan on prt1_l_p2_p1 t2_1 - Filter: ((t1_1.a = a) AND ((t1_1.c)::text = (c)::text)) - -> Nested Loop Left Join - -> Seq Scan on prt1_l_p2_p2 t1_2 + -> Append + -> Nested Loop Left Join + -> Seq Scan on prt1_l_p1 t1 + Filter: (b = 0) + -> Hash Join + Hash Cond: ((t3.b = t2.a) AND ((t3.c)::text = (t2.c)::text)) + -> Seq Scan on prt2_l_p1 t3 + -> Hash + -> Seq Scan on prt1_l_p1 t2 + Filter: ((t1.a = a) AND ((t1.c)::text = (c)::text)) + -> Nested Loop Left Join + -> Seq Scan on prt1_l_p2_p1 t1_1 + Filter: (b = 0) + -> Hash Join + Hash Cond: ((t3_1.b = t2_1.a) AND ((t3_1.c)::text = (t2_1.c)::text)) + -> Seq Scan on prt2_l_p2_p1 t3_1 + -> Hash + -> Seq Scan on prt1_l_p2_p1 t2_1 + Filter: ((t1_1.a = a) AND ((t1_1.c)::text = (c)::text)) + -> Nested Loop Left Join + -> Seq Scan on prt1_l_p2_p2 t1_2 + Filter: (b = 0) + -> Hash Join + Hash Cond: ((t3_2.b = t2_2.a) AND ((t3_2.c)::text = (t2_2.c)::text)) + -> Seq Scan on prt2_l_p2_p2 t3_2 + -> Hash + -> Seq Scan on prt1_l_p2_p2 t2_2 + Filter: ((t1_2.a = a) AND ((t1_2.c)::text = (c)::text)) + -> Nested Loop Left Join + -> Append + -> Seq Scan on prt1_l_p3_p1 t1_3 Filter: (b = 0) - -> Hash Join - Hash Cond: ((t3_2.b = t2_2.a) AND ((t3_2.c)::text = (t2_2.c)::text)) - -> Seq Scan on prt2_l_p2_p2 t3_2 - -> Hash - -> Seq Scan on prt1_l_p2_p2 t2_2 - Filter: ((t1_2.a = a) AND ((t1_2.c)::text = (c)::text)) - -> Nested Loop Left Join + -> Hash Join + Hash Cond: ((t3_3.b = t2_3.a) AND ((t3_3.c)::text = (t2_3.c)::text)) -> Append - -> Seq Scan on prt1_l_p3_p1 t1_3 - Filter: (b = 0) - -> Hash Join - Hash Cond: ((t3_3.b = t2_3.a) AND ((t3_3.c)::text = (t2_3.c)::text)) + -> Seq Scan on prt2_l_p3_p1 t3_3 + -> Seq Scan on prt2_l_p3_p2 t3_4 + -> Hash -> Append - -> Seq Scan on prt2_l_p3_p1 t3_3 - -> Seq Scan on prt2_l_p3_p2 t3_4 - -> Hash - -> Append - -> Seq Scan on prt1_l_p3_p1 t2_3 - Filter: ((t1_3.a = a) AND ((t1_3.c)::text = (c)::text)) - -> Seq Scan on prt1_l_p3_p2 t2_4 - Filter: ((t1_3.a = a) AND ((t1_3.c)::text = (c)::text)) -(46 rows) + -> Seq Scan on prt1_l_p3_p1 t2_3 + Filter: ((t1_3.a = a) AND ((t1_3.c)::text = (c)::text)) + -> Seq Scan on prt1_l_p3_p2 t2_4 + Filter: ((t1_3.a = a) AND ((t1_3.c)::text = (c)::text)) +(45 rows) SELECT * FROM prt1_l t1 LEFT JOIN LATERAL (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.b AS t3b, least(t1.a,t2.a,t3.b) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss |