@@ -5956,6 +5956,50 @@ string_to_bytea_const(const char *str, size_t str_len)
59565956 *
59575957 * Index cost estimation functions
59585958 *
5959+ *-------------------------------------------------------------------------
5960+ */
5961+
5962+ /*
5963+ * If the index is partial, add its predicate to the given qual list.
5964+ *
5965+ * ANDing the index predicate with the explicitly given indexquals produces
5966+ * a more accurate idea of the index's selectivity. However, we need to be
5967+ * careful not to insert redundant clauses, because clauselist_selectivity()
5968+ * is easily fooled into computing a too-low selectivity estimate. Our
5969+ * approach is to add only the predicate clause(s) that cannot be proven to
5970+ * be implied by the given indexquals. This successfully handles cases such
5971+ * as a qual "x = 42" used with a partial index "WHERE x >= 40 AND x < 50".
5972+ * There are many other cases where we won't detect redundancy, leading to a
5973+ * too-low selectivity estimate, which will bias the system in favor of using
5974+ * partial indexes where possible. That is not necessarily bad though.
5975+ *
5976+ * Note that indexQuals contains RestrictInfo nodes while the indpred
5977+ * does not, so the output list will be mixed. This is OK for both
5978+ * predicate_implied_by() and clauselist_selectivity(), but might be
5979+ * problematic if the result were passed to other things.
5980+ */
5981+ static List *
5982+ add_predicate_to_quals (IndexOptInfo * index , List * indexQuals )
5983+ {
5984+ List * predExtraQuals = NIL ;
5985+ ListCell * lc ;
5986+
5987+ if (index -> indpred == NIL )
5988+ return indexQuals ;
5989+
5990+ foreach (lc , index -> indpred )
5991+ {
5992+ Node * predQual = (Node * ) lfirst (lc );
5993+ List * oneQual = list_make1 (predQual );
5994+
5995+ if (!predicate_implied_by (oneQual , indexQuals ))
5996+ predExtraQuals = list_concat (predExtraQuals , oneQual );
5997+ }
5998+ /* list_concat avoids modifying the passed-in indexQuals list */
5999+ return list_concat (predExtraQuals , indexQuals );
6000+ }
6001+
6002+ /*
59596003 * genericcostestimate is a general-purpose estimator for use when we
59606004 * don't have any better idea about how to estimate. Index-type-specific
59616005 * knowledge can be incorporated in the type-specific routines.
@@ -5964,10 +6008,7 @@ string_to_bytea_const(const char *str, size_t str_len)
59646008 * in genericcostestimate is the estimate of the number of index tuples
59656009 * visited. If numIndexTuples is not 0 then it is used as the estimate,
59666010 * otherwise we compute a generic estimate.
5967- *
5968- *-------------------------------------------------------------------------
59696011 */
5970-
59716012static void
59726013genericcostestimate (PlannerInfo * root ,
59736014 IndexPath * path ,
@@ -5992,42 +6033,12 @@ genericcostestimate(PlannerInfo *root,
59926033 List * selectivityQuals ;
59936034 ListCell * l ;
59946035
5995- /*----------
6036+ /*
59966037 * If the index is partial, AND the index predicate with the explicitly
59976038 * given indexquals to produce a more accurate idea of the index
5998- * selectivity. However, we need to be careful not to insert redundant
5999- * clauses, because clauselist_selectivity() is easily fooled into
6000- * computing a too-low selectivity estimate. Our approach is to add
6001- * only the index predicate clause(s) that cannot be proven to be implied
6002- * by the given indexquals. This successfully handles cases such as a
6003- * qual "x = 42" used with a partial index "WHERE x >= 40 AND x < 50".
6004- * There are many other cases where we won't detect redundancy, leading
6005- * to a too-low selectivity estimate, which will bias the system in favor
6006- * of using partial indexes where possible. That is not necessarily bad
6007- * though.
6008- *
6009- * Note that indexQuals contains RestrictInfo nodes while the indpred
6010- * does not. This is OK for both predicate_implied_by() and
6011- * clauselist_selectivity().
6012- *----------
6039+ * selectivity.
60136040 */
6014- if (index -> indpred != NIL )
6015- {
6016- List * predExtraQuals = NIL ;
6017-
6018- foreach (l , index -> indpred )
6019- {
6020- Node * predQual = (Node * ) lfirst (l );
6021- List * oneQual = list_make1 (predQual );
6022-
6023- if (!predicate_implied_by (oneQual , indexQuals ))
6024- predExtraQuals = list_concat (predExtraQuals , oneQual );
6025- }
6026- /* list_concat avoids modifying the passed-in indexQuals list */
6027- selectivityQuals = list_concat (predExtraQuals , indexQuals );
6028- }
6029- else
6030- selectivityQuals = indexQuals ;
6041+ selectivityQuals = add_predicate_to_quals (index , indexQuals );
60316042
60326043 /*
60336044 * Check for ScalarArrayOpExpr index quals, and estimate the number of
@@ -6164,11 +6175,11 @@ genericcostestimate(PlannerInfo *root,
61646175 *
61656176 * We can deal with this by adding a very small "fudge factor" that
61666177 * depends on the index size. The fudge factor used here is one
6167- * spc_random_page_cost per 100000 index pages, which should be small
6178+ * spc_random_page_cost per 10000 index pages, which should be small
61686179 * enough to not alter index-vs-seqscan decisions, but will prevent
61696180 * indexes of different sizes from looking exactly equally attractive.
61706181 */
6171- * indexTotalCost += index -> pages * spc_random_page_cost / 100000 .0 ;
6182+ * indexTotalCost += index -> pages * spc_random_page_cost / 10000 .0 ;
61726183
61736184 /*
61746185 * CPU cost: any complex expressions in the indexquals will need to be
@@ -6386,9 +6397,17 @@ btcostestimate(PG_FUNCTION_ARGS)
63866397 numIndexTuples = 1.0 ;
63876398 else
63886399 {
6400+ List * selectivityQuals ;
63896401 Selectivity btreeSelectivity ;
63906402
6391- btreeSelectivity = clauselist_selectivity (root , indexBoundQuals ,
6403+ /*
6404+ * If the index is partial, AND the index predicate with the
6405+ * index-bound quals to produce a more accurate idea of the number
6406+ * of rows covered by the bound conditions.
6407+ */
6408+ selectivityQuals = add_predicate_to_quals (index , indexBoundQuals );
6409+
6410+ btreeSelectivity = clauselist_selectivity (root , selectivityQuals ,
63926411 index -> rel -> relid ,
63936412 JOIN_INNER ,
63946413 NULL );
0 commit comments