@@ -154,13 +154,17 @@ add_paths_to_joinrel(PlannerInfo *root,
154154 /*
155155 * See if the inner relation is provably unique for this outer rel.
156156 *
157- * We have some special cases: for JOIN_SEMI and JOIN_ANTI, it doesn't
158- * matter since the executor can make the equivalent optimization anyway;
159- * we need not expend planner cycles on proofs. For JOIN_UNIQUE_INNER, we
160- * must be considering a semijoin whose inner side is not provably unique
161- * (else reduce_unique_semijoins would've simplified it), so there's no
162- * point in calling innerrel_is_unique. However, if the LHS covers all of
163- * the semijoin's min_lefthand, then it's appropriate to set inner_unique
157+ * We have some special cases: for JOIN_SEMI, it doesn't matter since the
158+ * executor can make the equivalent optimization anyway. It also doesn't
159+ * help enable use of Memoize, since a semijoin with a provably unique
160+ * inner side should have been reduced to an inner join in that case.
161+ * Therefore, we need not expend planner cycles on proofs. (For
162+ * JOIN_ANTI, although it doesn't help the executor for the same reason,
163+ * it can benefit Memoize paths.) For JOIN_UNIQUE_INNER, we must be
164+ * considering a semijoin whose inner side is not provably unique (else
165+ * reduce_unique_semijoins would've simplified it), so there's no point in
166+ * calling innerrel_is_unique. However, if the LHS covers all of the
167+ * semijoin's min_lefthand, then it's appropriate to set inner_unique
164168 * because the path produced by create_unique_path will be unique relative
165169 * to the LHS. (If we have an LHS that's only part of the min_lefthand,
166170 * that is *not* true.) For JOIN_UNIQUE_OUTER, pass JOIN_INNER to avoid
@@ -169,12 +173,6 @@ add_paths_to_joinrel(PlannerInfo *root,
169173 switch (jointype )
170174 {
171175 case JOIN_SEMI :
172- case JOIN_ANTI :
173-
174- /*
175- * XXX it may be worth proving this to allow a Memoize to be
176- * considered for Nested Loop Semi/Anti Joins.
177- */
178176 extra .inner_unique = false; /* well, unproven */
179177 break ;
180178 case JOIN_UNIQUE_INNER :
@@ -715,16 +713,21 @@ get_memoize_path(PlannerInfo *root, RelOptInfo *innerrel,
715713 return NULL ;
716714
717715 /*
718- * Currently we don't do this for SEMI and ANTI joins unless they're
719- * marked as inner_unique. This is because nested loop SEMI/ANTI joins
720- * don't scan the inner node to completion, which will mean memoize cannot
721- * mark the cache entry as complete.
722- *
723- * XXX Currently we don't attempt to mark SEMI/ANTI joins as inner_unique
724- * = true. Should we? See add_paths_to_joinrel()
716+ * Currently we don't do this for SEMI and ANTI joins, because nested loop
717+ * SEMI/ANTI joins don't scan the inner node to completion, which means
718+ * memoize cannot mark the cache entry as complete. Nor can we mark the
719+ * cache entry as complete after fetching the first inner tuple, because
720+ * if that tuple and the current outer tuple don't satisfy the join
721+ * clauses, a second inner tuple that satisfies the parameters would find
722+ * the cache entry already marked as complete. The only exception is when
723+ * the inner relation is provably unique, as in that case, there won't be
724+ * a second matching tuple and we can safely mark the cache entry as
725+ * complete after fetching the first inner tuple. Note that in such
726+ * cases, the SEMI join should have been reduced to an inner join by
727+ * reduce_unique_semijoins.
725728 */
726- if (! extra -> inner_unique && (jointype == JOIN_SEMI ||
727- jointype == JOIN_ANTI ) )
729+ if ((jointype == JOIN_SEMI || jointype == JOIN_ANTI ) &&
730+ ! extra -> inner_unique )
728731 return NULL ;
729732
730733 /*
0 commit comments