PostgreSQL Source Code git master
Loading...
Searching...
No Matches
index_selfuncs.h File Reference
#include "access/amapi.h"
Include dependency graph for index_selfuncs.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void brincostestimate (struct PlannerInfo *root, struct IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages)
 
void btcostestimate (struct PlannerInfo *root, struct IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages)
 
void hashcostestimate (struct PlannerInfo *root, struct IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages)
 
void gistcostestimate (struct PlannerInfo *root, struct IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages)
 
void spgcostestimate (struct PlannerInfo *root, struct IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages)
 
void gincostestimate (struct PlannerInfo *root, struct IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages)
 

Function Documentation

◆ brincostestimate()

void brincostestimate ( struct PlannerInfo root,
struct IndexPath path,
double  loop_count,
Cost indexStartupCost,
Cost indexTotalCost,
Selectivity indexSelectivity,
double indexCorrelation,
double indexPages 
)
extern

Definition at line 9127 of file selfuncs.c.

9131{
9132 IndexOptInfo *index = path->indexinfo;
9134 double numPages = index->pages;
9135 RelOptInfo *baserel = index->rel;
9138 Cost spc_random_page_cost;
9139 double qual_arg_cost;
9140 double qualSelectivity;
9142 double indexRanges;
9143 double minimalRanges;
9144 double estimatedRanges;
9145 double selec;
9146 Relation indexRel;
9147 ListCell *l;
9149
9150 Assert(rte->rtekind == RTE_RELATION);
9151
9152 /* fetch estimated page cost for the tablespace containing the index */
9153 get_tablespace_page_costs(index->reltablespace,
9154 &spc_random_page_cost,
9156
9157 /*
9158 * Obtain some data from the index itself, if possible. Otherwise invent
9159 * some plausible internal statistics based on the relation page count.
9160 */
9161 if (!index->hypothetical)
9162 {
9163 /*
9164 * A lock should have already been obtained on the index in plancat.c.
9165 */
9166 indexRel = index_open(index->indexoid, NoLock);
9167 brinGetStats(indexRel, &statsData);
9168 index_close(indexRel, NoLock);
9169
9170 /* work out the actual number of ranges in the index */
9171 indexRanges = Max(ceil((double) baserel->pages /
9172 statsData.pagesPerRange), 1.0);
9173 }
9174 else
9175 {
9176 /*
9177 * Assume default number of pages per range, and estimate the number
9178 * of ranges based on that.
9179 */
9180 indexRanges = Max(ceil((double) baserel->pages /
9182
9184 statsData.revmapNumPages = (indexRanges / REVMAP_PAGE_MAXITEMS) + 1;
9185 }
9186
9187 /*
9188 * Compute index correlation
9189 *
9190 * Because we can use all index quals equally when scanning, we can use
9191 * the largest correlation (in absolute value) among columns used by the
9192 * query. Start at zero, the worst possible case. If we cannot find any
9193 * correlation statistics, we will keep it as 0.
9194 */
9195 *indexCorrelation = 0;
9196
9197 foreach(l, path->indexclauses)
9198 {
9200 AttrNumber attnum = index->indexkeys[iclause->indexcol];
9201
9202 /* attempt to lookup stats in relation for this index column */
9203 if (attnum != 0)
9204 {
9205 /* Simple variable -- look to stats for the underlying table */
9208 {
9209 /*
9210 * The hook took control of acquiring a stats tuple. If it
9211 * did supply a tuple, it'd better have supplied a freefunc.
9212 */
9213 if (HeapTupleIsValid(vardata.statsTuple) && !vardata.freefunc)
9214 elog(ERROR,
9215 "no function provided to release variable stats with");
9216 }
9217 else
9218 {
9219 vardata.statsTuple =
9221 ObjectIdGetDatum(rte->relid),
9223 BoolGetDatum(false));
9224 vardata.freefunc = ReleaseSysCache;
9225 }
9226 }
9227 else
9228 {
9229 /*
9230 * Looks like we've found an expression column in the index. Let's
9231 * see if there's any stats for it.
9232 */
9233
9234 /* get the attnum from the 0-based index. */
9235 attnum = iclause->indexcol + 1;
9236
9238 (*get_index_stats_hook) (root, index->indexoid, attnum, &vardata))
9239 {
9240 /*
9241 * The hook took control of acquiring a stats tuple. If it
9242 * did supply a tuple, it'd better have supplied a freefunc.
9243 */
9244 if (HeapTupleIsValid(vardata.statsTuple) &&
9245 !vardata.freefunc)
9246 elog(ERROR, "no function provided to release variable stats with");
9247 }
9248 else
9249 {
9251 ObjectIdGetDatum(index->indexoid),
9253 BoolGetDatum(false));
9254 vardata.freefunc = ReleaseSysCache;
9255 }
9256 }
9257
9258 if (HeapTupleIsValid(vardata.statsTuple))
9259 {
9261
9262 if (get_attstatsslot(&sslot, vardata.statsTuple,
9265 {
9266 double varCorrelation = 0.0;
9267
9268 if (sslot.nnumbers > 0)
9269 varCorrelation = fabs(sslot.numbers[0]);
9270
9271 if (varCorrelation > *indexCorrelation)
9272 *indexCorrelation = varCorrelation;
9273
9275 }
9276 }
9277
9279 }
9280
9282 baserel->relid,
9283 JOIN_INNER, NULL);
9284
9285 /*
9286 * Now calculate the minimum possible ranges we could match with if all of
9287 * the rows were in the perfect order in the table's heap.
9288 */
9290
9291 /*
9292 * Now estimate the number of ranges that we'll touch by using the
9293 * indexCorrelation from the stats. Careful not to divide by zero (note
9294 * we're using the absolute value of the correlation).
9295 */
9296 if (*indexCorrelation < 1.0e-10)
9298 else
9299 estimatedRanges = Min(minimalRanges / *indexCorrelation, indexRanges);
9300
9301 /* we expect to visit this portion of the table */
9303
9305
9306 *indexSelectivity = selec;
9307
9308 /*
9309 * Compute the index qual costs, much as in genericcostestimate, to add to
9310 * the index costs. We can disregard indexorderbys, since BRIN doesn't
9311 * support those.
9312 */
9314
9315 /*
9316 * Compute the startup cost as the cost to read the whole revmap
9317 * sequentially, including the cost to execute the index quals.
9318 */
9319 *indexStartupCost =
9320 spc_seq_page_cost * statsData.revmapNumPages * loop_count;
9321 *indexStartupCost += qual_arg_cost;
9322
9323 /*
9324 * To read a BRIN index there might be a bit of back and forth over
9325 * regular pages, as revmap might point to them out of sequential order;
9326 * calculate the total cost as reading the whole index in random order.
9327 */
9328 *indexTotalCost = *indexStartupCost +
9329 spc_random_page_cost * (numPages - statsData.revmapNumPages) * loop_count;
9330
9331 /*
9332 * Charge a small amount per range tuple which we expect to match to. This
9333 * is meant to reflect the costs of manipulating the bitmap. The BRIN scan
9334 * will set a bit for each page in the range when we find a matching
9335 * range, so we must multiply the charge by the number of pages in the
9336 * range.
9337 */
9338 *indexTotalCost += 0.1 * cpu_operator_cost * estimatedRanges *
9339 statsData.pagesPerRange;
9340
9341 *indexPages = index->pages;
9342}
int16 AttrNumber
Definition attnum.h:21
void brinGetStats(Relation index, BrinStatsData *stats)
Definition brin.c:1653
#define BRIN_DEFAULT_PAGES_PER_RANGE
Definition brin.h:40
#define REVMAP_PAGE_MAXITEMS
Definition brin_page.h:93
#define Min(x, y)
Definition c.h:1131
#define Max(x, y)
Definition c.h:1125
#define Assert(condition)
Definition c.h:1002
Selectivity clauselist_selectivity(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo)
Definition clausesel.c:100
double cpu_operator_cost
Definition costsize.c:135
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define HeapTupleIsValid(tuple)
Definition htup.h:78
void index_close(Relation relation, LOCKMODE lockmode)
Definition indexam.c:178
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:134
#define NoLock
Definition lockdefs.h:34
void free_attstatsslot(AttStatsSlot *sslot)
Definition lsyscache.c:3660
bool get_attstatsslot(AttStatsSlot *sslot, HeapTuple statstuple, int reqkind, Oid reqop, int flags)
Definition lsyscache.c:3550
#define ATTSTATSSLOT_NUMBERS
Definition lsyscache.h:44
double Cost
Definition nodes.h:259
@ JOIN_INNER
Definition nodes.h:301
@ RTE_RELATION
#define planner_rt_fetch(rti, root)
Definition pathnodes.h:704
int16 attnum
#define lfirst_node(type, lc)
Definition pg_list.h:176
static Datum Int16GetDatum(int16 X)
Definition postgres.h:172
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
#define InvalidOid
static int fb(int x)
tree ctl root
Definition radixtree.h:1857
List * get_quals_from_indexclauses(List *indexclauses)
Definition selfuncs.c:7423
get_index_stats_hook_type get_index_stats_hook
Definition selfuncs.c:184
Cost index_other_operands_eval_cost(PlannerInfo *root, List *indexquals)
Definition selfuncs.c:7453
get_relation_stats_hook_type get_relation_stats_hook
Definition selfuncs.c:183
#define ReleaseVariableStats(vardata)
Definition selfuncs.h:101
#define CLAMP_PROBABILITY(p)
Definition selfuncs.h:63
void get_tablespace_page_costs(Oid spcid, double *spc_random_page_cost, double *spc_seq_page_cost)
Definition spccache.c:183
List * indexclauses
Definition pathnodes.h:2057
IndexOptInfo * indexinfo
Definition pathnodes.h:2056
Definition pg_list.h:54
Definition type.h:97
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache3(SysCacheIdentifier cacheId, Datum key1, Datum key2, Datum key3)
Definition syscache.c:241

References Assert, attnum, ATTSTATSSLOT_NUMBERS, BoolGetDatum(), BRIN_DEFAULT_PAGES_PER_RANGE, brinGetStats(), CLAMP_PROBABILITY, clauselist_selectivity(), cpu_operator_cost, elog, ERROR, fb(), free_attstatsslot(), get_attstatsslot(), get_index_stats_hook, get_quals_from_indexclauses(), get_relation_stats_hook, get_tablespace_page_costs(), HeapTupleIsValid, index_close(), index_open(), index_other_operands_eval_cost(), IndexPath::indexclauses, IndexPath::indexinfo, Int16GetDatum(), InvalidOid, JOIN_INNER, lfirst_node, Max, Min, NoLock, ObjectIdGetDatum(), planner_rt_fetch, ReleaseSysCache(), ReleaseVariableStats, REVMAP_PAGE_MAXITEMS, root, RTE_RELATION, and SearchSysCache3().

Referenced by brinhandler().

◆ btcostestimate()

void btcostestimate ( struct PlannerInfo root,
struct IndexPath path,
double  loop_count,
Cost indexStartupCost,
Cost indexTotalCost,
Selectivity indexSelectivity,
double indexCorrelation,
double indexPages 
)
extern

Definition at line 7805 of file selfuncs.c.

7809{
7810 IndexOptInfo *index = path->indexinfo;
7811 GenericCosts costs = {0};
7813 double numIndexTuples;
7817 int indexcol;
7818 bool eqQualHere;
7819 bool found_row_compare;
7820 bool found_array;
7821 bool found_is_null_op;
7822 bool have_correlation = false;
7823 double num_sa_scans;
7824 double correlation = 0.0;
7825 ListCell *lc;
7826
7827 /*
7828 * For a btree scan, only leading '=' quals plus inequality quals for the
7829 * immediately next attribute contribute to index selectivity (these are
7830 * the "boundary quals" that determine the starting and stopping points of
7831 * the index scan). Additional quals can suppress visits to the heap, so
7832 * it's OK to count them in indexSelectivity, but they should not count
7833 * for estimating numIndexTuples. So we must examine the given indexquals
7834 * to find out which ones count as boundary quals. We rely on the
7835 * knowledge that they are given in index column order. Note that nbtree
7836 * preprocessing can add skip arrays that act as leading '=' quals in the
7837 * absence of ordinary input '=' quals, so in practice _most_ input quals
7838 * are able to act as index bound quals (which we take into account here).
7839 *
7840 * For a RowCompareExpr, we consider only the first column, just as
7841 * rowcomparesel() does.
7842 *
7843 * If there's a SAOP or skip array in the quals, we'll actually perform up
7844 * to N index descents (not just one), but the underlying array key's
7845 * operator can be considered to act the same as it normally does.
7846 */
7849 indexcol = 0;
7850 eqQualHere = false;
7851 found_row_compare = false;
7852 found_array = false;
7853 found_is_null_op = false;
7854 num_sa_scans = 1;
7855 foreach(lc, path->indexclauses)
7856 {
7858 ListCell *lc2;
7859
7860 if (indexcol < iclause->indexcol)
7861 {
7862 double num_sa_scans_prev_cols = num_sa_scans;
7863
7864 /*
7865 * Beginning of a new column's quals.
7866 *
7867 * Skip scans use skip arrays, which are ScalarArrayOp style
7868 * arrays that generate their elements procedurally and on demand.
7869 * Given a multi-column index on "(a, b)", and an SQL WHERE clause
7870 * "WHERE b = 42", a skip scan will effectively use an indexqual
7871 * "WHERE a = ANY('{every col a value}') AND b = 42". (Obviously,
7872 * the array on "a" must also return "IS NULL" matches, since our
7873 * WHERE clause used no strict operator on "a").
7874 *
7875 * Here we consider how nbtree will backfill skip arrays for any
7876 * index columns that lacked an '=' qual. This maintains our
7877 * num_sa_scans estimate, and determines if this new column (the
7878 * "iclause->indexcol" column, not the prior "indexcol" column)
7879 * can have its RestrictInfos/quals added to indexBoundQuals.
7880 *
7881 * We'll need to handle columns that have inequality quals, where
7882 * the skip array generates values from a range constrained by the
7883 * quals (not every possible value). We've been maintaining
7884 * indexSkipQuals to help with this; it will now contain all of
7885 * the prior column's quals (that is, indexcol's quals) when they
7886 * might be used for this.
7887 */
7889 {
7890 /*
7891 * Skip arrays can't be added after a RowCompare input qual
7892 * due to limitations in nbtree
7893 */
7894 break;
7895 }
7896 if (eqQualHere)
7897 {
7898 /*
7899 * Don't need to add a skip array for an indexcol that already
7900 * has an '=' qual/equality constraint
7901 */
7902 indexcol++;
7904 }
7905 eqQualHere = false;
7906
7907 while (indexcol < iclause->indexcol)
7908 {
7909 double ndistinct;
7910 bool isdefault = true;
7911
7912 found_array = true;
7913
7914 /*
7915 * A skipped attribute's ndistinct forms the basis of our
7916 * estimate of the total number of "array elements" used by
7917 * its skip array at runtime. Look that up first.
7918 */
7920 ndistinct = get_variable_numdistinct(&vardata, &isdefault);
7921
7922 if (indexcol == 0)
7923 {
7924 /*
7925 * Get an estimate of the leading column's correlation in
7926 * passing (avoids rereading variable stats below)
7927 */
7928 if (HeapTupleIsValid(vardata.statsTuple))
7930 have_correlation = true;
7931 }
7932
7934
7935 /*
7936 * If ndistinct is a default estimate, conservatively assume
7937 * that no skipping will happen at runtime
7938 */
7939 if (isdefault)
7940 {
7941 num_sa_scans = num_sa_scans_prev_cols;
7942 break; /* done building indexBoundQuals */
7943 }
7944
7945 /*
7946 * Apply indexcol's indexSkipQuals selectivity to ndistinct
7947 */
7948 if (indexSkipQuals != NIL)
7949 {
7952
7953 /*
7954 * If the index is partial, AND the index predicate with
7955 * the index-bound quals to produce a more accurate idea
7956 * of the number of distinct values for prior indexcol
7957 */
7960
7962 index->rel->relid,
7963 JOIN_INNER,
7964 NULL);
7965
7966 /*
7967 * If ndistinctfrac is selective (on its own), the scan is
7968 * unlikely to benefit from repositioning itself using
7969 * later quals. Do not allow iclause->indexcol's quals to
7970 * be added to indexBoundQuals (it would increase descent
7971 * costs, without lowering numIndexTuples costs by much).
7972 */
7974 {
7975 num_sa_scans = num_sa_scans_prev_cols;
7976 break; /* done building indexBoundQuals */
7977 }
7978
7979 /* Adjust ndistinct downward */
7980 ndistinct = rint(ndistinct * ndistinctfrac);
7981 ndistinct = Max(ndistinct, 1);
7982 }
7983
7984 /*
7985 * When there's no inequality quals, account for the need to
7986 * find an initial value by counting -inf/+inf as a value.
7987 *
7988 * We don't charge anything extra for possible next/prior key
7989 * index probes, which are sometimes used to find the next
7990 * valid skip array element (ahead of using the located
7991 * element value to relocate the scan to the next position
7992 * that might contain matching tuples). It seems hard to do
7993 * better here. Use of the skip support infrastructure often
7994 * avoids most next/prior key probes. But even when it can't,
7995 * there's a decent chance that most individual next/prior key
7996 * probes will locate a leaf page whose key space overlaps all
7997 * of the scan's keys (even the lower-order keys) -- which
7998 * also avoids the need for a separate, extra index descent.
7999 * Note also that these probes are much cheaper than non-probe
8000 * primitive index scans: they're reliably very selective.
8001 */
8002 if (indexSkipQuals == NIL)
8003 ndistinct += 1;
8004
8005 /*
8006 * Update num_sa_scans estimate by multiplying by ndistinct.
8007 *
8008 * We make the pessimistic assumption that there is no
8009 * naturally occurring cross-column correlation. This is
8010 * often wrong, but it seems best to err on the side of not
8011 * expecting skipping to be helpful...
8012 */
8013 num_sa_scans *= ndistinct;
8014
8015 /*
8016 * ...but back out of adding this latest group of 1 or more
8017 * skip arrays when num_sa_scans exceeds the total number of
8018 * index pages (revert to num_sa_scans from before indexcol).
8019 * This causes a sharp discontinuity in cost (as a function of
8020 * the indexcol's ndistinct), but that is representative of
8021 * actual runtime costs.
8022 *
8023 * Note that skipping is helpful when each primitive index
8024 * scan only manages to skip over 1 or 2 irrelevant leaf pages
8025 * on average. Skip arrays bring savings in CPU costs due to
8026 * the scan not needing to evaluate indexquals against every
8027 * tuple, which can greatly exceed any savings in I/O costs.
8028 * This test is a test of whether num_sa_scans implies that
8029 * we're past the point where the ability to skip ceases to
8030 * lower the scan's costs (even qual evaluation CPU costs).
8031 */
8032 if (index->pages < num_sa_scans)
8033 {
8034 num_sa_scans = num_sa_scans_prev_cols;
8035 break; /* done building indexBoundQuals */
8036 }
8037
8038 indexcol++;
8040 }
8041
8042 /*
8043 * Finished considering the need to add skip arrays to bridge an
8044 * initial eqQualHere gap between the old and new index columns
8045 * (or there was no initial eqQualHere gap in the first place).
8046 *
8047 * If an initial gap could not be bridged, then new column's quals
8048 * (i.e. iclause->indexcol's quals) won't go into indexBoundQuals,
8049 * and so won't affect our final numIndexTuples estimate.
8050 */
8051 if (indexcol != iclause->indexcol)
8052 break; /* done building indexBoundQuals */
8053 }
8054
8055 Assert(indexcol == iclause->indexcol);
8056
8057 /* Examine each indexqual associated with this index clause */
8058 foreach(lc2, iclause->indexquals)
8059 {
8061 Expr *clause = rinfo->clause;
8062 Oid clause_op = InvalidOid;
8063 int op_strategy;
8064
8065 if (IsA(clause, OpExpr))
8066 {
8067 OpExpr *op = (OpExpr *) clause;
8068
8069 clause_op = op->opno;
8070 }
8071 else if (IsA(clause, RowCompareExpr))
8072 {
8073 RowCompareExpr *rc = (RowCompareExpr *) clause;
8074
8075 clause_op = linitial_oid(rc->opnos);
8076 found_row_compare = true;
8077 }
8078 else if (IsA(clause, ScalarArrayOpExpr))
8079 {
8080 ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
8081 Node *other_operand = (Node *) lsecond(saop->args);
8083
8084 clause_op = saop->opno;
8085 found_array = true;
8086 /* estimate SA descents by indexBoundQuals only */
8087 if (alength > 1)
8088 num_sa_scans *= alength;
8089 }
8090 else if (IsA(clause, NullTest))
8091 {
8092 NullTest *nt = (NullTest *) clause;
8093
8094 if (nt->nulltesttype == IS_NULL)
8095 {
8096 found_is_null_op = true;
8097 /* IS NULL is like = for selectivity/skip scan purposes */
8098 eqQualHere = true;
8099 }
8100 }
8101 else
8102 elog(ERROR, "unsupported indexqual type: %d",
8103 (int) nodeTag(clause));
8104
8105 /* check for equality operator */
8106 if (OidIsValid(clause_op))
8107 {
8108 op_strategy = get_op_opfamily_strategy(clause_op,
8109 index->opfamily[indexcol]);
8110 Assert(op_strategy != 0); /* not a member of opfamily?? */
8111 if (op_strategy == BTEqualStrategyNumber)
8112 eqQualHere = true;
8113 }
8114
8116
8117 /*
8118 * We apply inequality selectivities to estimate index descent
8119 * costs with scans that use skip arrays. Save this indexcol's
8120 * RestrictInfos if it looks like they'll be needed for that.
8121 */
8122 if (!eqQualHere && !found_row_compare &&
8123 indexcol < index->nkeycolumns - 1)
8125 }
8126 }
8127
8128 /*
8129 * If index is unique and we found an '=' clause for each column, we can
8130 * just assume numIndexTuples = 1 and skip the expensive
8131 * clauselist_selectivity calculations. However, an array or NullTest
8132 * always invalidates that theory (even when eqQualHere has been set).
8133 */
8134 if (index->unique &&
8135 indexcol == index->nkeycolumns - 1 &&
8136 eqQualHere &&
8137 !found_array &&
8139 numIndexTuples = 1.0;
8140 else
8141 {
8144
8145 /*
8146 * If the index is partial, AND the index predicate with the
8147 * index-bound quals to produce a more accurate idea of the number of
8148 * rows covered by the bound conditions.
8149 */
8151
8153 index->rel->relid,
8154 JOIN_INNER,
8155 NULL);
8156 numIndexTuples = btreeSelectivity * index->rel->tuples;
8157
8158 /*
8159 * btree automatically combines individual array element primitive
8160 * index scans whenever the tuples covered by the next set of array
8161 * keys are close to tuples covered by the current set. That puts a
8162 * natural ceiling on the worst case number of descents -- there
8163 * cannot possibly be more than one descent per leaf page scanned.
8164 *
8165 * Clamp the number of descents to at most 1/3 the number of index
8166 * pages. This avoids implausibly high estimates with low selectivity
8167 * paths, where scans usually require only one or two descents. This
8168 * is most likely to help when there are several SAOP clauses, where
8169 * naively accepting the total number of distinct combinations of
8170 * array elements as the number of descents would frequently lead to
8171 * wild overestimates.
8172 *
8173 * We somewhat arbitrarily don't just make the cutoff the total number
8174 * of leaf pages (we make it 1/3 the total number of pages instead) to
8175 * give the btree code credit for its ability to continue on the leaf
8176 * level with low selectivity scans.
8177 *
8178 * Note: num_sa_scans includes both ScalarArrayOp array elements and
8179 * skip array elements whose qual affects our numIndexTuples estimate.
8180 */
8181 num_sa_scans = Min(num_sa_scans, ceil(index->pages * 0.3333333));
8182 num_sa_scans = Max(num_sa_scans, 1);
8183
8184 /*
8185 * As in genericcostestimate(), we have to adjust for any array quals
8186 * included in indexBoundQuals, and then round to integer.
8187 *
8188 * It is tempting to make genericcostestimate behave as if array
8189 * clauses work in almost the same way as scalar operators during
8190 * btree scans, making the top-level scan look like a continuous scan
8191 * (as opposed to num_sa_scans-many primitive index scans). After
8192 * all, btree scans mostly work like that at runtime. However, such a
8193 * scheme would badly bias genericcostestimate's simplistic approach
8194 * to calculating numIndexPages through prorating.
8195 *
8196 * Stick with the approach taken by non-native SAOP scans for now.
8197 * genericcostestimate will use the Mackert-Lohman formula to
8198 * compensate for repeat page fetches, even though that definitely
8199 * won't happen during btree scans (not for leaf pages, at least).
8200 * We're usually very pessimistic about the number of primitive index
8201 * scans that will be required, but it's not clear how to do better.
8202 */
8203 numIndexTuples = rint(numIndexTuples / num_sa_scans);
8204 }
8205
8206 /*
8207 * Now do generic index cost estimation.
8208 *
8209 * While we expended effort to make realistic estimates of numIndexTuples
8210 * and num_sa_scans, we are content to count only the btree metapage as
8211 * non-leaf. btree fanout is typically high enough that upper pages are
8212 * few relative to leaf pages, so accounting for them would move the
8213 * estimates at most a percent or two. Given the uncertainty in just how
8214 * many upper pages exist in a particular index, we'll skip trying to
8215 * handle that.
8216 */
8217 costs.numIndexTuples = numIndexTuples;
8218 costs.num_sa_scans = num_sa_scans;
8219 costs.numNonLeafPages = 1;
8220
8221 genericcostestimate(root, path, loop_count, &costs);
8222
8223 /*
8224 * Add a CPU-cost component to represent the costs of initial btree
8225 * descent. We don't charge any I/O cost for touching upper btree levels,
8226 * since they tend to stay in cache, but we still have to do about log2(N)
8227 * comparisons to descend a btree of N leaf tuples. We charge one
8228 * cpu_operator_cost per comparison.
8229 *
8230 * If there are SAOP or skip array keys, charge this once per estimated
8231 * index descent. The ones after the first one are not startup cost so
8232 * far as the overall plan goes, so just add them to "total" cost.
8233 */
8234 if (index->tuples > 1) /* avoid computing log(0) */
8235 {
8236 descentCost = ceil(log(index->tuples) / log(2.0)) * cpu_operator_cost;
8238 costs.indexTotalCost += costs.num_sa_scans * descentCost;
8239 }
8240
8241 /*
8242 * Even though we're not charging I/O cost for touching upper btree pages,
8243 * it's still reasonable to charge some CPU cost per page descended
8244 * through. Moreover, if we had no such charge at all, bloated indexes
8245 * would appear to have the same search cost as unbloated ones, at least
8246 * in cases where only a single leaf page is expected to be visited. This
8247 * cost is somewhat arbitrarily set at 50x cpu_operator_cost per page
8248 * touched. The number of such pages is btree tree height plus one (ie,
8249 * we charge for the leaf page too). As above, charge once per estimated
8250 * SAOP/skip array descent.
8251 */
8254 costs.indexTotalCost += costs.num_sa_scans * descentCost;
8255
8256 if (!have_correlation)
8257 {
8259 if (HeapTupleIsValid(vardata.statsTuple))
8262 }
8263 else
8264 {
8265 /* btcost_correlation already called earlier on */
8267 }
8268
8269 *indexStartupCost = costs.indexStartupCost;
8270 *indexTotalCost = costs.indexTotalCost;
8271 *indexSelectivity = costs.indexSelectivity;
8272 *indexCorrelation = costs.indexCorrelation;
8273 *indexPages = costs.numIndexPages;
8274}
#define OidIsValid(objectId)
Definition c.h:917
List * lappend(List *list, void *datum)
Definition list.c:339
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition lsyscache.c:87
#define IsA(nodeptr, _type_)
Definition nodes.h:162
#define nodeTag(nodeptr)
Definition nodes.h:137
double Selectivity
Definition nodes.h:258
#define NIL
Definition pg_list.h:68
#define lsecond(l)
Definition pg_list.h:183
#define linitial_oid(l)
Definition pg_list.h:180
unsigned int Oid
@ IS_NULL
Definition primnodes.h:1975
List * add_predicate_to_index_quals(IndexOptInfo *index, List *indexQuals)
Definition selfuncs.c:7737
#define DEFAULT_PAGE_CPU_MULTIPLIER
Definition selfuncs.c:144
double estimate_array_length(PlannerInfo *root, Node *arrayexpr)
Definition selfuncs.c:2242
void genericcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, GenericCosts *costs)
Definition selfuncs.c:7512
static void examine_indexcol_variable(PlannerInfo *root, IndexOptInfo *index, int indexcol, VariableStatData *vardata)
Definition selfuncs.c:6610
static double btcost_correlation(IndexOptInfo *index, VariableStatData *vardata)
Definition selfuncs.c:7768
double get_variable_numdistinct(VariableStatData *vardata, bool *isdefault)
Definition selfuncs.c:6713
#define DEFAULT_RANGE_INEQ_SEL
Definition selfuncs.h:40
#define BTEqualStrategyNumber
Definition stratnum.h:31
Selectivity indexSelectivity
Definition selfuncs.h:135
BlockNumber numNonLeafPages
Definition selfuncs.h:143
Cost indexStartupCost
Definition selfuncs.h:133
double indexCorrelation
Definition selfuncs.h:136
double num_sa_scans
Definition selfuncs.h:142
Cost indexTotalCost
Definition selfuncs.h:134
double numIndexPages
Definition selfuncs.h:139
double numIndexTuples
Definition selfuncs.h:140
Definition nodes.h:133
Oid opno
Definition primnodes.h:835
Expr * clause
Definition pathnodes.h:2901

References add_predicate_to_index_quals(), ScalarArrayOpExpr::args, Assert, btcost_correlation(), BTEqualStrategyNumber, RestrictInfo::clause, clauselist_selectivity(), cpu_operator_cost, DEFAULT_PAGE_CPU_MULTIPLIER, DEFAULT_RANGE_INEQ_SEL, elog, ERROR, estimate_array_length(), examine_indexcol_variable(), fb(), genericcostestimate(), get_op_opfamily_strategy(), get_variable_numdistinct(), HeapTupleIsValid, IndexPath::indexclauses, GenericCosts::indexCorrelation, IndexPath::indexinfo, GenericCosts::indexSelectivity, GenericCosts::indexStartupCost, GenericCosts::indexTotalCost, InvalidOid, IS_NULL, IsA, JOIN_INNER, lappend(), lfirst_node, linitial_oid, lsecond, Max, Min, NIL, nodeTag, GenericCosts::num_sa_scans, GenericCosts::numIndexPages, GenericCosts::numIndexTuples, GenericCosts::numNonLeafPages, OidIsValid, OpExpr::opno, ScalarArrayOpExpr::opno, ReleaseVariableStats, and root.

Referenced by bthandler().

◆ gincostestimate()

void gincostestimate ( struct PlannerInfo root,
struct IndexPath path,
double  loop_count,
Cost indexStartupCost,
Cost indexTotalCost,
Selectivity indexSelectivity,
double indexCorrelation,
double indexPages 
)
extern

Definition at line 8737 of file selfuncs.c.

8741{
8742 IndexOptInfo *index = path->indexinfo;
8745 double numPages = index->pages,
8746 numTuples = index->tuples;
8747 double numEntryPages,
8750 numEntries;
8751 GinQualCounts counts;
8752 bool matchPossible;
8753 bool fullIndexScan;
8754 double partialScale;
8755 double entryPagesFetched,
8758 double qual_op_cost,
8760 spc_random_page_cost,
8763 Relation indexRel;
8765 ListCell *lc;
8766 int i;
8767
8768 /*
8769 * Obtain statistical information from the meta page, if possible. Else
8770 * set ginStats to zeroes, and we'll cope below.
8771 */
8772 if (!index->hypothetical)
8773 {
8774 /* Lock should have already been obtained in plancat.c */
8775 indexRel = index_open(index->indexoid, NoLock);
8776 ginGetStats(indexRel, &ginStats);
8777 index_close(indexRel, NoLock);
8778 }
8779 else
8780 {
8781 memset(&ginStats, 0, sizeof(ginStats));
8782 }
8783
8784 /*
8785 * Assuming we got valid (nonzero) stats at all, nPendingPages can be
8786 * trusted, but the other fields are data as of the last VACUUM. We can
8787 * scale them up to account for growth since then, but that method only
8788 * goes so far; in the worst case, the stats might be for a completely
8789 * empty index, and scaling them will produce pretty bogus numbers.
8790 * Somewhat arbitrarily, set the cutoff for doing scaling at 4X growth; if
8791 * it's grown more than that, fall back to estimating things only from the
8792 * assumed-accurate index size. But we'll trust nPendingPages in any case
8793 * so long as it's not clearly insane, ie, more than the index size.
8794 */
8795 if (ginStats.nPendingPages < numPages)
8796 numPendingPages = ginStats.nPendingPages;
8797 else
8798 numPendingPages = 0;
8799
8800 if (numPages > 0 && ginStats.nTotalPages <= numPages &&
8801 ginStats.nTotalPages > numPages / 4 &&
8802 ginStats.nEntryPages > 0 && ginStats.nEntries > 0)
8803 {
8804 /*
8805 * OK, the stats seem close enough to sane to be trusted. But we
8806 * still need to scale them by the ratio numPages / nTotalPages to
8807 * account for growth since the last VACUUM.
8808 */
8809 double scale = numPages / ginStats.nTotalPages;
8810
8811 numEntryPages = ceil(ginStats.nEntryPages * scale);
8812 numDataPages = ceil(ginStats.nDataPages * scale);
8813 numEntries = ceil(ginStats.nEntries * scale);
8814 /* ensure we didn't round up too much */
8818 }
8819 else
8820 {
8821 /*
8822 * We might get here because it's a hypothetical index, or an index
8823 * created pre-9.1 and never vacuumed since upgrading (in which case
8824 * its stats would read as zeroes), or just because it's grown too
8825 * much since the last VACUUM for us to put our faith in scaling.
8826 *
8827 * Invent some plausible internal statistics based on the index page
8828 * count (and clamp that to at least 10 pages, just in case). We
8829 * estimate that 90% of the index is entry pages, and the rest is data
8830 * pages. Estimate 100 entries per entry page; this is rather bogus
8831 * since it'll depend on the size of the keys, but it's more robust
8832 * than trying to predict the number of entries per heap tuple.
8833 */
8834 numPages = Max(numPages, 10);
8838 }
8839
8840 /* In an empty index, numEntries could be zero. Avoid divide-by-zero */
8841 if (numEntries < 1)
8842 numEntries = 1;
8843
8844 /*
8845 * If the index is partial, AND the index predicate with the index-bound
8846 * quals to produce a more accurate idea of the number of rows covered by
8847 * the bound conditions.
8848 */
8850
8851 /* Estimate the fraction of main-table tuples that will be visited */
8852 *indexSelectivity = clauselist_selectivity(root, selectivityQuals,
8853 index->rel->relid,
8854 JOIN_INNER,
8855 NULL);
8856
8857 /* fetch estimated page cost for tablespace containing index */
8858 get_tablespace_page_costs(index->reltablespace,
8859 &spc_random_page_cost,
8860 NULL);
8861
8862 /*
8863 * Generic assumption about index correlation: there isn't any.
8864 */
8865 *indexCorrelation = 0.0;
8866
8867 /*
8868 * Examine quals to estimate number of search entries & partial matches
8869 */
8870 memset(&counts, 0, sizeof(counts));
8871 counts.arrayScans = 1;
8872 matchPossible = true;
8873
8874 foreach(lc, path->indexclauses)
8875 {
8877 ListCell *lc2;
8878
8879 foreach(lc2, iclause->indexquals)
8880 {
8882 Expr *clause = rinfo->clause;
8883
8884 if (IsA(clause, OpExpr))
8885 {
8887 index,
8888 iclause->indexcol,
8889 (OpExpr *) clause,
8890 &counts);
8891 if (!matchPossible)
8892 break;
8893 }
8894 else if (IsA(clause, ScalarArrayOpExpr))
8895 {
8897 index,
8898 iclause->indexcol,
8899 (ScalarArrayOpExpr *) clause,
8900 numEntries,
8901 &counts);
8902 if (!matchPossible)
8903 break;
8904 }
8905 else
8906 {
8907 /* shouldn't be anything else for a GIN index */
8908 elog(ERROR, "unsupported GIN indexqual type: %d",
8909 (int) nodeTag(clause));
8910 }
8911 }
8912 }
8913
8914 /* Fall out if there were any provably-unsatisfiable quals */
8915 if (!matchPossible)
8916 {
8917 *indexStartupCost = 0;
8918 *indexTotalCost = 0;
8919 *indexSelectivity = 0;
8920 return;
8921 }
8922
8923 /*
8924 * If attribute has a full scan and at the same time doesn't have normal
8925 * scan, then we'll have to scan all non-null entries of that attribute.
8926 * Currently, we don't have per-attribute statistics for GIN. Thus, we
8927 * must assume the whole GIN index has to be scanned in this case.
8928 */
8929 fullIndexScan = false;
8930 for (i = 0; i < index->nkeycolumns; i++)
8931 {
8932 if (counts.attHasFullScan[i] && !counts.attHasNormalScan[i])
8933 {
8934 fullIndexScan = true;
8935 break;
8936 }
8937 }
8938
8939 if (fullIndexScan || indexQuals == NIL)
8940 {
8941 /*
8942 * Full index scan will be required. We treat this as if every key in
8943 * the index had been listed in the query; is that reasonable?
8944 */
8945 counts.partialEntries = 0;
8946 counts.exactEntries = numEntries;
8947 counts.searchEntries = numEntries;
8948 }
8949
8950 /* Will we have more than one iteration of a nestloop scan? */
8952
8953 /*
8954 * Compute cost to begin scan, first of all, pay attention to pending
8955 * list.
8956 */
8958
8959 /*
8960 * Estimate number of entry pages read. We need to do
8961 * counts.searchEntries searches. Use a power function as it should be,
8962 * but tuples on leaf pages usually is much greater. Here we include all
8963 * searches in entry tree, including search of first entry in partial
8964 * match algorithm
8965 */
8967
8968 /*
8969 * Add an estimate of entry pages read by partial match algorithm. It's a
8970 * scan over leaf pages in entry tree. We haven't any useful stats here,
8971 * so estimate it as proportion. Because counts.partialEntries is really
8972 * pretty bogus (see code above), it's possible that it is more than
8973 * numEntries; clamp the proportion to ensure sanity.
8974 */
8977
8979
8980 /*
8981 * Partial match algorithm reads all data pages before doing actual scan,
8982 * so it's a startup cost. Again, we haven't any useful stats here, so
8983 * estimate it as proportion.
8984 */
8986
8987 *indexStartupCost = 0;
8988 *indexTotalCost = 0;
8989
8990 /*
8991 * Add a CPU-cost component to represent the costs of initial entry btree
8992 * descent. We don't charge any I/O cost for touching upper btree levels,
8993 * since they tend to stay in cache, but we still have to do about log2(N)
8994 * comparisons to descend a btree of N leaf tuples. We charge one
8995 * cpu_operator_cost per comparison.
8996 *
8997 * If there are ScalarArrayOpExprs, charge this once per SA scan. The
8998 * ones after the first one are not startup cost so far as the overall
8999 * plan is concerned, so add them only to "total" cost.
9000 */
9001 if (numEntries > 1) /* avoid computing log(0) */
9002 {
9004 *indexStartupCost += descentCost * counts.searchEntries;
9005 *indexTotalCost += counts.arrayScans * descentCost * counts.searchEntries;
9006 }
9007
9008 /*
9009 * Add a cpu cost per entry-page fetched. This is not amortized over a
9010 * loop.
9011 */
9014
9015 /*
9016 * Add a cpu cost per data-page fetched. This is also not amortized over a
9017 * loop. Since those are the data pages from the partial match algorithm,
9018 * charge them as startup cost.
9019 */
9021
9022 /*
9023 * Since we add the startup cost to the total cost later on, remove the
9024 * initial arrayscan from the total.
9025 */
9026 *indexTotalCost += dataPagesFetched * (counts.arrayScans - 1) * DEFAULT_PAGE_CPU_MULTIPLIER * cpu_operator_cost;
9027
9028 /*
9029 * Calculate cache effects if more than one scan due to nestloops or array
9030 * quals. The result is pro-rated per nestloop scan, but the array qual
9031 * factor shouldn't be pro-rated (compare genericcostestimate).
9032 */
9033 if (outer_scans > 1 || counts.arrayScans > 1)
9034 {
9045 }
9046
9047 /*
9048 * Here we use random page cost because logically-close pages could be far
9049 * apart on disk.
9050 */
9051 *indexStartupCost += (entryPagesFetched + dataPagesFetched) * spc_random_page_cost;
9052
9053 /*
9054 * Now compute the number of data pages fetched during the scan.
9055 *
9056 * We assume every entry to have the same number of items, and that there
9057 * is no overlap between them. (XXX: tsvector and array opclasses collect
9058 * statistics on the frequency of individual keys; it would be nice to use
9059 * those here.)
9060 */
9062
9063 /*
9064 * If there is a lot of overlap among the entries, in particular if one of
9065 * the entries is very frequent, the above calculation can grossly
9066 * under-estimate. As a simple cross-check, calculate a lower bound based
9067 * on the overall selectivity of the quals. At a minimum, we must read
9068 * one item pointer for each matching entry.
9069 *
9070 * The width of each item pointer varies, based on the level of
9071 * compression. We don't have statistics on that, but an average of
9072 * around 3 bytes per item is fairly typical.
9073 */
9074 dataPagesFetchedBySel = ceil(*indexSelectivity *
9075 (numTuples / (BLCKSZ / 3)));
9078
9079 /* Add one page cpu-cost to the startup cost */
9080 *indexStartupCost += DEFAULT_PAGE_CPU_MULTIPLIER * cpu_operator_cost * counts.searchEntries;
9081
9082 /*
9083 * Add once again a CPU-cost for those data pages, before amortizing for
9084 * cache.
9085 */
9087
9088 /* Account for cache effects, the same as above */
9089 if (outer_scans > 1 || counts.arrayScans > 1)
9090 {
9096 }
9097
9098 /* And apply random_page_cost as the cost per page */
9099 *indexTotalCost += *indexStartupCost +
9100 dataPagesFetched * spc_random_page_cost;
9101
9102 /*
9103 * Add on index qual eval costs, much as in genericcostestimate. We charge
9104 * cpu but we can disregard indexorderbys, since GIN doesn't support
9105 * those.
9106 */
9109
9110 *indexStartupCost += qual_arg_cost;
9111 *indexTotalCost += qual_arg_cost;
9112
9113 /*
9114 * Add a cpu cost per search entry, corresponding to the actual visited
9115 * entries.
9116 */
9117 *indexTotalCost += (counts.searchEntries * counts.arrayScans) * (qual_op_cost);
9118 /* Now add a cpu cost per tuple in the posting lists / trees */
9119 *indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost);
9121}
uint32 BlockNumber
Definition block.h:31
double index_pages_fetched(double tuples_fetched, BlockNumber pages, double index_pages, PlannerInfo *root)
Definition costsize.c:898
double cpu_index_tuple_cost
Definition costsize.c:134
void ginGetStats(Relation index, GinStatsData *stats)
Definition ginutil.c:578
int i
Definition isn.c:77
static int list_length(const List *l)
Definition pg_list.h:152
static int scale
Definition pgbench.c:182
static bool gincost_scalararrayopexpr(PlannerInfo *root, IndexOptInfo *index, int indexcol, ScalarArrayOpExpr *clause, double numIndexEntries, GinQualCounts *counts)
Definition selfuncs.c:8621
static bool gincost_opexpr(PlannerInfo *root, IndexOptInfo *index, int indexcol, OpExpr *clause, GinQualCounts *counts)
Definition selfuncs.c:8571
bool attHasNormalScan[INDEX_MAX_KEYS]
Definition selfuncs.c:8444
double exactEntries
Definition selfuncs.c:8446
double arrayScans
Definition selfuncs.c:8448
double partialEntries
Definition selfuncs.c:8445
bool attHasFullScan[INDEX_MAX_KEYS]
Definition selfuncs.c:8443
double searchEntries
Definition selfuncs.c:8447

References add_predicate_to_index_quals(), GinQualCounts::arrayScans, GinQualCounts::attHasFullScan, GinQualCounts::attHasNormalScan, RestrictInfo::clause, clauselist_selectivity(), cpu_index_tuple_cost, cpu_operator_cost, DEFAULT_PAGE_CPU_MULTIPLIER, elog, ERROR, GinQualCounts::exactEntries, fb(), get_quals_from_indexclauses(), get_tablespace_page_costs(), gincost_opexpr(), gincost_scalararrayopexpr(), ginGetStats(), i, index_close(), index_open(), index_other_operands_eval_cost(), index_pages_fetched(), IndexPath::indexclauses, IndexPath::indexinfo, IsA, JOIN_INNER, lfirst_node, list_length(), Max, Min, NIL, nodeTag, NoLock, GinQualCounts::partialEntries, root, scale, and GinQualCounts::searchEntries.

Referenced by ginhandler().

◆ gistcostestimate()

void gistcostestimate ( struct PlannerInfo root,
struct IndexPath path,
double  loop_count,
Cost indexStartupCost,
Cost indexTotalCost,
Selectivity indexSelectivity,
double indexCorrelation,
double indexPages 
)
extern

Definition at line 8322 of file selfuncs.c.

8326{
8327 IndexOptInfo *index = path->indexinfo;
8328 GenericCosts costs = {0};
8330
8331 /* GiST has no metapage, so we treat all pages as leaf pages */
8332
8333 genericcostestimate(root, path, loop_count, &costs);
8334
8335 /*
8336 * We model index descent costs similarly to those for btree, but to do
8337 * that we first need an idea of the tree height. We somewhat arbitrarily
8338 * assume that the fanout is 100, meaning the tree height is at most
8339 * log100(index->pages).
8340 *
8341 * Although this computation isn't really expensive enough to require
8342 * caching, we might as well use index->tree_height to cache it.
8343 */
8344 if (index->tree_height < 0) /* unknown? */
8345 {
8346 if (index->pages > 1) /* avoid computing log(0) */
8347 index->tree_height = (int) (log(index->pages) / log(100.0));
8348 else
8349 index->tree_height = 0;
8350 }
8351
8352 /*
8353 * Add a CPU-cost component to represent the costs of initial descent. We
8354 * just use log(N) here not log2(N) since the branching factor isn't
8355 * necessarily two anyway. As for btree, charge once per SA scan.
8356 */
8357 if (index->tuples > 1) /* avoid computing log(0) */
8358 {
8361 costs.indexTotalCost += costs.num_sa_scans * descentCost;
8362 }
8363
8364 /*
8365 * Likewise add a per-page charge, calculated the same as for btrees.
8366 */
8369 costs.indexTotalCost += costs.num_sa_scans * descentCost;
8370
8371 *indexStartupCost = costs.indexStartupCost;
8372 *indexTotalCost = costs.indexTotalCost;
8373 *indexSelectivity = costs.indexSelectivity;
8374 *indexCorrelation = costs.indexCorrelation;
8375 *indexPages = costs.numIndexPages;
8376}

References cpu_operator_cost, DEFAULT_PAGE_CPU_MULTIPLIER, fb(), genericcostestimate(), GenericCosts::indexCorrelation, IndexPath::indexinfo, GenericCosts::indexSelectivity, GenericCosts::indexStartupCost, GenericCosts::indexTotalCost, GenericCosts::num_sa_scans, GenericCosts::numIndexPages, and root.

Referenced by gisthandler().

◆ hashcostestimate()

void hashcostestimate ( struct PlannerInfo root,
struct IndexPath path,
double  loop_count,
Cost indexStartupCost,
Cost indexTotalCost,
Selectivity indexSelectivity,
double indexCorrelation,
double indexPages 
)
extern

Definition at line 8277 of file selfuncs.c.

8281{
8282 GenericCosts costs = {0};
8283
8284 /* As in btcostestimate, count only the metapage as non-leaf */
8285 costs.numNonLeafPages = 1;
8286
8287 genericcostestimate(root, path, loop_count, &costs);
8288
8289 /*
8290 * A hash index has no descent costs as such, since the index AM can go
8291 * directly to the target bucket after computing the hash value. There
8292 * are a couple of other hash-specific costs that we could conceivably add
8293 * here, though:
8294 *
8295 * Ideally we'd charge spc_random_page_cost for each page in the target
8296 * bucket, not just the numIndexPages pages that genericcostestimate
8297 * thought we'd visit. However in most cases we don't know which bucket
8298 * that will be. There's no point in considering the average bucket size
8299 * because the hash AM makes sure that's always one page.
8300 *
8301 * Likewise, we could consider charging some CPU for each index tuple in
8302 * the bucket, if we knew how many there were. But the per-tuple cost is
8303 * just a hash value comparison, not a general datatype-dependent
8304 * comparison, so any such charge ought to be quite a bit less than
8305 * cpu_operator_cost; which makes it probably not worth worrying about.
8306 *
8307 * A bigger issue is that chance hash-value collisions will result in
8308 * wasted probes into the heap. We don't currently attempt to model this
8309 * cost on the grounds that it's rare, but maybe it's not rare enough.
8310 * (Any fix for this ought to consider the generic lossy-operator problem,
8311 * though; it's not entirely hash-specific.)
8312 */
8313
8314 *indexStartupCost = costs.indexStartupCost;
8315 *indexTotalCost = costs.indexTotalCost;
8316 *indexSelectivity = costs.indexSelectivity;
8317 *indexCorrelation = costs.indexCorrelation;
8318 *indexPages = costs.numIndexPages;
8319}

References fb(), genericcostestimate(), GenericCosts::indexCorrelation, GenericCosts::indexSelectivity, GenericCosts::indexStartupCost, GenericCosts::indexTotalCost, GenericCosts::numIndexPages, GenericCosts::numNonLeafPages, and root.

Referenced by hashhandler().

◆ spgcostestimate()

void spgcostestimate ( struct PlannerInfo root,
struct IndexPath path,
double  loop_count,
Cost indexStartupCost,
Cost indexTotalCost,
Selectivity indexSelectivity,
double indexCorrelation,
double indexPages 
)
extern

Definition at line 8379 of file selfuncs.c.

8383{
8384 IndexOptInfo *index = path->indexinfo;
8385 GenericCosts costs = {0};
8387
8388 /* As in btcostestimate, count only the metapage as non-leaf */
8389 costs.numNonLeafPages = 1;
8390
8391 genericcostestimate(root, path, loop_count, &costs);
8392
8393 /*
8394 * We model index descent costs similarly to those for btree, but to do
8395 * that we first need an idea of the tree height. We somewhat arbitrarily
8396 * assume that the fanout is 100, meaning the tree height is at most
8397 * log100(index->pages).
8398 *
8399 * Although this computation isn't really expensive enough to require
8400 * caching, we might as well use index->tree_height to cache it.
8401 */
8402 if (index->tree_height < 0) /* unknown? */
8403 {
8404 if (index->pages > 1) /* avoid computing log(0) */
8405 index->tree_height = (int) (log(index->pages) / log(100.0));
8406 else
8407 index->tree_height = 0;
8408 }
8409
8410 /*
8411 * Add a CPU-cost component to represent the costs of initial descent. We
8412 * just use log(N) here not log2(N) since the branching factor isn't
8413 * necessarily two anyway. As for btree, charge once per SA scan.
8414 */
8415 if (index->tuples > 1) /* avoid computing log(0) */
8416 {
8419 costs.indexTotalCost += costs.num_sa_scans * descentCost;
8420 }
8421
8422 /*
8423 * Likewise add a per-page charge, calculated the same as for btrees.
8424 */
8427 costs.indexTotalCost += costs.num_sa_scans * descentCost;
8428
8429 *indexStartupCost = costs.indexStartupCost;
8430 *indexTotalCost = costs.indexTotalCost;
8431 *indexSelectivity = costs.indexSelectivity;
8432 *indexCorrelation = costs.indexCorrelation;
8433 *indexPages = costs.numIndexPages;
8434}

References cpu_operator_cost, DEFAULT_PAGE_CPU_MULTIPLIER, fb(), genericcostestimate(), GenericCosts::indexCorrelation, IndexPath::indexinfo, GenericCosts::indexSelectivity, GenericCosts::indexStartupCost, GenericCosts::indexTotalCost, GenericCosts::num_sa_scans, GenericCosts::numIndexPages, GenericCosts::numNonLeafPages, and root.

Referenced by spghandler().