mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-24 18:55:04 +08:00
Adjust join_search_one_level's handling of clauseless joins.
For an initial relation that lacks any join clauses (that is, it has to be cartesian-product-joined to the rest of the query), we considered only cartesian joins with initial rels appearing later in the initial-relations list. This creates an undesirable dependency on FROM-list order. We would never fail to find a plan, but perhaps we might not find the best available plan. Noted while discussing the logic with Amit Kapila. Improve the comments a bit in this area, too. Arguably this is a bug fix, but given the lack of complaints from the field I'll refrain from back-patching.
This commit is contained in:
parent
5b7b5518d0
commit
1f03630011
@ -65,33 +65,34 @@ join_search_one_level(PlannerInfo *root, int level)
|
|||||||
* We prefer to join using join clauses, but if we find a rel of level-1
|
* We prefer to join using join clauses, but if we find a rel of level-1
|
||||||
* members that has no join clauses, we will generate Cartesian-product
|
* members that has no join clauses, we will generate Cartesian-product
|
||||||
* joins against all initial rels not already contained in it.
|
* joins against all initial rels not already contained in it.
|
||||||
*
|
|
||||||
* In the first pass (level == 2), we try to join each initial rel to each
|
|
||||||
* initial rel that appears later in joinrels[1]. (The mirror-image joins
|
|
||||||
* are handled automatically by make_join_rel.) In later passes, we try
|
|
||||||
* to join rels of size level-1 from joinrels[level-1] to each initial rel
|
|
||||||
* in joinrels[1].
|
|
||||||
*/
|
*/
|
||||||
foreach(r, joinrels[level - 1])
|
foreach(r, joinrels[level - 1])
|
||||||
{
|
{
|
||||||
RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
|
RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
|
||||||
ListCell *other_rels;
|
|
||||||
|
|
||||||
if (level == 2)
|
|
||||||
other_rels = lnext(r); /* only consider remaining initial
|
|
||||||
* rels */
|
|
||||||
else
|
|
||||||
other_rels = list_head(joinrels[1]); /* consider all initial
|
|
||||||
* rels */
|
|
||||||
|
|
||||||
if (old_rel->joininfo != NIL || old_rel->has_eclass_joins ||
|
if (old_rel->joininfo != NIL || old_rel->has_eclass_joins ||
|
||||||
has_join_restriction(root, old_rel))
|
has_join_restriction(root, old_rel))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* There are relevant join clauses or join order restrictions,
|
* There are join clauses or join order restrictions relevant to
|
||||||
* so consider joins between this rel and (only) those rels it is
|
* this rel, so consider joins between this rel and (only) those
|
||||||
* linked to by a clause or restriction.
|
* initial rels it is linked to by a clause or restriction.
|
||||||
|
*
|
||||||
|
* At level 2 this condition is symmetric, so there is no need to
|
||||||
|
* look at initial rels before this one in the list; we already
|
||||||
|
* considered such joins when we were at the earlier rel. (The
|
||||||
|
* mirror-image joins are handled automatically by make_join_rel.)
|
||||||
|
* In later passes (level > 2), we join rels of the previous level
|
||||||
|
* to each initial rel they don't already include but have a join
|
||||||
|
* clause or restriction with.
|
||||||
*/
|
*/
|
||||||
|
ListCell *other_rels;
|
||||||
|
|
||||||
|
if (level == 2) /* consider remaining initial rels */
|
||||||
|
other_rels = lnext(r);
|
||||||
|
else /* consider all initial rels */
|
||||||
|
other_rels = list_head(joinrels[1]);
|
||||||
|
|
||||||
make_rels_by_clause_joins(root,
|
make_rels_by_clause_joins(root,
|
||||||
old_rel,
|
old_rel,
|
||||||
other_rels);
|
other_rels);
|
||||||
@ -102,10 +103,17 @@ join_search_one_level(PlannerInfo *root, int level)
|
|||||||
* Oops, we have a relation that is not joined to any other
|
* Oops, we have a relation that is not joined to any other
|
||||||
* relation, either directly or by join-order restrictions.
|
* relation, either directly or by join-order restrictions.
|
||||||
* Cartesian product time.
|
* Cartesian product time.
|
||||||
|
*
|
||||||
|
* We consider a cartesian product with each not-already-included
|
||||||
|
* initial rel, whether it has other join clauses or not. At
|
||||||
|
* level 2, if there are two or more clauseless initial rels, we
|
||||||
|
* will redundantly consider joining them in both directions; but
|
||||||
|
* such cases aren't common enough to justify adding complexity to
|
||||||
|
* avoid the duplicated effort.
|
||||||
*/
|
*/
|
||||||
make_rels_by_clauseless_joins(root,
|
make_rels_by_clauseless_joins(root,
|
||||||
old_rel,
|
old_rel,
|
||||||
other_rels);
|
list_head(joinrels[1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +143,7 @@ join_search_one_level(PlannerInfo *root, int level)
|
|||||||
ListCell *r2;
|
ListCell *r2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can ignore clauseless joins here, *except* when they
|
* We can ignore relations without join clauses here, unless they
|
||||||
* participate in join-order restrictions --- then we might have
|
* participate in join-order restrictions --- then we might have
|
||||||
* to force a bushy join plan.
|
* to force a bushy join plan.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user