summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/joinpath.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2017-05-01 14:53:42 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2017-05-01 14:53:42 -0400
commit92a43e4857d9682b93c9f755f453cc8fd7c66c81 (patch)
tree804a1b8aa610596b00e53453894fafd94b28039a /src/backend/optimizer/path/joinpath.c
parent2057a58d1629ebffce694e3cef7f714571a88dd7 (diff)
Reduce semijoins with unique inner relations to plain inner joins.
If the inner relation can be proven unique, that is it can have no more than one matching row for any row of the outer query, then we might as well implement the semijoin as a plain inner join, allowing substantially more freedom to the planner. This is a form of outer join strength reduction, but it can't be implemented in reduce_outer_joins() because we don't have enough info about the individual relations at that stage. Instead do it much like remove_useless_joins(): once we've built base relations, we can make another pass over the SpecialJoinInfo list and get rid of any entries representing reducible semijoins. This is essentially a followon to the inner-unique patch (commit 9c7f5229a) and makes use of the proof machinery that that patch created. We need only minor refactoring of innerrel_is_unique's API to support this usage. Per performance complaint from Teodor Sigaev. Discussion: https://postgr.es/m/f994fc98-389f-4a46-d1bc-c42e05cb43ed@sigaev.ru
Diffstat (limited to 'src/backend/optimizer/path/joinpath.c')
-rw-r--r--src/backend/optimizer/path/joinpath.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index 39e2ddda906..c130d2f17f2 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -126,13 +126,15 @@ add_paths_to_joinrel(PlannerInfo *root,
*
* We have some special cases: for JOIN_SEMI and JOIN_ANTI, it doesn't
* matter since the executor can make the equivalent optimization anyway;
- * we need not expend planner cycles on proofs. For JOIN_UNIQUE_INNER, if
- * the LHS covers all of the associated semijoin's min_lefthand, then it's
- * appropriate to set inner_unique because the path produced by
- * create_unique_path will be unique relative to the LHS. (If we have an
- * LHS that's only part of the min_lefthand, that is *not* true.) For
- * JOIN_UNIQUE_OUTER, pass JOIN_INNER to avoid letting that value escape
- * this module.
+ * we need not expend planner cycles on proofs. For JOIN_UNIQUE_INNER, we
+ * must be considering a semijoin whose inner side is not provably unique
+ * (else reduce_unique_semijoins would've simplified it), so there's no
+ * point in calling innerrel_is_unique. However, if the LHS covers all of
+ * the semijoin's min_lefthand, then it's appropriate to set inner_unique
+ * because the path produced by create_unique_path will be unique relative
+ * to the LHS. (If we have an LHS that's only part of the min_lefthand,
+ * that is *not* true.) For JOIN_UNIQUE_OUTER, pass JOIN_INNER to avoid
+ * letting that value escape this module.
*/
switch (jointype)
{
@@ -145,12 +147,20 @@ add_paths_to_joinrel(PlannerInfo *root,
outerrel->relids);
break;
case JOIN_UNIQUE_OUTER:
- extra.inner_unique = innerrel_is_unique(root, outerrel, innerrel,
- JOIN_INNER, restrictlist);
+ extra.inner_unique = innerrel_is_unique(root,
+ outerrel->relids,
+ innerrel,
+ JOIN_INNER,
+ restrictlist,
+ false);
break;
default:
- extra.inner_unique = innerrel_is_unique(root, outerrel, innerrel,
- jointype, restrictlist);
+ extra.inner_unique = innerrel_is_unique(root,
+ outerrel->relids,
+ innerrel,
+ jointype,
+ restrictlist,
+ false);
break;
}