OSDN Git Service

Make reduce_outer_joins() smarter about semijoins.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 30 Jan 2011 22:04:31 +0000 (17:04 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 30 Jan 2011 22:05:15 +0000 (17:05 -0500)
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

index dbe7836..5a49768 100644 (file)
@@ -1745,6 +1745,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?
                         */
@@ -1754,7 +1759,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,
@@ -1774,14 +1779,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;