@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $ PostgreSQL : pgsql / src / backend / optimizer / path / joinpath . c , v 1.101 2006 / 02 / 04 23 : 03 : 20 tgl Exp $
* $ PostgreSQL : pgsql / src / backend / optimizer / path / joinpath . c , v 1.102 2006 / 02 / 05 02 : 59 : 16 tgl Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -35,9 +35,8 @@ static void match_unsorted_outer(PlannerInfo *root, RelOptInfo *joinrel,
static void hash_inner_and_outer ( PlannerInfo * root , RelOptInfo * joinrel ,
RelOptInfo * outerrel , RelOptInfo * innerrel ,
List * restrictlist , JoinType jointype ) ;
static void join_before_append ( PlannerInfo * root , RelOptInfo * joinrel ,
RelOptInfo * outerrel , RelOptInfo * innerrel ,
JoinType jointype ) ;
static Path * best_appendrel_indexscan ( PlannerInfo * root , RelOptInfo * rel ,
Relids outer_relids , JoinType jointype ) ;
static List * select_mergejoin_clauses ( RelOptInfo * joinrel ,
RelOptInfo * outerrel ,
RelOptInfo * innerrel ,
@ -118,13 +117,6 @@ add_paths_to_joinrel(PlannerInfo *root,
if ( enable_hashjoin )
hash_inner_and_outer ( root , joinrel , outerrel , innerrel ,
restrictlist , jointype ) ;
/*
* 5. If the inner relation is an append relation , consider joining
* the outer rel to each append member and then appending the results .
*/
if ( innerrel - > cheapest_total_path - > pathtype = = T_Append )
join_before_append ( root , joinrel , outerrel , innerrel , jointype ) ;
}
/*
@ -405,8 +397,17 @@ match_unsorted_outer(PlannerInfo *root,
* Get the best innerjoin indexpath ( if any ) for this outer rel . It ' s
* the same for all outer paths .
*/
bestinnerjoin = best_inner_indexscan ( root , innerrel ,
outerrel - > relids , jointype ) ;
if ( innerrel - > reloptkind ! = RELOPT_JOINREL )
{
if ( IsA ( inner_cheapest_total , AppendPath ) )
bestinnerjoin = best_appendrel_indexscan ( root , innerrel ,
outerrel - > relids ,
jointype ) ;
else if ( innerrel - > rtekind = = RTE_RELATION )
bestinnerjoin = best_inner_indexscan ( root , innerrel ,
outerrel - > relids ,
jointype ) ;
}
}
foreach ( l , outerrel - > pathlist )
@ -788,75 +789,27 @@ hash_inner_and_outer(PlannerInfo *root,
}
/*
* join_before_append
* Creates possible join paths for processing a single join relation
* ' joinrel ' when the inner input is an append relation .
*
* The idea here is to swap the order of the APPEND and JOIN operators .
* This is only really helpful if it allows us to reduce the cost of
* scanning the members of the append relation , and so we only consider
* plans involving nestloops with inner indexscans . Also , since the APPEND
* will certainly yield an unsorted result , there ' s no point in considering
* any but the cheapest - total outer path .
*
* XXX this is a bit of a kluge , because the resulting plan has to evaluate
* the outer relation multiple times . Would be better to allow
* best_inner_indexscan to generate an AppendPath and not have this routine
* at all . But we can ' t do that without some executor changes ( need a way
* to pass outer keys down through Append ) . FIXME later .
*
* ' joinrel ' is the join relation
* ' outerrel ' is the outer join relation
* ' innerrel ' is the inner join relation
* ' jointype ' is the type of join to do
* best_appendrel_indexscan
* Finds the best available set of inner indexscans for a nestloop join
* with the given append relation on the inside and the given outer_relids
* outside . Returns an AppendPath comprising the best inner scans , or
* NULL if there are no possible inner indexscans .
*/
static void
join_before_append ( PlannerInfo * root ,
RelOptInfo * joinrel ,
RelOptInfo * outerrel ,
RelOptInfo * innerrel ,
JoinType jointype )
static Path *
best_appendrel_indexscan ( PlannerInfo * root , RelOptInfo * rel ,
Relids outer_relids , JoinType jointype )
{
Path * outer_cheapest_total = outerrel - > cheapest_total_path ;
int parentRTindex = innerrel - > relid ;
int parentRTindex = rel - > relid ;
List * append_paths = NIL ;
bool found_indexscan = false ;
ListCell * l ;
/*
* Swapping JOIN with APPEND only works for inner joins , not outer joins .
* However , we can also handle a unique - ified outer path .
*/
switch ( jointype )
{
case JOIN_INNER :
break ;
case JOIN_UNIQUE_OUTER :
outer_cheapest_total = ( Path * )
create_unique_path ( root , outerrel , outer_cheapest_total ) ;
break ;
case JOIN_LEFT :
case JOIN_RIGHT :
case JOIN_FULL :
case JOIN_IN :
case JOIN_UNIQUE_INNER :
return ; /* can't join this way */
default :
elog ( ERROR , " unrecognized join type: %d " ,
( int ) jointype ) ;
break ;
}
/*
* Generate suitable access paths for each member relation .
*/
foreach ( l , root - > append_rel_list )
{
AppendRelInfo * appinfo = ( AppendRelInfo * ) lfirst ( l ) ;
int childRTindex ;
RelOptInfo * childrel ;
Path * bestinnerjoin ;
RelOptInfo * this_joinrel ;
List * this_restrictlist ;
/* append_rel_list contains all append rels; ignore others */
if ( appinfo - > parent_relid ! = parentRTindex )
@ -876,42 +829,30 @@ join_before_append(PlannerInfo *root,
continue ; /* OK, we can ignore it */
/*
* Get the best innerjoin indexpath ( if any ) for this outer rel .
* Get the best innerjoin indexpath ( if any ) for this child rel .
*/
bestinnerjoin = best_inner_indexscan ( root , childrel ,
outerrel - > relids , JOIN_INNER ) ;
outer_relids , jointype ) ;
/*
* If no luck on an indexpath for this rel , we ' ll still consider
* an Append substituting the cheapest - total inner path . This
* is only likely to win if there ' s at least one member rel for
* which an indexscan path does exist .
* an Append substituting the cheapest - total inner path . However
* we must find at least one indexpath , else there ' s not going to
* be any improvement over the base path for the appendrel .
*/
if ( ! bestinnerjoin )
if ( bestinnerjoin )
found_indexscan = true ;
else
bestinnerjoin = childrel - > cheapest_total_path ;
/*
* We need a joinrel that describes this join accurately . Although
* the joinrel won ' t ever be used by the join path search algorithm
* in joinrels . c , it provides necessary context for the Path ,
* such as properly - translated target and quals lists .
*/
this_joinrel = translate_join_rel ( root , joinrel , appinfo ,
outerrel , childrel , jointype ,
& this_restrictlist ) ;
/* Build Path for join and add to result list */
append_paths = lappend ( append_paths ,
create_nestloop_path ( root ,
this_joinrel ,
JOIN_INNER ,
outer_cheapest_total ,
bestinnerjoin ,
this_restrictlist ,
NIL ) ) ;
append_paths = lappend ( append_paths , bestinnerjoin ) ;
}
/* Form the completed Append path and add it to the join relation. */
add_path ( joinrel , ( Path * ) create_append_path ( joinrel , append_paths ) ) ;
if ( ! found_indexscan )
return NULL ;
/* Form and return the completed Append path. */
return ( Path * ) create_append_path ( rel , append_paths ) ;
}
/*