From 9688c4e6f1516d2fc0db5d200112c4d91538878d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 30 Jan 2011 17:04:31 -0500 Subject: [PATCH] Make reduce_outer_joins() smarter about semijoins. reduce_outer_joins() mistakenly treated a semijoin like a left join for purposes of deciding whether not-null constraints created by the join's quals could be passed down into the join's left-hand side (possibly resulting in outer-join simplification there). Actually, semijoin works like inner join for this purpose, ie, we do not need to see any rows that can't possibly satisfy the quals. Hence, two-line fix to treat semi and inner joins alike. Per observation by Andres Freund about a performance gripe from Yazan Suleiman. Back-patch to 8.4, since this oversight has been there since the current handling of semijoins was implemented. --- src/backend/optimizer/prep/prepjointree.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index c386586f40..f92bcd41b1 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -1840,6 +1840,11 @@ reduce_outer_joins_pass2(Node *jtnode, * is that we pass either the local or the upper constraints, * never both, to the children of an outer join. * + * Note that a SEMI join works like an inner join here: it's okay + * to pass down both local and upper constraints. (There can't + * be any upper constraints affecting its inner side, but it's + * not worth having a separate code path to avoid passing them.) + * * At a FULL join we just punt and pass nothing down --- is it * possible to be smarter? */ @@ -1849,7 +1854,7 @@ reduce_outer_joins_pass2(Node *jtnode, if (!computed_local_nonnullable_vars) local_nonnullable_vars = find_nonnullable_vars(j->quals); local_forced_null_vars = find_forced_null_vars(j->quals); - if (jointype == JOIN_INNER) + if (jointype == JOIN_INNER || jointype == JOIN_SEMI) { /* OK to merge upper and local constraints */ local_nonnullable_rels = bms_add_members(local_nonnullable_rels, @@ -1869,14 +1874,14 @@ reduce_outer_joins_pass2(Node *jtnode, if (left_state->contains_outer) { - if (jointype == JOIN_INNER) + if (jointype == JOIN_INNER || jointype == JOIN_SEMI) { /* pass union of local and upper constraints */ pass_nonnullable_rels = local_nonnullable_rels; pass_nonnullable_vars = local_nonnullable_vars; pass_forced_null_vars = local_forced_null_vars; } - else if (jointype != JOIN_FULL) /* ie, LEFT/SEMI/ANTI */ + else if (jointype != JOIN_FULL) /* ie, LEFT or ANTI */ { /* can't pass local constraints to non-nullable side */ pass_nonnullable_rels = nonnullable_rels;