@@ -139,9 +139,11 @@ static double ineq_histogram_selectivity(PlannerInfo *root,
139
139
FmgrInfo * opproc , bool isgt ,
140
140
Datum constval , Oid consttype );
141
141
static double eqjoinsel_inner (Oid operator ,
142
- VariableStatData * vardata1 , VariableStatData * vardata2 );
142
+ VariableStatData * vardata1 , VariableStatData * vardata2 ,
143
+ RelOptInfo * rel1 , RelOptInfo * rel2 );
143
144
static double eqjoinsel_semi (Oid operator ,
144
- VariableStatData * vardata1 , VariableStatData * vardata2 );
145
+ VariableStatData * vardata1 , VariableStatData * vardata2 ,
146
+ RelOptInfo * rel1 , RelOptInfo * rel2 );
145
147
static bool convert_to_scalar (Datum value , Oid valuetypid , double * scaledvalue ,
146
148
Datum lobound , Datum hibound , Oid boundstypid ,
147
149
double * scaledlobound , double * scaledhibound );
@@ -170,6 +172,7 @@ static bool get_actual_variable_range(PlannerInfo *root,
170
172
VariableStatData * vardata ,
171
173
Oid sortop ,
172
174
Datum * min , Datum * max );
175
+ static RelOptInfo * find_join_input_rel (PlannerInfo * root , Relids relids );
173
176
static Selectivity prefix_selectivity (PlannerInfo * root ,
174
177
VariableStatData * vardata ,
175
178
Oid vartype , Oid opfamily , Const * prefixcon );
@@ -1990,24 +1993,47 @@ eqjoinsel(PG_FUNCTION_ARGS)
1990
1993
VariableStatData vardata1 ;
1991
1994
VariableStatData vardata2 ;
1992
1995
bool join_is_reversed ;
1996
+ RelOptInfo * rel1 ;
1997
+ RelOptInfo * rel2 ;
1993
1998
1994
1999
get_join_variables (root , args , sjinfo ,
1995
2000
& vardata1 , & vardata2 , & join_is_reversed );
1996
2001
2002
+ /*
2003
+ * Identify the join's direct input relations. We use the min lefthand
2004
+ * and min righthand as the inputs, even though the join might actually
2005
+ * get done with larger input relations. The min inputs are guaranteed to
2006
+ * have been formed by now, though, and always using them ensures
2007
+ * consistency of estimates.
2008
+ */
2009
+ if (!join_is_reversed )
2010
+ {
2011
+ rel1 = find_join_input_rel (root , sjinfo -> min_lefthand );
2012
+ rel2 = find_join_input_rel (root , sjinfo -> min_righthand );
2013
+ }
2014
+ else
2015
+ {
2016
+ rel1 = find_join_input_rel (root , sjinfo -> min_righthand );
2017
+ rel2 = find_join_input_rel (root , sjinfo -> min_lefthand );
2018
+ }
2019
+
1997
2020
switch (sjinfo -> jointype )
1998
2021
{
1999
2022
case JOIN_INNER :
2000
2023
case JOIN_LEFT :
2001
2024
case JOIN_FULL :
2002
- selec = eqjoinsel_inner (operator , & vardata1 , & vardata2 );
2025
+ selec = eqjoinsel_inner (operator , & vardata1 , & vardata2 ,
2026
+ rel1 , rel2 );
2003
2027
break ;
2004
2028
case JOIN_SEMI :
2005
2029
case JOIN_ANTI :
2006
2030
if (!join_is_reversed )
2007
- selec = eqjoinsel_semi (operator , & vardata1 , & vardata2 );
2031
+ selec = eqjoinsel_semi (operator , & vardata1 , & vardata2 ,
2032
+ rel1 , rel2 );
2008
2033
else
2009
2034
selec = eqjoinsel_semi (get_commutator (operator ),
2010
- & vardata2 , & vardata1 );
2035
+ & vardata2 , & vardata1 ,
2036
+ rel2 , rel1 );
2011
2037
break ;
2012
2038
default :
2013
2039
/* other values not expected here */
@@ -2033,7 +2059,8 @@ eqjoinsel(PG_FUNCTION_ARGS)
2033
2059
*/
2034
2060
static double
2035
2061
eqjoinsel_inner (Oid operator ,
2036
- VariableStatData * vardata1 , VariableStatData * vardata2 )
2062
+ VariableStatData * vardata1 , VariableStatData * vardata2 ,
2063
+ RelOptInfo * rel1 , RelOptInfo * rel2 )
2037
2064
{
2038
2065
double selec ;
2039
2066
double nd1 ;
@@ -2233,15 +2260,19 @@ eqjoinsel_inner(Oid operator,
2233
2260
* be, providing a crude correction for the selectivity of restriction
2234
2261
* clauses on those relations. (We don't do that in the other path
2235
2262
* since there we are comparing the nd values to stats for the whole
2236
- * relations.)
2263
+ * relations.) We can apply this clamp both with respect to the base
2264
+ * relations from which the join variables come, and to the immediate
2265
+ * input relations of the current join.
2237
2266
*/
2238
2267
double nullfrac1 = stats1 ? stats1 -> stanullfrac : 0.0 ;
2239
2268
double nullfrac2 = stats2 ? stats2 -> stanullfrac : 0.0 ;
2240
2269
2241
2270
if (vardata1 -> rel )
2242
2271
nd1 = Min (nd1 , vardata1 -> rel -> rows );
2272
+ nd1 = Min (nd1 , rel1 -> rows );
2243
2273
if (vardata2 -> rel )
2244
2274
nd2 = Min (nd2 , vardata2 -> rel -> rows );
2275
+ nd2 = Min (nd2 , rel2 -> rows );
2245
2276
2246
2277
selec = (1.0 - nullfrac1 ) * (1.0 - nullfrac2 );
2247
2278
if (nd1 > nd2 )
@@ -2268,7 +2299,8 @@ eqjoinsel_inner(Oid operator,
2268
2299
*/
2269
2300
static double
2270
2301
eqjoinsel_semi (Oid operator ,
2271
- VariableStatData * vardata1 , VariableStatData * vardata2 )
2302
+ VariableStatData * vardata1 , VariableStatData * vardata2 ,
2303
+ RelOptInfo * rel1 , RelOptInfo * rel2 )
2272
2304
{
2273
2305
double selec ;
2274
2306
double nd1 ;
@@ -2417,8 +2449,10 @@ eqjoinsel_semi(Oid operator,
2417
2449
{
2418
2450
if (vardata1 -> rel )
2419
2451
nd1 = Min (nd1 , vardata1 -> rel -> rows );
2452
+ nd1 = Min (nd1 , rel1 -> rows );
2420
2453
if (vardata2 -> rel )
2421
2454
nd2 = Min (nd2 , vardata2 -> rel -> rows );
2455
+ nd2 = Min (nd2 , rel2 -> rows );
2422
2456
2423
2457
if (nd1 <= nd2 || nd2 <= 0 )
2424
2458
selec = 1.0 - nullfrac1 ;
@@ -4722,6 +4756,37 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata,
4722
4756
return have_data ;
4723
4757
}
4724
4758
4759
+ /*
4760
+ * find_join_input_rel
4761
+ * Look up the input relation for a join.
4762
+ *
4763
+ * We assume that the input relation's RelOptInfo must have been constructed
4764
+ * already.
4765
+ */
4766
+ static RelOptInfo *
4767
+ find_join_input_rel (PlannerInfo * root , Relids relids )
4768
+ {
4769
+ RelOptInfo * rel = NULL ;
4770
+
4771
+ switch (bms_membership (relids ))
4772
+ {
4773
+ case BMS_EMPTY_SET :
4774
+ /* should not happen */
4775
+ break ;
4776
+ case BMS_SINGLETON :
4777
+ rel = find_base_rel (root , bms_singleton_member (relids ));
4778
+ break ;
4779
+ case BMS_MULTIPLE :
4780
+ rel = find_join_rel (root , relids );
4781
+ break ;
4782
+ }
4783
+
4784
+ if (rel == NULL )
4785
+ elog (ERROR , "could not find RelOptInfo for given relids" );
4786
+
4787
+ return rel ;
4788
+ }
4789
+
4725
4790
4726
4791
/*-------------------------------------------------------------------------
4727
4792
*
0 commit comments