PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 
)

Definition at line 8191 of file selfuncs.c.

8195{
8196 IndexOptInfo *index = path->indexinfo;
8197 List *indexQuals = get_quals_from_indexclauses(path->indexclauses);
8198 double numPages = index->pages;
8199 RelOptInfo *baserel = index->rel;
8200 RangeTblEntry *rte = planner_rt_fetch(baserel->relid, root);
8201 Cost spc_seq_page_cost;
8202 Cost spc_random_page_cost;
8203 double qual_arg_cost;
8204 double qualSelectivity;
8205 BrinStatsData statsData;
8206 double indexRanges;
8207 double minimalRanges;
8208 double estimatedRanges;
8209 double selec;
8210 Relation indexRel;
8211 ListCell *l;
8212 VariableStatData vardata;
8213
8214 Assert(rte->rtekind == RTE_RELATION);
8215
8216 /* fetch estimated page cost for the tablespace containing the index */
8217 get_tablespace_page_costs(index->reltablespace,
8218 &spc_random_page_cost,
8219 &spc_seq_page_cost);
8220
8221 /*
8222 * Obtain some data from the index itself, if possible. Otherwise invent
8223 * some plausible internal statistics based on the relation page count.
8224 */
8225 if (!index->hypothetical)
8226 {
8227 /*
8228 * A lock should have already been obtained on the index in plancat.c.
8229 */
8230 indexRel = index_open(index->indexoid, NoLock);
8231 brinGetStats(indexRel, &statsData);
8232 index_close(indexRel, NoLock);
8233
8234 /* work out the actual number of ranges in the index */
8235 indexRanges = Max(ceil((double) baserel->pages /
8236 statsData.pagesPerRange), 1.0);
8237 }
8238 else
8239 {
8240 /*
8241 * Assume default number of pages per range, and estimate the number
8242 * of ranges based on that.
8243 */
8244 indexRanges = Max(ceil((double) baserel->pages /
8246
8248 statsData.revmapNumPages = (indexRanges / REVMAP_PAGE_MAXITEMS) + 1;
8249 }
8250
8251 /*
8252 * Compute index correlation
8253 *
8254 * Because we can use all index quals equally when scanning, we can use
8255 * the largest correlation (in absolute value) among columns used by the
8256 * query. Start at zero, the worst possible case. If we cannot find any
8257 * correlation statistics, we will keep it as 0.
8258 */
8259 *indexCorrelation = 0;
8260
8261 foreach(l, path->indexclauses)
8262 {
8263 IndexClause *iclause = lfirst_node(IndexClause, l);
8264 AttrNumber attnum = index->indexkeys[iclause->indexcol];
8265
8266 /* attempt to lookup stats in relation for this index column */
8267 if (attnum != 0)
8268 {
8269 /* Simple variable -- look to stats for the underlying table */
8271 (*get_relation_stats_hook) (root, rte, attnum, &vardata))
8272 {
8273 /*
8274 * The hook took control of acquiring a stats tuple. If it
8275 * did supply a tuple, it'd better have supplied a freefunc.
8276 */
8277 if (HeapTupleIsValid(vardata.statsTuple) && !vardata.freefunc)
8278 elog(ERROR,
8279 "no function provided to release variable stats with");
8280 }
8281 else
8282 {
8283 vardata.statsTuple =
8284 SearchSysCache3(STATRELATTINH,
8285 ObjectIdGetDatum(rte->relid),
8287 BoolGetDatum(false));
8288 vardata.freefunc = ReleaseSysCache;
8289 }
8290 }
8291 else
8292 {
8293 /*
8294 * Looks like we've found an expression column in the index. Let's
8295 * see if there's any stats for it.
8296 */
8297
8298 /* get the attnum from the 0-based index. */
8299 attnum = iclause->indexcol + 1;
8300
8302 (*get_index_stats_hook) (root, index->indexoid, attnum, &vardata))
8303 {
8304 /*
8305 * The hook took control of acquiring a stats tuple. If it
8306 * did supply a tuple, it'd better have supplied a freefunc.
8307 */
8308 if (HeapTupleIsValid(vardata.statsTuple) &&
8309 !vardata.freefunc)
8310 elog(ERROR, "no function provided to release variable stats with");
8311 }
8312 else
8313 {
8314 vardata.statsTuple = SearchSysCache3(STATRELATTINH,
8315 ObjectIdGetDatum(index->indexoid),
8317 BoolGetDatum(false));
8318 vardata.freefunc = ReleaseSysCache;
8319 }
8320 }
8321
8322 if (HeapTupleIsValid(vardata.statsTuple))
8323 {
8324 AttStatsSlot sslot;
8325
8326 if (get_attstatsslot(&sslot, vardata.statsTuple,
8327 STATISTIC_KIND_CORRELATION, InvalidOid,
8329 {
8330 double varCorrelation = 0.0;
8331
8332 if (sslot.nnumbers > 0)
8333 varCorrelation = fabs(sslot.numbers[0]);
8334
8335 if (varCorrelation > *indexCorrelation)
8336 *indexCorrelation = varCorrelation;
8337
8338 free_attstatsslot(&sslot);
8339 }
8340 }
8341
8342 ReleaseVariableStats(vardata);
8343 }
8344
8345 qualSelectivity = clauselist_selectivity(root, indexQuals,
8346 baserel->relid,
8347 JOIN_INNER, NULL);
8348
8349 /*
8350 * Now calculate the minimum possible ranges we could match with if all of
8351 * the rows were in the perfect order in the table's heap.
8352 */
8353 minimalRanges = ceil(indexRanges * qualSelectivity);
8354
8355 /*
8356 * Now estimate the number of ranges that we'll touch by using the
8357 * indexCorrelation from the stats. Careful not to divide by zero (note
8358 * we're using the absolute value of the correlation).
8359 */
8360 if (*indexCorrelation < 1.0e-10)
8361 estimatedRanges = indexRanges;
8362 else
8363 estimatedRanges = Min(minimalRanges / *indexCorrelation, indexRanges);
8364
8365 /* we expect to visit this portion of the table */
8366 selec = estimatedRanges / indexRanges;
8367
8368 CLAMP_PROBABILITY(selec);
8369
8370 *indexSelectivity = selec;
8371
8372 /*
8373 * Compute the index qual costs, much as in genericcostestimate, to add to
8374 * the index costs. We can disregard indexorderbys, since BRIN doesn't
8375 * support those.
8376 */
8377 qual_arg_cost = index_other_operands_eval_cost(root, indexQuals);
8378
8379 /*
8380 * Compute the startup cost as the cost to read the whole revmap
8381 * sequentially, including the cost to execute the index quals.
8382 */
8383 *indexStartupCost =
8384 spc_seq_page_cost * statsData.revmapNumPages * loop_count;
8385 *indexStartupCost += qual_arg_cost;
8386
8387 /*
8388 * To read a BRIN index there might be a bit of back and forth over
8389 * regular pages, as revmap might point to them out of sequential order;
8390 * calculate the total cost as reading the whole index in random order.
8391 */
8392 *indexTotalCost = *indexStartupCost +
8393 spc_random_page_cost * (numPages - statsData.revmapNumPages) * loop_count;
8394
8395 /*
8396 * Charge a small amount per range tuple which we expect to match to. This
8397 * is meant to reflect the costs of manipulating the bitmap. The BRIN scan
8398 * will set a bit for each page in the range when we find a matching
8399 * range, so we must multiply the charge by the number of pages in the
8400 * range.
8401 */
8402 *indexTotalCost += 0.1 * cpu_operator_cost * estimatedRanges *
8403 statsData.pagesPerRange;
8404
8405 *indexPages = index->pages;
8406}
int16 AttrNumber
Definition: attnum.h:21
void brinGetStats(Relation index, BrinStatsData *stats)
Definition: brin.c:1649
#define BRIN_DEFAULT_PAGES_PER_RANGE
Definition: brin.h:39
#define REVMAP_PAGE_MAXITEMS
Definition: brin_page.h:93
#define Min(x, y)
Definition: c.h:975
#define Max(x, y)
Definition: c.h:969
Selectivity clauselist_selectivity(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo)
Definition: clausesel.c:100
double cpu_operator_cost
Definition: costsize.c:134
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
Assert(PointerIsAligned(start, uint64))
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
#define NoLock
Definition: lockdefs.h:34
void free_attstatsslot(AttStatsSlot *sslot)
Definition: lsyscache.c:3427
bool get_attstatsslot(AttStatsSlot *sslot, HeapTuple statstuple, int reqkind, Oid reqop, int flags)
Definition: lsyscache.c:3317
#define ATTSTATSSLOT_NUMBERS
Definition: lsyscache.h:44
double Cost
Definition: nodes.h:257
@ JOIN_INNER
Definition: nodes.h:299
@ RTE_RELATION
Definition: parsenodes.h:1026
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:597
int16 attnum
Definition: pg_attribute.h:74
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
#define InvalidOid
Definition: postgres_ext.h:35
tree ctl root
Definition: radixtree.h:1857
List * get_quals_from_indexclauses(List *indexclauses)
Definition: selfuncs.c:6678
get_index_stats_hook_type get_index_stats_hook
Definition: selfuncs.c:149
Cost index_other_operands_eval_cost(PlannerInfo *root, List *indexquals)
Definition: selfuncs.c:6708
get_relation_stats_hook_type get_relation_stats_hook
Definition: selfuncs.c:148
#define ReleaseVariableStats(vardata)
Definition: selfuncs.h:100
#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:182
float4 * numbers
Definition: lsyscache.h:57
int nnumbers
Definition: lsyscache.h:58
BlockNumber revmapNumPages
Definition: brin.h:35
BlockNumber pagesPerRange
Definition: brin.h:34
AttrNumber indexcol
Definition: pathnodes.h:1800
List * indexclauses
Definition: pathnodes.h:1750
IndexOptInfo * indexinfo
Definition: pathnodes.h:1749
Definition: pg_list.h:54
RTEKind rtekind
Definition: parsenodes.h:1061
Index relid
Definition: pathnodes.h:945
BlockNumber pages
Definition: pathnodes.h:975
HeapTuple statsTuple
Definition: selfuncs.h:89
void(* freefunc)(HeapTuple tuple)
Definition: selfuncs.h:91
Definition: type.h:96
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:243

References Assert(), attnum, ATTSTATSSLOT_NUMBERS, BoolGetDatum(), BRIN_DEFAULT_PAGES_PER_RANGE, brinGetStats(), CLAMP_PROBABILITY, clauselist_selectivity(), cpu_operator_cost, elog, ERROR, free_attstatsslot(), VariableStatData::freefunc, 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, IndexClause::indexcol, IndexPath::indexinfo, Int16GetDatum(), InvalidOid, JOIN_INNER, lfirst_node, Max, Min, AttStatsSlot::nnumbers, NoLock, AttStatsSlot::numbers, ObjectIdGetDatum(), RelOptInfo::pages, BrinStatsData::pagesPerRange, planner_rt_fetch, ReleaseSysCache(), ReleaseVariableStats, RelOptInfo::relid, REVMAP_PAGE_MAXITEMS, BrinStatsData::revmapNumPages, root, RTE_RELATION, RangeTblEntry::rtekind, SearchSysCache3(), and VariableStatData::statsTuple.

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 
)

Definition at line 7006 of file selfuncs.c.

7010{
7011 IndexOptInfo *index = path->indexinfo;
7012 GenericCosts costs = {0};
7013 Oid relid;
7014 AttrNumber colnum;
7015 VariableStatData vardata = {0};
7016 double numIndexTuples;
7017 Cost descentCost;
7018 List *indexBoundQuals;
7019 int indexcol;
7020 bool eqQualHere;
7021 bool found_saop;
7022 bool found_is_null_op;
7023 double num_sa_scans;
7024 ListCell *lc;
7025
7026 /*
7027 * For a btree scan, only leading '=' quals plus inequality quals for the
7028 * immediately next attribute contribute to index selectivity (these are
7029 * the "boundary quals" that determine the starting and stopping points of
7030 * the index scan). Additional quals can suppress visits to the heap, so
7031 * it's OK to count them in indexSelectivity, but they should not count
7032 * for estimating numIndexTuples. So we must examine the given indexquals
7033 * to find out which ones count as boundary quals. We rely on the
7034 * knowledge that they are given in index column order.
7035 *
7036 * For a RowCompareExpr, we consider only the first column, just as
7037 * rowcomparesel() does.
7038 *
7039 * If there's a ScalarArrayOpExpr in the quals, we'll actually perform up
7040 * to N index descents (not just one), but the ScalarArrayOpExpr's
7041 * operator can be considered to act the same as it normally does.
7042 */
7043 indexBoundQuals = NIL;
7044 indexcol = 0;
7045 eqQualHere = false;
7046 found_saop = false;
7047 found_is_null_op = false;
7048 num_sa_scans = 1;
7049 foreach(lc, path->indexclauses)
7050 {
7051 IndexClause *iclause = lfirst_node(IndexClause, lc);
7052 ListCell *lc2;
7053
7054 if (indexcol != iclause->indexcol)
7055 {
7056 /* Beginning of a new column's quals */
7057 if (!eqQualHere)
7058 break; /* done if no '=' qual for indexcol */
7059 eqQualHere = false;
7060 indexcol++;
7061 if (indexcol != iclause->indexcol)
7062 break; /* no quals at all for indexcol */
7063 }
7064
7065 /* Examine each indexqual associated with this index clause */
7066 foreach(lc2, iclause->indexquals)
7067 {
7068 RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc2);
7069 Expr *clause = rinfo->clause;
7070 Oid clause_op = InvalidOid;
7071 int op_strategy;
7072
7073 if (IsA(clause, OpExpr))
7074 {
7075 OpExpr *op = (OpExpr *) clause;
7076
7077 clause_op = op->opno;
7078 }
7079 else if (IsA(clause, RowCompareExpr))
7080 {
7081 RowCompareExpr *rc = (RowCompareExpr *) clause;
7082
7083 clause_op = linitial_oid(rc->opnos);
7084 }
7085 else if (IsA(clause, ScalarArrayOpExpr))
7086 {
7087 ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
7088 Node *other_operand = (Node *) lsecond(saop->args);
7089 double alength = estimate_array_length(root, other_operand);
7090
7091 clause_op = saop->opno;
7092 found_saop = true;
7093 /* estimate SA descents by indexBoundQuals only */
7094 if (alength > 1)
7095 num_sa_scans *= alength;
7096 }
7097 else if (IsA(clause, NullTest))
7098 {
7099 NullTest *nt = (NullTest *) clause;
7100
7101 if (nt->nulltesttype == IS_NULL)
7102 {
7103 found_is_null_op = true;
7104 /* IS NULL is like = for selectivity purposes */
7105 eqQualHere = true;
7106 }
7107 }
7108 else
7109 elog(ERROR, "unsupported indexqual type: %d",
7110 (int) nodeTag(clause));
7111
7112 /* check for equality operator */
7113 if (OidIsValid(clause_op))
7114 {
7115 op_strategy = get_op_opfamily_strategy(clause_op,
7116 index->opfamily[indexcol]);
7117 Assert(op_strategy != 0); /* not a member of opfamily?? */
7118 if (op_strategy == BTEqualStrategyNumber)
7119 eqQualHere = true;
7120 }
7121
7122 indexBoundQuals = lappend(indexBoundQuals, rinfo);
7123 }
7124 }
7125
7126 /*
7127 * If index is unique and we found an '=' clause for each column, we can
7128 * just assume numIndexTuples = 1 and skip the expensive
7129 * clauselist_selectivity calculations. However, a ScalarArrayOp or
7130 * NullTest invalidates that theory, even though it sets eqQualHere.
7131 */
7132 if (index->unique &&
7133 indexcol == index->nkeycolumns - 1 &&
7134 eqQualHere &&
7135 !found_saop &&
7136 !found_is_null_op)
7137 numIndexTuples = 1.0;
7138 else
7139 {
7140 List *selectivityQuals;
7141 Selectivity btreeSelectivity;
7142
7143 /*
7144 * If the index is partial, AND the index predicate with the
7145 * index-bound quals to produce a more accurate idea of the number of
7146 * rows covered by the bound conditions.
7147 */
7148 selectivityQuals = add_predicate_to_index_quals(index, indexBoundQuals);
7149
7150 btreeSelectivity = clauselist_selectivity(root, selectivityQuals,
7151 index->rel->relid,
7152 JOIN_INNER,
7153 NULL);
7154 numIndexTuples = btreeSelectivity * index->rel->tuples;
7155
7156 /*
7157 * btree automatically combines individual ScalarArrayOpExpr primitive
7158 * index scans whenever the tuples covered by the next set of array
7159 * keys are close to tuples covered by the current set. That puts a
7160 * natural ceiling on the worst case number of descents -- there
7161 * cannot possibly be more than one descent per leaf page scanned.
7162 *
7163 * Clamp the number of descents to at most 1/3 the number of index
7164 * pages. This avoids implausibly high estimates with low selectivity
7165 * paths, where scans usually require only one or two descents. This
7166 * is most likely to help when there are several SAOP clauses, where
7167 * naively accepting the total number of distinct combinations of
7168 * array elements as the number of descents would frequently lead to
7169 * wild overestimates.
7170 *
7171 * We somewhat arbitrarily don't just make the cutoff the total number
7172 * of leaf pages (we make it 1/3 the total number of pages instead) to
7173 * give the btree code credit for its ability to continue on the leaf
7174 * level with low selectivity scans.
7175 */
7176 num_sa_scans = Min(num_sa_scans, ceil(index->pages * 0.3333333));
7177 num_sa_scans = Max(num_sa_scans, 1);
7178
7179 /*
7180 * As in genericcostestimate(), we have to adjust for any
7181 * ScalarArrayOpExpr quals included in indexBoundQuals, and then round
7182 * to integer.
7183 *
7184 * It is tempting to make genericcostestimate behave as if SAOP
7185 * clauses work in almost the same way as scalar operators during
7186 * btree scans, making the top-level scan look like a continuous scan
7187 * (as opposed to num_sa_scans-many primitive index scans). After
7188 * all, btree scans mostly work like that at runtime. However, such a
7189 * scheme would badly bias genericcostestimate's simplistic approach
7190 * to calculating numIndexPages through prorating.
7191 *
7192 * Stick with the approach taken by non-native SAOP scans for now.
7193 * genericcostestimate will use the Mackert-Lohman formula to
7194 * compensate for repeat page fetches, even though that definitely
7195 * won't happen during btree scans (not for leaf pages, at least).
7196 * We're usually very pessimistic about the number of primitive index
7197 * scans that will be required, but it's not clear how to do better.
7198 */
7199 numIndexTuples = rint(numIndexTuples / num_sa_scans);
7200 }
7201
7202 /*
7203 * Now do generic index cost estimation.
7204 */
7205 costs.numIndexTuples = numIndexTuples;
7206 costs.num_sa_scans = num_sa_scans;
7207
7208 genericcostestimate(root, path, loop_count, &costs);
7209
7210 /*
7211 * Add a CPU-cost component to represent the costs of initial btree
7212 * descent. We don't charge any I/O cost for touching upper btree levels,
7213 * since they tend to stay in cache, but we still have to do about log2(N)
7214 * comparisons to descend a btree of N leaf tuples. We charge one
7215 * cpu_operator_cost per comparison.
7216 *
7217 * If there are ScalarArrayOpExprs, charge this once per estimated SA
7218 * index descent. The ones after the first one are not startup cost so
7219 * far as the overall plan goes, so just add them to "total" cost.
7220 */
7221 if (index->tuples > 1) /* avoid computing log(0) */
7222 {
7223 descentCost = ceil(log(index->tuples) / log(2.0)) * cpu_operator_cost;
7224 costs.indexStartupCost += descentCost;
7225 costs.indexTotalCost += costs.num_sa_scans * descentCost;
7226 }
7227
7228 /*
7229 * Even though we're not charging I/O cost for touching upper btree pages,
7230 * it's still reasonable to charge some CPU cost per page descended
7231 * through. Moreover, if we had no such charge at all, bloated indexes
7232 * would appear to have the same search cost as unbloated ones, at least
7233 * in cases where only a single leaf page is expected to be visited. This
7234 * cost is somewhat arbitrarily set at 50x cpu_operator_cost per page
7235 * touched. The number of such pages is btree tree height plus one (ie,
7236 * we charge for the leaf page too). As above, charge once per estimated
7237 * SA index descent.
7238 */
7239 descentCost = (index->tree_height + 1) * DEFAULT_PAGE_CPU_MULTIPLIER * cpu_operator_cost;
7240 costs.indexStartupCost += descentCost;
7241 costs.indexTotalCost += costs.num_sa_scans * descentCost;
7242
7243 /*
7244 * If we can get an estimate of the first column's ordering correlation C
7245 * from pg_statistic, estimate the index correlation as C for a
7246 * single-column index, or C * 0.75 for multiple columns. (The idea here
7247 * is that multiple columns dilute the importance of the first column's
7248 * ordering, but don't negate it entirely. Before 8.0 we divided the
7249 * correlation by the number of columns, but that seems too strong.)
7250 */
7251 if (index->indexkeys[0] != 0)
7252 {
7253 /* Simple variable --- look to stats for the underlying table */
7254 RangeTblEntry *rte = planner_rt_fetch(index->rel->relid, root);
7255
7256 Assert(rte->rtekind == RTE_RELATION);
7257 relid = rte->relid;
7258 Assert(relid != InvalidOid);
7259 colnum = index->indexkeys[0];
7260
7262 (*get_relation_stats_hook) (root, rte, colnum, &vardata))
7263 {
7264 /*
7265 * The hook took control of acquiring a stats tuple. If it did
7266 * supply a tuple, it'd better have supplied a freefunc.
7267 */
7268 if (HeapTupleIsValid(vardata.statsTuple) &&
7269 !vardata.freefunc)
7270 elog(ERROR, "no function provided to release variable stats with");
7271 }
7272 else
7273 {
7274 vardata.statsTuple = SearchSysCache3(STATRELATTINH,
7275 ObjectIdGetDatum(relid),
7276 Int16GetDatum(colnum),
7277 BoolGetDatum(rte->inh));
7278 vardata.freefunc = ReleaseSysCache;
7279 }
7280 }
7281 else
7282 {
7283 /* Expression --- maybe there are stats for the index itself */
7284 relid = index->indexoid;
7285 colnum = 1;
7286
7288 (*get_index_stats_hook) (root, relid, colnum, &vardata))
7289 {
7290 /*
7291 * The hook took control of acquiring a stats tuple. If it did
7292 * supply a tuple, it'd better have supplied a freefunc.
7293 */
7294 if (HeapTupleIsValid(vardata.statsTuple) &&
7295 !vardata.freefunc)
7296 elog(ERROR, "no function provided to release variable stats with");
7297 }
7298 else
7299 {
7300 vardata.statsTuple = SearchSysCache3(STATRELATTINH,
7301 ObjectIdGetDatum(relid),
7302 Int16GetDatum(colnum),
7303 BoolGetDatum(false));
7304 vardata.freefunc = ReleaseSysCache;
7305 }
7306 }
7307
7308 if (HeapTupleIsValid(vardata.statsTuple))
7309 {
7310 Oid sortop;
7311 AttStatsSlot sslot;
7312
7313 sortop = get_opfamily_member(index->opfamily[0],
7314 index->opcintype[0],
7315 index->opcintype[0],
7317 if (OidIsValid(sortop) &&
7318 get_attstatsslot(&sslot, vardata.statsTuple,
7319 STATISTIC_KIND_CORRELATION, sortop,
7321 {
7322 double varCorrelation;
7323
7324 Assert(sslot.nnumbers == 1);
7325 varCorrelation = sslot.numbers[0];
7326
7327 if (index->reverse_sort[0])
7328 varCorrelation = -varCorrelation;
7329
7330 if (index->nkeycolumns > 1)
7331 costs.indexCorrelation = varCorrelation * 0.75;
7332 else
7333 costs.indexCorrelation = varCorrelation;
7334
7335 free_attstatsslot(&sslot);
7336 }
7337 }
7338
7339 ReleaseVariableStats(vardata);
7340
7341 *indexStartupCost = costs.indexStartupCost;
7342 *indexTotalCost = costs.indexTotalCost;
7343 *indexSelectivity = costs.indexSelectivity;
7344 *indexCorrelation = costs.indexCorrelation;
7345 *indexPages = costs.numIndexPages;
7346}
#define OidIsValid(objectId)
Definition: c.h:746
List * lappend(List *list, void *datum)
Definition: list.c:339
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:84
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:167
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define nodeTag(nodeptr)
Definition: nodes.h:139
double Selectivity
Definition: nodes.h:256
#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
Definition: postgres_ext.h:30
@ IS_NULL
Definition: primnodes.h:1957
List * add_predicate_to_index_quals(IndexOptInfo *index, List *indexQuals)
Definition: selfuncs.c:6985
#define DEFAULT_PAGE_CPU_MULTIPLIER
Definition: selfuncs.c:145
double estimate_array_length(PlannerInfo *root, Node *arrayexpr)
Definition: selfuncs.c:2140
void genericcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, GenericCosts *costs)
Definition: selfuncs.c:6762
#define BTLessStrategyNumber
Definition: stratnum.h:29
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Selectivity indexSelectivity
Definition: selfuncs.h:128
Cost indexStartupCost
Definition: selfuncs.h:126
double indexCorrelation
Definition: selfuncs.h:129
double num_sa_scans
Definition: selfuncs.h:135
Cost indexTotalCost
Definition: selfuncs.h:127
double numIndexPages
Definition: selfuncs.h:132
double numIndexTuples
Definition: selfuncs.h:133
List * indexquals
Definition: pathnodes.h:1798
Definition: nodes.h:135
NullTestType nulltesttype
Definition: primnodes.h:1964
Oid opno
Definition: primnodes.h:835
Expr * clause
Definition: pathnodes.h:2602

References add_predicate_to_index_quals(), ScalarArrayOpExpr::args, Assert(), ATTSTATSSLOT_NUMBERS, BoolGetDatum(), BTEqualStrategyNumber, BTLessStrategyNumber, RestrictInfo::clause, clauselist_selectivity(), cpu_operator_cost, DEFAULT_PAGE_CPU_MULTIPLIER, elog, ERROR, estimate_array_length(), free_attstatsslot(), VariableStatData::freefunc, genericcostestimate(), get_attstatsslot(), get_index_stats_hook, get_op_opfamily_strategy(), get_opfamily_member(), get_relation_stats_hook, HeapTupleIsValid, IndexPath::indexclauses, IndexClause::indexcol, GenericCosts::indexCorrelation, IndexPath::indexinfo, IndexClause::indexquals, GenericCosts::indexSelectivity, GenericCosts::indexStartupCost, GenericCosts::indexTotalCost, RangeTblEntry::inh, Int16GetDatum(), InvalidOid, IS_NULL, IsA, JOIN_INNER, lappend(), lfirst_node, linitial_oid, lsecond, Max, Min, NIL, AttStatsSlot::nnumbers, nodeTag, NullTest::nulltesttype, GenericCosts::num_sa_scans, AttStatsSlot::numbers, GenericCosts::numIndexPages, GenericCosts::numIndexTuples, ObjectIdGetDatum(), OidIsValid, OpExpr::opno, ScalarArrayOpExpr::opno, planner_rt_fetch, ReleaseSysCache(), ReleaseVariableStats, root, RTE_RELATION, RangeTblEntry::rtekind, SearchSysCache3(), and VariableStatData::statsTuple.

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 
)

Definition at line 7801 of file selfuncs.c.

7805{
7806 IndexOptInfo *index = path->indexinfo;
7807 List *indexQuals = get_quals_from_indexclauses(path->indexclauses);
7808 List *selectivityQuals;
7809 double numPages = index->pages,
7810 numTuples = index->tuples;
7811 double numEntryPages,
7812 numDataPages,
7813 numPendingPages,
7814 numEntries;
7815 GinQualCounts counts;
7816 bool matchPossible;
7817 bool fullIndexScan;
7818 double partialScale;
7819 double entryPagesFetched,
7820 dataPagesFetched,
7821 dataPagesFetchedBySel;
7822 double qual_op_cost,
7823 qual_arg_cost,
7824 spc_random_page_cost,
7825 outer_scans;
7826 Cost descentCost;
7827 Relation indexRel;
7828 GinStatsData ginStats;
7829 ListCell *lc;
7830 int i;
7831
7832 /*
7833 * Obtain statistical information from the meta page, if possible. Else
7834 * set ginStats to zeroes, and we'll cope below.
7835 */
7836 if (!index->hypothetical)
7837 {
7838 /* Lock should have already been obtained in plancat.c */
7839 indexRel = index_open(index->indexoid, NoLock);
7840 ginGetStats(indexRel, &ginStats);
7841 index_close(indexRel, NoLock);
7842 }
7843 else
7844 {
7845 memset(&ginStats, 0, sizeof(ginStats));
7846 }
7847
7848 /*
7849 * Assuming we got valid (nonzero) stats at all, nPendingPages can be
7850 * trusted, but the other fields are data as of the last VACUUM. We can
7851 * scale them up to account for growth since then, but that method only
7852 * goes so far; in the worst case, the stats might be for a completely
7853 * empty index, and scaling them will produce pretty bogus numbers.
7854 * Somewhat arbitrarily, set the cutoff for doing scaling at 4X growth; if
7855 * it's grown more than that, fall back to estimating things only from the
7856 * assumed-accurate index size. But we'll trust nPendingPages in any case
7857 * so long as it's not clearly insane, ie, more than the index size.
7858 */
7859 if (ginStats.nPendingPages < numPages)
7860 numPendingPages = ginStats.nPendingPages;
7861 else
7862 numPendingPages = 0;
7863
7864 if (numPages > 0 && ginStats.nTotalPages <= numPages &&
7865 ginStats.nTotalPages > numPages / 4 &&
7866 ginStats.nEntryPages > 0 && ginStats.nEntries > 0)
7867 {
7868 /*
7869 * OK, the stats seem close enough to sane to be trusted. But we
7870 * still need to scale them by the ratio numPages / nTotalPages to
7871 * account for growth since the last VACUUM.
7872 */
7873 double scale = numPages / ginStats.nTotalPages;
7874
7875 numEntryPages = ceil(ginStats.nEntryPages * scale);
7876 numDataPages = ceil(ginStats.nDataPages * scale);
7877 numEntries = ceil(ginStats.nEntries * scale);
7878 /* ensure we didn't round up too much */
7879 numEntryPages = Min(numEntryPages, numPages - numPendingPages);
7880 numDataPages = Min(numDataPages,
7881 numPages - numPendingPages - numEntryPages);
7882 }
7883 else
7884 {
7885 /*
7886 * We might get here because it's a hypothetical index, or an index
7887 * created pre-9.1 and never vacuumed since upgrading (in which case
7888 * its stats would read as zeroes), or just because it's grown too
7889 * much since the last VACUUM for us to put our faith in scaling.
7890 *
7891 * Invent some plausible internal statistics based on the index page
7892 * count (and clamp that to at least 10 pages, just in case). We
7893 * estimate that 90% of the index is entry pages, and the rest is data
7894 * pages. Estimate 100 entries per entry page; this is rather bogus
7895 * since it'll depend on the size of the keys, but it's more robust
7896 * than trying to predict the number of entries per heap tuple.
7897 */
7898 numPages = Max(numPages, 10);
7899 numEntryPages = floor((numPages - numPendingPages) * 0.90);
7900 numDataPages = numPages - numPendingPages - numEntryPages;
7901 numEntries = floor(numEntryPages * 100);
7902 }
7903
7904 /* In an empty index, numEntries could be zero. Avoid divide-by-zero */
7905 if (numEntries < 1)
7906 numEntries = 1;
7907
7908 /*
7909 * If the index is partial, AND the index predicate with the index-bound
7910 * quals to produce a more accurate idea of the number of rows covered by
7911 * the bound conditions.
7912 */
7913 selectivityQuals = add_predicate_to_index_quals(index, indexQuals);
7914
7915 /* Estimate the fraction of main-table tuples that will be visited */
7916 *indexSelectivity = clauselist_selectivity(root, selectivityQuals,
7917 index->rel->relid,
7918 JOIN_INNER,
7919 NULL);
7920
7921 /* fetch estimated page cost for tablespace containing index */
7922 get_tablespace_page_costs(index->reltablespace,
7923 &spc_random_page_cost,
7924 NULL);
7925
7926 /*
7927 * Generic assumption about index correlation: there isn't any.
7928 */
7929 *indexCorrelation = 0.0;
7930
7931 /*
7932 * Examine quals to estimate number of search entries & partial matches
7933 */
7934 memset(&counts, 0, sizeof(counts));
7935 counts.arrayScans = 1;
7936 matchPossible = true;
7937
7938 foreach(lc, path->indexclauses)
7939 {
7940 IndexClause *iclause = lfirst_node(IndexClause, lc);
7941 ListCell *lc2;
7942
7943 foreach(lc2, iclause->indexquals)
7944 {
7945 RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc2);
7946 Expr *clause = rinfo->clause;
7947
7948 if (IsA(clause, OpExpr))
7949 {
7950 matchPossible = gincost_opexpr(root,
7951 index,
7952 iclause->indexcol,
7953 (OpExpr *) clause,
7954 &counts);
7955 if (!matchPossible)
7956 break;
7957 }
7958 else if (IsA(clause, ScalarArrayOpExpr))
7959 {
7960 matchPossible = gincost_scalararrayopexpr(root,
7961 index,
7962 iclause->indexcol,
7963 (ScalarArrayOpExpr *) clause,
7964 numEntries,
7965 &counts);
7966 if (!matchPossible)
7967 break;
7968 }
7969 else
7970 {
7971 /* shouldn't be anything else for a GIN index */
7972 elog(ERROR, "unsupported GIN indexqual type: %d",
7973 (int) nodeTag(clause));
7974 }
7975 }
7976 }
7977
7978 /* Fall out if there were any provably-unsatisfiable quals */
7979 if (!matchPossible)
7980 {
7981 *indexStartupCost = 0;
7982 *indexTotalCost = 0;
7983 *indexSelectivity = 0;
7984 return;
7985 }
7986
7987 /*
7988 * If attribute has a full scan and at the same time doesn't have normal
7989 * scan, then we'll have to scan all non-null entries of that attribute.
7990 * Currently, we don't have per-attribute statistics for GIN. Thus, we
7991 * must assume the whole GIN index has to be scanned in this case.
7992 */
7993 fullIndexScan = false;
7994 for (i = 0; i < index->nkeycolumns; i++)
7995 {
7996 if (counts.attHasFullScan[i] && !counts.attHasNormalScan[i])
7997 {
7998 fullIndexScan = true;
7999 break;
8000 }
8001 }
8002
8003 if (fullIndexScan || indexQuals == NIL)
8004 {
8005 /*
8006 * Full index scan will be required. We treat this as if every key in
8007 * the index had been listed in the query; is that reasonable?
8008 */
8009 counts.partialEntries = 0;
8010 counts.exactEntries = numEntries;
8011 counts.searchEntries = numEntries;
8012 }
8013
8014 /* Will we have more than one iteration of a nestloop scan? */
8015 outer_scans = loop_count;
8016
8017 /*
8018 * Compute cost to begin scan, first of all, pay attention to pending
8019 * list.
8020 */
8021 entryPagesFetched = numPendingPages;
8022
8023 /*
8024 * Estimate number of entry pages read. We need to do
8025 * counts.searchEntries searches. Use a power function as it should be,
8026 * but tuples on leaf pages usually is much greater. Here we include all
8027 * searches in entry tree, including search of first entry in partial
8028 * match algorithm
8029 */
8030 entryPagesFetched += ceil(counts.searchEntries * rint(pow(numEntryPages, 0.15)));
8031
8032 /*
8033 * Add an estimate of entry pages read by partial match algorithm. It's a
8034 * scan over leaf pages in entry tree. We haven't any useful stats here,
8035 * so estimate it as proportion. Because counts.partialEntries is really
8036 * pretty bogus (see code above), it's possible that it is more than
8037 * numEntries; clamp the proportion to ensure sanity.
8038 */
8039 partialScale = counts.partialEntries / numEntries;
8040 partialScale = Min(partialScale, 1.0);
8041
8042 entryPagesFetched += ceil(numEntryPages * partialScale);
8043
8044 /*
8045 * Partial match algorithm reads all data pages before doing actual scan,
8046 * so it's a startup cost. Again, we haven't any useful stats here, so
8047 * estimate it as proportion.
8048 */
8049 dataPagesFetched = ceil(numDataPages * partialScale);
8050
8051 *indexStartupCost = 0;
8052 *indexTotalCost = 0;
8053
8054 /*
8055 * Add a CPU-cost component to represent the costs of initial entry btree
8056 * descent. We don't charge any I/O cost for touching upper btree levels,
8057 * since they tend to stay in cache, but we still have to do about log2(N)
8058 * comparisons to descend a btree of N leaf tuples. We charge one
8059 * cpu_operator_cost per comparison.
8060 *
8061 * If there are ScalarArrayOpExprs, charge this once per SA scan. The
8062 * ones after the first one are not startup cost so far as the overall
8063 * plan is concerned, so add them only to "total" cost.
8064 */
8065 if (numEntries > 1) /* avoid computing log(0) */
8066 {
8067 descentCost = ceil(log(numEntries) / log(2.0)) * cpu_operator_cost;
8068 *indexStartupCost += descentCost * counts.searchEntries;
8069 *indexTotalCost += counts.arrayScans * descentCost * counts.searchEntries;
8070 }
8071
8072 /*
8073 * Add a cpu cost per entry-page fetched. This is not amortized over a
8074 * loop.
8075 */
8076 *indexStartupCost += entryPagesFetched * DEFAULT_PAGE_CPU_MULTIPLIER * cpu_operator_cost;
8077 *indexTotalCost += entryPagesFetched * counts.arrayScans * DEFAULT_PAGE_CPU_MULTIPLIER * cpu_operator_cost;
8078
8079 /*
8080 * Add a cpu cost per data-page fetched. This is also not amortized over a
8081 * loop. Since those are the data pages from the partial match algorithm,
8082 * charge them as startup cost.
8083 */
8084 *indexStartupCost += DEFAULT_PAGE_CPU_MULTIPLIER * cpu_operator_cost * dataPagesFetched;
8085
8086 /*
8087 * Since we add the startup cost to the total cost later on, remove the
8088 * initial arrayscan from the total.
8089 */
8090 *indexTotalCost += dataPagesFetched * (counts.arrayScans - 1) * DEFAULT_PAGE_CPU_MULTIPLIER * cpu_operator_cost;
8091
8092 /*
8093 * Calculate cache effects if more than one scan due to nestloops or array
8094 * quals. The result is pro-rated per nestloop scan, but the array qual
8095 * factor shouldn't be pro-rated (compare genericcostestimate).
8096 */
8097 if (outer_scans > 1 || counts.arrayScans > 1)
8098 {
8099 entryPagesFetched *= outer_scans * counts.arrayScans;
8100 entryPagesFetched = index_pages_fetched(entryPagesFetched,
8101 (BlockNumber) numEntryPages,
8102 numEntryPages, root);
8103 entryPagesFetched /= outer_scans;
8104 dataPagesFetched *= outer_scans * counts.arrayScans;
8105 dataPagesFetched = index_pages_fetched(dataPagesFetched,
8106 (BlockNumber) numDataPages,
8107 numDataPages, root);
8108 dataPagesFetched /= outer_scans;
8109 }
8110
8111 /*
8112 * Here we use random page cost because logically-close pages could be far
8113 * apart on disk.
8114 */
8115 *indexStartupCost += (entryPagesFetched + dataPagesFetched) * spc_random_page_cost;
8116
8117 /*
8118 * Now compute the number of data pages fetched during the scan.
8119 *
8120 * We assume every entry to have the same number of items, and that there
8121 * is no overlap between them. (XXX: tsvector and array opclasses collect
8122 * statistics on the frequency of individual keys; it would be nice to use
8123 * those here.)
8124 */
8125 dataPagesFetched = ceil(numDataPages * counts.exactEntries / numEntries);
8126
8127 /*
8128 * If there is a lot of overlap among the entries, in particular if one of
8129 * the entries is very frequent, the above calculation can grossly
8130 * under-estimate. As a simple cross-check, calculate a lower bound based
8131 * on the overall selectivity of the quals. At a minimum, we must read
8132 * one item pointer for each matching entry.
8133 *
8134 * The width of each item pointer varies, based on the level of
8135 * compression. We don't have statistics on that, but an average of
8136 * around 3 bytes per item is fairly typical.
8137 */
8138 dataPagesFetchedBySel = ceil(*indexSelectivity *
8139 (numTuples / (BLCKSZ / 3)));
8140 if (dataPagesFetchedBySel > dataPagesFetched)
8141 dataPagesFetched = dataPagesFetchedBySel;
8142
8143 /* Add one page cpu-cost to the startup cost */
8144 *indexStartupCost += DEFAULT_PAGE_CPU_MULTIPLIER * cpu_operator_cost * counts.searchEntries;
8145
8146 /*
8147 * Add once again a CPU-cost for those data pages, before amortizing for
8148 * cache.
8149 */
8150 *indexTotalCost += dataPagesFetched * counts.arrayScans * DEFAULT_PAGE_CPU_MULTIPLIER * cpu_operator_cost;
8151
8152 /* Account for cache effects, the same as above */
8153 if (outer_scans > 1 || counts.arrayScans > 1)
8154 {
8155 dataPagesFetched *= outer_scans * counts.arrayScans;
8156 dataPagesFetched = index_pages_fetched(dataPagesFetched,
8157 (BlockNumber) numDataPages,
8158 numDataPages, root);
8159 dataPagesFetched /= outer_scans;
8160 }
8161
8162 /* And apply random_page_cost as the cost per page */
8163 *indexTotalCost += *indexStartupCost +
8164 dataPagesFetched * spc_random_page_cost;
8165
8166 /*
8167 * Add on index qual eval costs, much as in genericcostestimate. We charge
8168 * cpu but we can disregard indexorderbys, since GIN doesn't support
8169 * those.
8170 */
8171 qual_arg_cost = index_other_operands_eval_cost(root, indexQuals);
8172 qual_op_cost = cpu_operator_cost * list_length(indexQuals);
8173
8174 *indexStartupCost += qual_arg_cost;
8175 *indexTotalCost += qual_arg_cost;
8176
8177 /*
8178 * Add a cpu cost per search entry, corresponding to the actual visited
8179 * entries.
8180 */
8181 *indexTotalCost += (counts.searchEntries * counts.arrayScans) * (qual_op_cost);
8182 /* Now add a cpu cost per tuple in the posting lists / trees */
8183 *indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost);
8184 *indexPages = dataPagesFetched;
8185}
uint32 BlockNumber
Definition: block.h:31
double index_pages_fetched(double tuples_fetched, BlockNumber pages, double index_pages, PlannerInfo *root)
Definition: costsize.c:908
double cpu_index_tuple_cost
Definition: costsize.c:133
void ginGetStats(Relation index, GinStatsData *stats)
Definition: ginutil.c:628
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:7685
static bool gincost_opexpr(PlannerInfo *root, IndexOptInfo *index, int indexcol, OpExpr *clause, GinQualCounts *counts)
Definition: selfuncs.c:7635
bool attHasNormalScan[INDEX_MAX_KEYS]
Definition: selfuncs.c:7508
double exactEntries
Definition: selfuncs.c:7510
double arrayScans
Definition: selfuncs.c:7512
double partialEntries
Definition: selfuncs.c:7509
bool attHasFullScan[INDEX_MAX_KEYS]
Definition: selfuncs.c:7507
double searchEntries
Definition: selfuncs.c:7511
BlockNumber nDataPages
Definition: gin.h:60
BlockNumber nPendingPages
Definition: gin.h:57
BlockNumber nEntryPages
Definition: gin.h:59
int64 nEntries
Definition: gin.h:61
BlockNumber nTotalPages
Definition: gin.h:58

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, 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, IndexClause::indexcol, IndexPath::indexinfo, IndexClause::indexquals, IsA, JOIN_INNER, lfirst_node, list_length(), Max, Min, GinStatsData::nDataPages, GinStatsData::nEntries, GinStatsData::nEntryPages, NIL, nodeTag, NoLock, GinStatsData::nPendingPages, GinStatsData::nTotalPages, 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 
)

Definition at line 7391 of file selfuncs.c.

7395{
7396 IndexOptInfo *index = path->indexinfo;
7397 GenericCosts costs = {0};
7398 Cost descentCost;
7399
7400 genericcostestimate(root, path, loop_count, &costs);
7401
7402 /*
7403 * We model index descent costs similarly to those for btree, but to do
7404 * that we first need an idea of the tree height. We somewhat arbitrarily
7405 * assume that the fanout is 100, meaning the tree height is at most
7406 * log100(index->pages).
7407 *
7408 * Although this computation isn't really expensive enough to require
7409 * caching, we might as well use index->tree_height to cache it.
7410 */
7411 if (index->tree_height < 0) /* unknown? */
7412 {
7413 if (index->pages > 1) /* avoid computing log(0) */
7414 index->tree_height = (int) (log(index->pages) / log(100.0));
7415 else
7416 index->tree_height = 0;
7417 }
7418
7419 /*
7420 * Add a CPU-cost component to represent the costs of initial descent. We
7421 * just use log(N) here not log2(N) since the branching factor isn't
7422 * necessarily two anyway. As for btree, charge once per SA scan.
7423 */
7424 if (index->tuples > 1) /* avoid computing log(0) */
7425 {
7426 descentCost = ceil(log(index->tuples)) * cpu_operator_cost;
7427 costs.indexStartupCost += descentCost;
7428 costs.indexTotalCost += costs.num_sa_scans * descentCost;
7429 }
7430
7431 /*
7432 * Likewise add a per-page charge, calculated the same as for btrees.
7433 */
7434 descentCost = (index->tree_height + 1) * DEFAULT_PAGE_CPU_MULTIPLIER * cpu_operator_cost;
7435 costs.indexStartupCost += descentCost;
7436 costs.indexTotalCost += costs.num_sa_scans * descentCost;
7437
7438 *indexStartupCost = costs.indexStartupCost;
7439 *indexTotalCost = costs.indexTotalCost;
7440 *indexSelectivity = costs.indexSelectivity;
7441 *indexCorrelation = costs.indexCorrelation;
7442 *indexPages = costs.numIndexPages;
7443}

References cpu_operator_cost, DEFAULT_PAGE_CPU_MULTIPLIER, 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 
)

Definition at line 7349 of file selfuncs.c.

7353{
7354 GenericCosts costs = {0};
7355
7356 genericcostestimate(root, path, loop_count, &costs);
7357
7358 /*
7359 * A hash index has no descent costs as such, since the index AM can go
7360 * directly to the target bucket after computing the hash value. There
7361 * are a couple of other hash-specific costs that we could conceivably add
7362 * here, though:
7363 *
7364 * Ideally we'd charge spc_random_page_cost for each page in the target
7365 * bucket, not just the numIndexPages pages that genericcostestimate
7366 * thought we'd visit. However in most cases we don't know which bucket
7367 * that will be. There's no point in considering the average bucket size
7368 * because the hash AM makes sure that's always one page.
7369 *
7370 * Likewise, we could consider charging some CPU for each index tuple in
7371 * the bucket, if we knew how many there were. But the per-tuple cost is
7372 * just a hash value comparison, not a general datatype-dependent
7373 * comparison, so any such charge ought to be quite a bit less than
7374 * cpu_operator_cost; which makes it probably not worth worrying about.
7375 *
7376 * A bigger issue is that chance hash-value collisions will result in
7377 * wasted probes into the heap. We don't currently attempt to model this
7378 * cost on the grounds that it's rare, but maybe it's not rare enough.
7379 * (Any fix for this ought to consider the generic lossy-operator problem,
7380 * though; it's not entirely hash-specific.)
7381 */
7382
7383 *indexStartupCost = costs.indexStartupCost;
7384 *indexTotalCost = costs.indexTotalCost;
7385 *indexSelectivity = costs.indexSelectivity;
7386 *indexCorrelation = costs.indexCorrelation;
7387 *indexPages = costs.numIndexPages;
7388}

References genericcostestimate(), GenericCosts::indexCorrelation, GenericCosts::indexSelectivity, GenericCosts::indexStartupCost, GenericCosts::indexTotalCost, GenericCosts::numIndexPages, 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 
)

Definition at line 7446 of file selfuncs.c.

7450{
7451 IndexOptInfo *index = path->indexinfo;
7452 GenericCosts costs = {0};
7453 Cost descentCost;
7454
7455 genericcostestimate(root, path, loop_count, &costs);
7456
7457 /*
7458 * We model index descent costs similarly to those for btree, but to do
7459 * that we first need an idea of the tree height. We somewhat arbitrarily
7460 * assume that the fanout is 100, meaning the tree height is at most
7461 * log100(index->pages).
7462 *
7463 * Although this computation isn't really expensive enough to require
7464 * caching, we might as well use index->tree_height to cache it.
7465 */
7466 if (index->tree_height < 0) /* unknown? */
7467 {
7468 if (index->pages > 1) /* avoid computing log(0) */
7469 index->tree_height = (int) (log(index->pages) / log(100.0));
7470 else
7471 index->tree_height = 0;
7472 }
7473
7474 /*
7475 * Add a CPU-cost component to represent the costs of initial descent. We
7476 * just use log(N) here not log2(N) since the branching factor isn't
7477 * necessarily two anyway. As for btree, charge once per SA scan.
7478 */
7479 if (index->tuples > 1) /* avoid computing log(0) */
7480 {
7481 descentCost = ceil(log(index->tuples)) * cpu_operator_cost;
7482 costs.indexStartupCost += descentCost;
7483 costs.indexTotalCost += costs.num_sa_scans * descentCost;
7484 }
7485
7486 /*
7487 * Likewise add a per-page charge, calculated the same as for btrees.
7488 */
7489 descentCost = (index->tree_height + 1) * DEFAULT_PAGE_CPU_MULTIPLIER * cpu_operator_cost;
7490 costs.indexStartupCost += descentCost;
7491 costs.indexTotalCost += costs.num_sa_scans * descentCost;
7492
7493 *indexStartupCost = costs.indexStartupCost;
7494 *indexTotalCost = costs.indexTotalCost;
7495 *indexSelectivity = costs.indexSelectivity;
7496 *indexCorrelation = costs.indexCorrelation;
7497 *indexPages = costs.numIndexPages;
7498}

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

Referenced by spghandler().