summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/plancat.c
diff options
context:
space:
mode:
authorTom Lane2011-10-14 21:23:01 +0000
committerTom Lane2011-10-14 21:23:46 +0000
commite6858e665731c0f56d3ecc9fbb245c32d24f8ef7 (patch)
tree4df2705d53d53b1bbd7a14d7017cb519d82ee227 /src/backend/optimizer/util/plancat.c
parentdea95c7a7beb5ef66ce89269dd0e84d0c26e5523 (diff)
Measure the number of all-visible pages for use in index-only scan costing.
Add a column pg_class.relallvisible to remember the number of pages that were all-visible according to the visibility map as of the last VACUUM (or ANALYZE, or some other operations that update pg_class.relpages). Use relallvisible/relpages, instead of an arbitrary constant, to estimate how many heap page fetches can be avoided during an index-only scan. This is pretty primitive and will no doubt see refinements once we've acquired more field experience with the index-only scan mechanism, but it's way better than using a constant. Note: I had to adjust an underspecified query in the window.sql regression test, because it was changing answers when the plan changed to use an index-only scan. Some of the adjacent tests perhaps should be adjusted as well, but I didn't do that here.
Diffstat (limited to 'src/backend/optimizer/util/plancat.c')
-rw-r--r--src/backend/optimizer/util/plancat.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 0b3675f1461..aa436004f89 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -116,7 +116,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
*/
if (!inhparent)
estimate_rel_size(relation, rel->attr_widths - rel->min_attr,
- &rel->pages, &rel->tuples);
+ &rel->pages, &rel->tuples, &rel->allvisfrac);
/*
* Make list of indexes. Ignore indexes on system catalogs if told to.
@@ -339,8 +339,10 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
}
else
{
+ double allvisfrac; /* dummy */
+
estimate_rel_size(indexRelation, NULL,
- &info->pages, &info->tuples);
+ &info->pages, &info->tuples, &allvisfrac);
if (info->tuples > rel->tuples)
info->tuples = rel->tuples;
}
@@ -369,17 +371,21 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
/*
* estimate_rel_size - estimate # pages and # tuples in a table or index
*
+ * We also estimate the fraction of the pages that are marked all-visible in
+ * the visibility map, for use in estimation of index-only scans.
+ *
* If attr_widths isn't NULL, it points to the zero-index entry of the
* relation's attr_widths[] cache; we fill this in if we have need to compute
* the attribute widths for estimation purposes.
*/
void
estimate_rel_size(Relation rel, int32 *attr_widths,
- BlockNumber *pages, double *tuples)
+ BlockNumber *pages, double *tuples, double *allvisfrac)
{
BlockNumber curpages;
BlockNumber relpages;
double reltuples;
+ BlockNumber relallvisible;
double density;
switch (rel->rd_rel->relkind)
@@ -432,11 +438,13 @@ estimate_rel_size(Relation rel, int32 *attr_widths,
if (curpages == 0)
{
*tuples = 0;
+ *allvisfrac = 0;
break;
}
/* coerce values in pg_class to more desirable types */
relpages = (BlockNumber) rel->rd_rel->relpages;
reltuples = (double) rel->rd_rel->reltuples;
+ relallvisible = (BlockNumber) rel->rd_rel->relallvisible;
/*
* If it's an index, discount the metapage while estimating the
@@ -480,21 +488,37 @@ estimate_rel_size(Relation rel, int32 *attr_widths,
density = (BLCKSZ - SizeOfPageHeaderData) / tuple_width;
}
*tuples = rint(density * (double) curpages);
+
+ /*
+ * We use relallvisible as-is, rather than scaling it up like we
+ * do for the pages and tuples counts, on the theory that any
+ * pages added since the last VACUUM are most likely not marked
+ * all-visible. But costsize.c wants it converted to a fraction.
+ */
+ if (relallvisible == 0 || curpages <= 0)
+ *allvisfrac = 0;
+ else if ((double) relallvisible >= curpages)
+ *allvisfrac = 1;
+ else
+ *allvisfrac = (double) relallvisible / curpages;
break;
case RELKIND_SEQUENCE:
/* Sequences always have a known size */
*pages = 1;
*tuples = 1;
+ *allvisfrac = 0;
break;
case RELKIND_FOREIGN_TABLE:
/* Just use whatever's in pg_class */
*pages = rel->rd_rel->relpages;
*tuples = rel->rd_rel->reltuples;
+ *allvisfrac = 0;
break;
default:
/* else it has no disk storage; probably shouldn't get here? */
*pages = 0;
*tuples = 0;
+ *allvisfrac = 0;
break;
}
}