@@ -77,8 +77,8 @@ static bool dependency_implies_attribute(MVDependency *dependency,
77
77
AttrNumber attnum );
78
78
static bool dependency_is_compatible_clause (Node * clause , Index relid ,
79
79
AttrNumber * attnum );
80
- static MVDependency * find_strongest_dependency (StatisticExtInfo * stats ,
81
- MVDependencies * dependencies ,
80
+ static MVDependency * find_strongest_dependency (MVDependencies * * dependencies ,
81
+ int ndependencies ,
82
82
Bitmapset * attnums );
83
83
84
84
static void
@@ -862,10 +862,10 @@ dependency_is_compatible_clause(Node *clause, Index relid, AttrNumber *attnum)
862
862
* (see the comment in dependencies_clauselist_selectivity).
863
863
*/
864
864
static MVDependency *
865
- find_strongest_dependency (StatisticExtInfo * stats , MVDependencies * dependencies ,
865
+ find_strongest_dependency (MVDependencies * * dependencies , int ndependencies ,
866
866
Bitmapset * attnums )
867
867
{
868
- int i ;
868
+ int i , j ;
869
869
MVDependency * strongest = NULL ;
870
870
871
871
/* number of attnums in clauses */
@@ -876,36 +876,39 @@ find_strongest_dependency(StatisticExtInfo *stats, MVDependencies *dependencies,
876
876
* fully-matched dependencies. We do the cheap checks first, before
877
877
* matching it against the attnums.
878
878
*/
879
- for (i = 0 ; i < dependencies -> ndeps ; i ++ )
879
+ for (i = 0 ; i < ndependencies ; i ++ )
880
880
{
881
- MVDependency * dependency = dependencies -> deps [i ];
882
-
883
- /*
884
- * Skip dependencies referencing more attributes than available
885
- * clauses, as those can't be fully matched.
886
- */
887
- if (dependency -> nattributes > nattnums )
888
- continue ;
889
-
890
- if (strongest )
881
+ for (j = 0 ; j < dependencies [i ]-> ndeps ; j ++ )
891
882
{
892
- /* skip dependencies on fewer attributes than the strongest. */
893
- if (dependency -> nattributes < strongest -> nattributes )
894
- continue ;
883
+ MVDependency * dependency = dependencies [i ]-> deps [j ];
895
884
896
- /* also skip weaker dependencies when attribute count matches */
897
- if (strongest -> nattributes == dependency -> nattributes &&
898
- strongest -> degree > dependency -> degree )
885
+ /*
886
+ * Skip dependencies referencing more attributes than available
887
+ * clauses, as those can't be fully matched.
888
+ */
889
+ if (dependency -> nattributes > nattnums )
899
890
continue ;
900
- }
901
891
902
- /*
903
- * this dependency is stronger, but we must still check that it's
904
- * fully matched to these attnums. We perform this check last as it's
905
- * slightly more expensive than the previous checks.
906
- */
907
- if (dependency_is_fully_matched (dependency , attnums ))
908
- strongest = dependency ; /* save new best match */
892
+ if (strongest )
893
+ {
894
+ /* skip dependencies on fewer attributes than the strongest. */
895
+ if (dependency -> nattributes < strongest -> nattributes )
896
+ continue ;
897
+
898
+ /* also skip weaker dependencies when attribute count matches */
899
+ if (strongest -> nattributes == dependency -> nattributes &&
900
+ strongest -> degree > dependency -> degree )
901
+ continue ;
902
+ }
903
+
904
+ /*
905
+ * this dependency is stronger, but we must still check that it's
906
+ * fully matched to these attnums. We perform this check last as it's
907
+ * slightly more expensive than the previous checks.
908
+ */
909
+ if (dependency_is_fully_matched (dependency , attnums ))
910
+ strongest = dependency ; /* save new best match */
911
+ }
909
912
}
910
913
911
914
return strongest ;
@@ -949,10 +952,11 @@ dependencies_clauselist_selectivity(PlannerInfo *root,
949
952
Selectivity s1 = 1.0 ;
950
953
ListCell * l ;
951
954
Bitmapset * clauses_attnums = NULL ;
952
- StatisticExtInfo * stat ;
953
- MVDependencies * dependencies ;
954
955
Bitmapset * * list_attnums ;
955
956
int listidx ;
957
+ MVDependencies * * dependencies = NULL ;
958
+ int ndependencies = 0 ;
959
+ int i ;
956
960
957
961
/* check if there's any stats that might be useful for us. */
958
962
if (!has_stats_of_kind (rel -> statlist , STATS_EXT_DEPENDENCIES ))
@@ -1001,20 +1005,50 @@ dependencies_clauselist_selectivity(PlannerInfo *root,
1001
1005
return 1.0 ;
1002
1006
}
1003
1007
1004
- /* find the best suited statistics object for these attnums */
1005
- stat = choose_best_statistics (rel -> statlist , STATS_EXT_DEPENDENCIES ,
1006
- list_attnums , list_length (clauses ));
1008
+ /*
1009
+ * Load all functional dependencies matching at least two parameters. We
1010
+ * can simply consider all dependencies at once, without having to search
1011
+ * for the best statistics object.
1012
+ *
1013
+ * To not waste cycles and memory, we deserialize dependencies only for
1014
+ * statistics that match at least two attributes. The array is allocated
1015
+ * with the assumption that all objects match - we could grow the array
1016
+ * to make it just the right size, but it's likely wasteful anyway thanks
1017
+ * to moving the freed chunks to freelists etc.
1018
+ */
1019
+ ndependencies = 0 ;
1020
+ dependencies = (MVDependencies * * ) palloc (sizeof (MVDependencies * ) *
1021
+ list_length (rel -> statlist ));
1022
+
1023
+ foreach (l ,rel -> statlist )
1024
+ {
1025
+ StatisticExtInfo * stat = (StatisticExtInfo * ) lfirst (l );
1026
+ Bitmapset * matched ;
1027
+ int num_matched ;
1028
+
1029
+ /* skip statistics that are not of the correct type */
1030
+ if (stat -> kind != STATS_EXT_DEPENDENCIES )
1031
+ continue ;
1032
+
1033
+ matched = bms_intersect (clauses_attnums , stat -> keys );
1034
+ num_matched = bms_num_members (matched );
1035
+ bms_free (matched );
1036
+
1037
+ /* skip objects matching fewer than two attributes from clauses */
1038
+ if (num_matched < 2 )
1039
+ continue ;
1040
+
1041
+ dependencies [ndependencies ++ ]
1042
+ = statext_dependencies_load (stat -> statOid );
1043
+ }
1007
1044
1008
1045
/* if no matching stats could be found then we've nothing to do */
1009
- if (!stat )
1046
+ if (!ndependencies )
1010
1047
{
1011
1048
pfree (list_attnums );
1012
1049
return 1.0 ;
1013
1050
}
1014
1051
1015
- /* load the dependency items stored in the statistics object */
1016
- dependencies = statext_dependencies_load (stat -> statOid );
1017
-
1018
1052
/*
1019
1053
* Apply the dependencies recursively, starting with the widest/strongest
1020
1054
* ones, and proceeding to the smaller/weaker ones. At the end of each
@@ -1027,7 +1061,7 @@ dependencies_clauselist_selectivity(PlannerInfo *root,
1027
1061
MVDependency * dependency ;
1028
1062
1029
1063
/* the widest/strongest dependency, fully matched by clauses */
1030
- dependency = find_strongest_dependency (stat , dependencies ,
1064
+ dependency = find_strongest_dependency (dependencies , ndependencies ,
1031
1065
clauses_attnums );
1032
1066
1033
1067
/* if no suitable dependency was found, we're done */
@@ -1097,6 +1131,10 @@ dependencies_clauselist_selectivity(PlannerInfo *root,
1097
1131
s1 *= (dependency -> degree + (1 - dependency -> degree ) * s2 );
1098
1132
}
1099
1133
1134
+ /* free deserialized functional dependencies (and then the array) */
1135
+ for (i = 0 ; i < ndependencies ; i ++ )
1136
+ pfree (dependencies [i ]);
1137
+
1100
1138
pfree (dependencies );
1101
1139
pfree (list_attnums );
1102
1140
0 commit comments