index 35c9353d2e21888000e874346e9dece81b765b5c..f069f13fefb5115ed3577ec5a25c68d4ad780b24 100644 (file)
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.130 2010年02月26日 02:00:44 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.131 2010年03月22日 13:57:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -192,7 +192,9 @@ clause_sides_match_join(RestrictInfo *rinfo, RelOptInfo *outerrel,
*
* This is true for a left join for which the join condition cannot match
* more than one inner-side row. (There are other possibly interesting
- * cases, but we don't have the infrastructure to prove them.)
+ * cases, but we don't have the infrastructure to prove them.) We also
+ * have to check that the inner side doesn't generate any variables needed
+ * above the join.
*
* Note: there is no need to consider the symmetrical case of duplicating the
* right input, because add_paths_to_joinrel() will be called with each rel
return false;
}
+ /*
+ * Similarly check that the inner rel doesn't produce any PlaceHolderVars
+ * that will be used above the join.
+ */
+ foreach(l, root->placeholder_list)
+ {
+ PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(l);
+
+ if (bms_is_subset(phinfo->ph_eval_at, innerrel->relids) &&
+ !bms_is_subset(phinfo->ph_needed, joinrel->relids))
+ return false;
+ }
+
/*
* Search for mergejoinable clauses that constrain the inner rel against
* either the outer rel or a pseudoconstant. If an operator is
index f2b346e50841bb05287dba3100321efb2fc6b4b9..ad164e1c02bf0cdc98d7be1aa31e82885de3c893 100644 (file)
@@ -2491,3 +2491,52 @@ select * from int4_tbl a full join int4_tbl b on false;
-2147483647 |
(10 rows)
+--
+-- test join removal
+--
+create temp table parent (k int primary key, pd int);
+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "parent_pkey" for table "parent"
+create temp table child (k int unique, cd int);
+NOTICE: CREATE TABLE / UNIQUE will create implicit index "child_k_key" for table "child"
+insert into parent values (1, 10), (2, 20), (3, 30);
+insert into child values (1, 100), (4, 400);
+-- this case is optimizable
+select p.* from parent p left join child c on (p.k = c.k);
+ k | pd
+---+----
+ 1 | 10
+ 2 | 20
+ 3 | 30
+(3 rows)
+
+explain (costs off)
+ select p.* from parent p left join child c on (p.k = c.k);
+ QUERY PLAN
+----------------------
+ Seq Scan on parent p
+(1 row)
+
+-- this case is not
+select p.*, linked from parent p
+ left join (select c.*, true as linked from child c) as ss
+ on (p.k = ss.k);
+ k | pd | linked
+---+----+--------
+ 1 | 10 | t
+ 2 | 20 |
+ 3 | 30 |
+(3 rows)
+
+explain (costs off)
+ select p.*, linked from parent p
+ left join (select c.*, true as linked from child c) as ss
+ on (p.k = ss.k);
+ QUERY PLAN
+---------------------------------
+ Hash Left Join
+ Hash Cond: (p.k = c.k)
+ -> Seq Scan on parent p
+ -> Hash
+ -> Seq Scan on child c
+(5 rows)
+
index 977765551d5a020c6bda8f55b16539ff67212c3a..b0a4ceccf0bd578406323370536a0127174a3b14 100644 (file)
--
select * from int4_tbl a full join int4_tbl b on true;
select * from int4_tbl a full join int4_tbl b on false;
+
+--
+-- test join removal
+--
+
+create temp table parent (k int primary key, pd int);
+create temp table child (k int unique, cd int);
+insert into parent values (1, 10), (2, 20), (3, 30);
+insert into child values (1, 100), (4, 400);
+
+-- this case is optimizable
+select p.* from parent p left join child c on (p.k = c.k);
+explain (costs off)
+ select p.* from parent p left join child c on (p.k = c.k);
+
+-- this case is not
+select p.*, linked from parent p
+ left join (select c.*, true as linked from child c) as ss
+ on (p.k = ss.k);
+explain (costs off)
+ select p.*, linked from parent p
+ left join (select c.*, true as linked from child c) as ss
+ on (p.k = ss.k);