summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-01-09 20:42:29 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-01-09 20:42:29 +0000
commit6a6522529fb0c1b42050f322d37d91df14d7994c (patch)
tree98cab5863d3c83be2561fb4079edbcd4486e5864 /src/backend/optimizer/plan
parent8d546c71709b5c396e54ce1a7fd49ff153a78862 (diff)
Fix some planner issues found while investigating Kevin Grittner's report
of poorer planning in 8.3 than 8.2: 1. After pushing a constant across an outer join --- ie, given "a LEFT JOIN b ON (a.x = b.y) WHERE a.x = 42", we can deduce that b.y is sort of equal to 42, in the sense that we needn't fetch any b rows where it isn't 42 --- loop to see if any additional deductions can be made. Previous releases did that by recursing, but I had mistakenly thought that this was no longer necessary given the EquivalenceClass machinery. 2. Allow pushing constants across outer join conditions even if the condition is outerjoin_delayed due to a lower outer join. This is safe as long as the condition is strict and we re-test it at the upper join. 3. Keep the outer-join clause even if we successfully push a constant across it. This is *necessary* in the outerjoin_delayed case, but even in the simple case, it seems better to do this to ensure that the join search order heuristics will consider the join as reasonable to make. Mark such a clause as having selectivity 1.0, though, since it's not going to eliminate very many rows after application of the constant condition. 4. Tweak have_relevant_eclass_joinclause to report that two relations are joinable when they have vars that are equated to the same constant. We won't actually generate any joinclause from such an EquivalenceClass, but again it seems that in such a case it's a good idea to consider the join as worth costing out. 5. Fix a bug in select_mergejoin_clauses that was exposed by these changes: we have to reject candidate mergejoin clauses if either side was equated to a constant, because we can't construct a canonical pathkey list for such a clause. This is an implementation restriction that might be worth fixing someday, but it doesn't seem critical to get it done for 8.3.
Diffstat (limited to 'src/backend/optimizer/plan')
-rw-r--r--src/backend/optimizer/plan/initsplan.c25
1 files changed, 13 insertions, 12 deletions
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 42a202b9503..0255b646a3b 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.137 2008/01/01 19:45:50 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.138 2008/01/09 20:42:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -778,13 +778,13 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
if (ojscope)
{
/* clause is attached to outer join, eval it there */
- relids = ojscope;
+ relids = bms_copy(ojscope);
/* mustn't use as gating qual, so don't mark pseudoconstant */
}
else
{
/* eval at original syntactic level */
- relids = qualscope;
+ relids = bms_copy(qualscope);
if (!contain_volatile_functions(clause))
{
/* mark as gating qual */
@@ -849,12 +849,15 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
* We can't use such a clause to deduce equivalence (the left and
* right sides might be unequal above the join because one of them has
* gone to NULL) ... but we might be able to use it for more limited
- * deductions, if there are no lower outer joins that delay its
- * application. If so, consider adding it to the lists of set-aside
- * clauses.
+ * deductions, if it is mergejoinable. So consider adding it to the
+ * lists of set-aside outer-join clauses.
*/
+ is_pushed_down = false;
maybe_equivalence = false;
- maybe_outer_join = !check_outerjoin_delay(root, &relids, false);
+ maybe_outer_join = true;
+
+ /* Check to see if must be delayed by lower outer join */
+ outerjoin_delayed = check_outerjoin_delay(root, &relids, false);
/*
* Now force the qual to be evaluated exactly at the level of joining
@@ -868,8 +871,6 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
*/
Assert(ojscope);
relids = ojscope;
- is_pushed_down = false;
- outerjoin_delayed = true;
Assert(!pseudoconstant);
}
else
@@ -880,7 +881,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
*/
is_pushed_down = true;
- /* Check to see if must be delayed by outer join */
+ /* Check to see if must be delayed by lower outer join */
outerjoin_delayed = check_outerjoin_delay(root, &relids, true);
if (outerjoin_delayed)
@@ -1052,8 +1053,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
* mentioning only C cannot be applied below the join to A.
*
* For a non-pushed-down qual, this isn't going to determine where we place the
- * qual, but we need to determine outerjoin_delayed anyway so we can decide
- * whether the qual is potentially useful for equivalence deductions.
+ * qual, but we need to determine outerjoin_delayed anyway for possible use
+ * in reconsider_outer_join_clauses().
*
* Lastly, a pushed-down qual that references the nullable side of any current
* oj_info_list member and has to be evaluated above that OJ (because its