diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-01-30 17:04:31 -0500 | 
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-01-30 17:05:15 -0500 | 
| commit | 1df57f63f3f60c684aa8918910ac410e9c780713 (patch) | |
| tree | 7a51e5befb4b87f929ae0c711fa7e37314d0bbb0 /src | |
| parent | 2fb64d857003c91378ba86b03d753a63ebee95b2 (diff) | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/backend/optimizer/prep/prepjointree.c | 11 | 
1 files changed, 8 insertions, 3 deletions
| diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index dbe7836b423..5a49768c6ce 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -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; | 
