7095
7096
GinStatsData ginStats;
7098
* Obtain statistic information from the meta page
7099
* Obtain statistical information from the meta page, if possible. Else
7100
* set ginStats to zeroes, and we'll cope below.
7100
indexRel = index_open(index->indexoid, AccessShareLock);
7101
ginGetStats(indexRel, &ginStats);
7102
index_close(indexRel, AccessShareLock);
7104
numEntryPages = ginStats.nEntryPages;
7105
numDataPages = ginStats.nDataPages;
7106
numPendingPages = ginStats.nPendingPages;
7107
numEntries = ginStats.nEntries;
7102
if (!index->hypothetical)
7104
indexRel = index_open(index->indexoid, AccessShareLock);
7105
ginGetStats(indexRel, &ginStats);
7106
index_close(indexRel, AccessShareLock);
7110
memset(&ginStats, 0, sizeof(ginStats));
7110
* nPendingPages can be trusted, but the other fields are as of the last
7111
* VACUUM. Scale them by the ratio numPages / nTotalPages to account for
7112
* growth since then. If the fields are zero (implying no VACUUM at all,
7113
* and an index created pre-9.1), assume all pages are entry pages.
7114
* Assuming we got valid (nonzero) stats at all, nPendingPages can be
7115
* trusted, but the other fields are data as of the last VACUUM. We can
7116
* scale them up to account for growth since then, but that method only
7117
* goes so far; in the worst case, the stats might be for a completely
7118
* empty index, and scaling them will produce pretty bogus numbers.
7119
* Somewhat arbitrarily, set the cutoff for doing scaling at 4X growth; if
7120
* it's grown more than that, fall back to estimating things only from the
7121
* assumed-accurate index size. But we'll trust nPendingPages in any case
7122
* so long as it's not clearly insane, ie, more than the index size.
7115
if (ginStats.nTotalPages == 0 || ginStats.nEntryPages == 0)
7117
numEntryPages = numPages;
7119
numEntries = numTuples; /* bogus, but no other info available */
7124
if (ginStats.nPendingPages < numPages)
7125
numPendingPages = ginStats.nPendingPages;
7127
numPendingPages = 0;
7129
if (numPages > 0 && ginStats.nTotalPages <= numPages &&
7130
ginStats.nTotalPages > numPages / 4 &&
7131
ginStats.nEntryPages > 0 && ginStats.nEntries > 0)
7134
* OK, the stats seem close enough to sane to be trusted. But we
7135
* still need to scale them by the ratio numPages / nTotalPages to
7136
* account for growth since the last VACUUM.
7123
7138
double scale = numPages / ginStats.nTotalPages;
7125
numEntryPages = ceil(numEntryPages * scale);
7126
numDataPages = ceil(numDataPages * scale);
7127
numEntries = ceil(numEntries * scale);
7140
numEntryPages = ceil(ginStats.nEntryPages * scale);
7141
numDataPages = ceil(ginStats.nDataPages * scale);
7142
numEntries = ceil(ginStats.nEntries * scale);
7128
7143
/* ensure we didn't round up too much */
7129
numEntryPages = Min(numEntryPages, numPages);
7130
numDataPages = Min(numDataPages, numPages - numEntryPages);
7144
numEntryPages = Min(numEntryPages, numPages - numPendingPages);
7145
numDataPages = Min(numDataPages,
7146
numPages - numPendingPages - numEntryPages);
7151
* We might get here because it's a hypothetical index, or an index
7152
* created pre-9.1 and never vacuumed since upgrading (in which case
7153
* its stats would read as zeroes), or just because it's grown too
7154
* much since the last VACUUM for us to put our faith in scaling.
7156
* Invent some plausible internal statistics based on the index page
7157
* count (and clamp that to at least 10 pages, just in case). We
7158
* estimate that 90% of the index is entry pages, and the rest is data
7159
* pages. Estimate 100 entries per entry page; this is rather bogus
7160
* since it'll depend on the size of the keys, but it's more robust
7161
* than trying to predict the number of entries per heap tuple.
7163
numPages = Max(numPages, 10);
7164
numEntryPages = floor((numPages - numPendingPages) * 0.90);
7165
numDataPages = numPages - numPendingPages - numEntryPages;
7166
numEntries = floor(numEntryPages * 100);
7133
7169
/* In an empty index, numEntries could be zero. Avoid divide-by-zero */
7255
7291
* Add an estimate of entry pages read by partial match algorithm. It's a
7256
7292
* scan over leaf pages in entry tree. We haven't any useful stats here,
7257
* so estimate it as proportion.
7293
* so estimate it as proportion. Because counts.partialEntries is really
7294
* pretty bogus (see code above), it's possible that it is more than
7295
* numEntries; clamp the proportion to ensure sanity.
7259
entryPagesFetched += ceil(numEntryPages * counts.partialEntries / numEntries);
7297
partialScale = counts.partialEntries / numEntries;
7298
partialScale = Min(partialScale, 1.0);
7300
entryPagesFetched += ceil(numEntryPages * partialScale);
7262
7303
* Partial match algorithm reads all data pages before doing actual scan,
7263
* so it's a startup cost. Again, we haven't any useful stats here, so,
7264
* estimate it as proportion
7304
* so it's a startup cost. Again, we haven't any useful stats here, so
7305
* estimate it as proportion.
7266
dataPagesFetched = ceil(numDataPages * counts.partialEntries / numEntries);
7307
dataPagesFetched = ceil(numDataPages * partialScale);
7269
7310
* Calculate cache effects if more than one scan due to nestloops or array