@@ -141,9 +141,11 @@ static double ineq_histogram_selectivity(PlannerInfo *root,
141
141
FmgrInfo * opproc , bool isgt ,
142
142
Datum constval , Oid consttype );
143
143
static double eqjoinsel_inner (Oid operator ,
144
- VariableStatData * vardata1 , VariableStatData * vardata2 );
144
+ VariableStatData * vardata1 , VariableStatData * vardata2 ,
145
+ RelOptInfo * rel1 , RelOptInfo * rel2 );
145
146
static double eqjoinsel_semi (Oid operator ,
146
- VariableStatData * vardata1 , VariableStatData * vardata2 );
147
+ VariableStatData * vardata1 , VariableStatData * vardata2 ,
148
+ RelOptInfo * rel1 , RelOptInfo * rel2 );
147
149
static bool convert_to_scalar (Datum value , Oid valuetypid , double * scaledvalue ,
148
150
Datum lobound , Datum hibound , Oid boundstypid ,
149
151
double * scaledlobound , double * scaledhibound );
@@ -172,6 +174,7 @@ static bool get_actual_variable_range(PlannerInfo *root,
172
174
VariableStatData * vardata ,
173
175
Oid sortop ,
174
176
Datum * min , Datum * max );
177
+ static RelOptInfo * find_join_input_rel (PlannerInfo * root , Relids relids );
175
178
static Selectivity prefix_selectivity (PlannerInfo * root ,
176
179
VariableStatData * vardata ,
177
180
Oid vartype , Oid opfamily , Const * prefixcon );
@@ -2007,24 +2010,47 @@ eqjoinsel(PG_FUNCTION_ARGS)
2007
2010
VariableStatData vardata1 ;
2008
2011
VariableStatData vardata2 ;
2009
2012
bool join_is_reversed ;
2013
+ RelOptInfo * rel1 ;
2014
+ RelOptInfo * rel2 ;
2010
2015
2011
2016
get_join_variables (root , args , sjinfo ,
2012
2017
& vardata1 , & vardata2 , & join_is_reversed );
2013
2018
2019
+ /*
2020
+ * Identify the join's direct input relations. We use the min lefthand
2021
+ * and min righthand as the inputs, even though the join might actually
2022
+ * get done with larger input relations. The min inputs are guaranteed to
2023
+ * have been formed by now, though, and always using them ensures
2024
+ * consistency of estimates.
2025
+ */
2026
+ if (!join_is_reversed )
2027
+ {
2028
+ rel1 = find_join_input_rel (root , sjinfo -> min_lefthand );
2029
+ rel2 = find_join_input_rel (root , sjinfo -> min_righthand );
2030
+ }
2031
+ else
2032
+ {
2033
+ rel1 = find_join_input_rel (root , sjinfo -> min_righthand );
2034
+ rel2 = find_join_input_rel (root , sjinfo -> min_lefthand );
2035
+ }
2036
+
2014
2037
switch (sjinfo -> jointype )
2015
2038
{
2016
2039
case JOIN_INNER :
2017
2040
case JOIN_LEFT :
2018
2041
case JOIN_FULL :
2019
- selec = eqjoinsel_inner (operator , & vardata1 , & vardata2 );
2042
+ selec = eqjoinsel_inner (operator , & vardata1 , & vardata2 ,
2043
+ rel1 , rel2 );
2020
2044
break ;
2021
2045
case JOIN_SEMI :
2022
2046
case JOIN_ANTI :
2023
2047
if (!join_is_reversed )
2024
- selec = eqjoinsel_semi (operator , & vardata1 , & vardata2 );
2048
+ selec = eqjoinsel_semi (operator , & vardata1 , & vardata2 ,
2049
+ rel1 , rel2 );
2025
2050
else
2026
2051
selec = eqjoinsel_semi (get_commutator (operator ),
2027
- & vardata2 , & vardata1 );
2052
+ & vardata2 , & vardata1 ,
2053
+ rel2 , rel1 );
2028
2054
break ;
2029
2055
default :
2030
2056
/* other values not expected here */
@@ -2050,7 +2076,8 @@ eqjoinsel(PG_FUNCTION_ARGS)
2050
2076
*/
2051
2077
static double
2052
2078
eqjoinsel_inner (Oid operator ,
2053
- VariableStatData * vardata1 , VariableStatData * vardata2 )
2079
+ VariableStatData * vardata1 , VariableStatData * vardata2 ,
2080
+ RelOptInfo * rel1 , RelOptInfo * rel2 )
2054
2081
{
2055
2082
double selec ;
2056
2083
double nd1 ;
@@ -2251,15 +2278,19 @@ eqjoinsel_inner(Oid operator,
2251
2278
* be, providing a crude correction for the selectivity of restriction
2252
2279
* clauses on those relations. (We don't do that in the other path
2253
2280
* since there we are comparing the nd values to stats for the whole
2254
- * relations.)
2281
+ * relations.) We can apply this clamp both with respect to the base
2282
+ * relations from which the join variables come, and to the immediate
2283
+ * input relations of the current join.
2255
2284
*/
2256
2285
double nullfrac1 = stats1 ? stats1 -> stanullfrac : 0.0 ;
2257
2286
double nullfrac2 = stats2 ? stats2 -> stanullfrac : 0.0 ;
2258
2287
2259
2288
if (vardata1 -> rel )
2260
2289
nd1 = Min (nd1 , vardata1 -> rel -> rows );
2290
+ nd1 = Min (nd1 , rel1 -> rows );
2261
2291
if (vardata2 -> rel )
2262
2292
nd2 = Min (nd2 , vardata2 -> rel -> rows );
2293
+ nd2 = Min (nd2 , rel2 -> rows );
2263
2294
2264
2295
selec = (1.0 - nullfrac1 ) * (1.0 - nullfrac2 );
2265
2296
if (nd1 > nd2 )
@@ -2286,7 +2317,8 @@ eqjoinsel_inner(Oid operator,
2286
2317
*/
2287
2318
static double
2288
2319
eqjoinsel_semi (Oid operator ,
2289
- VariableStatData * vardata1 , VariableStatData * vardata2 )
2320
+ VariableStatData * vardata1 , VariableStatData * vardata2 ,
2321
+ RelOptInfo * rel1 , RelOptInfo * rel2 )
2290
2322
{
2291
2323
double selec ;
2292
2324
double nd1 ;
@@ -2434,8 +2466,10 @@ eqjoinsel_semi(Oid operator,
2434
2466
{
2435
2467
if (vardata1 -> rel )
2436
2468
nd1 = Min (nd1 , vardata1 -> rel -> rows );
2469
+ nd1 = Min (nd1 , rel1 -> rows );
2437
2470
if (vardata2 -> rel )
2438
2471
nd2 = Min (nd2 , vardata2 -> rel -> rows );
2472
+ nd2 = Min (nd2 , rel2 -> rows );
2439
2473
2440
2474
if (nd1 <= nd2 || nd2 <= 0 )
2441
2475
selec = 1.0 - nullfrac1 ;
@@ -4758,6 +4792,37 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata,
4758
4792
return have_data ;
4759
4793
}
4760
4794
4795
+ /*
4796
+ * find_join_input_rel
4797
+ * Look up the input relation for a join.
4798
+ *
4799
+ * We assume that the input relation's RelOptInfo must have been constructed
4800
+ * already.
4801
+ */
4802
+ static RelOptInfo *
4803
+ find_join_input_rel (PlannerInfo * root , Relids relids )
4804
+ {
4805
+ RelOptInfo * rel = NULL ;
4806
+
4807
+ switch (bms_membership (relids ))
4808
+ {
4809
+ case BMS_EMPTY_SET :
4810
+ /* should not happen */
4811
+ break ;
4812
+ case BMS_SINGLETON :
4813
+ rel = find_base_rel (root , bms_singleton_member (relids ));
4814
+ break ;
4815
+ case BMS_MULTIPLE :
4816
+ rel = find_join_rel (root , relids );
4817
+ break ;
4818
+ }
4819
+
4820
+ if (rel == NULL )
4821
+ elog (ERROR , "could not find RelOptInfo for given relids" );
4822
+
4823
+ return rel ;
4824
+ }
4825
+
4761
4826
4762
4827
/*-------------------------------------------------------------------------
4763
4828
*
0 commit comments