mirror of
https://github.com/postgres/postgres.git
synced 2025-08-27 07:42:10 +03:00
Add stxdinherit flag to pg_statistic_ext_data
Add pg_statistic_ext_data.stxdinherit flag, so that for each extended statistics definition we can store two versions of data - one for the relation alone, one for the whole inheritance tree. This is analogous to pg_statistic.stainherit, but we failed to include such flag in catalogs for extended statistics, and we had to work around it (see commits859b3003de
,36c4bc6e72
and20b9fa308e
). This changes the relationship between the two catalogs storing extended statistics objects (pg_statistic_ext and pg_statistic_ext_data). Until now, there was a simple 1:1 mapping - for each definition there was one pg_statistic_ext_data row, and this row was inserted while creating the statistics (and then updated during ANALYZE). With the stxdinherit flag, we don't know how many rows there will be (child relations may be added after the statistics object is defined), so there may be up to two rows. We could make CREATE STATISTICS to always create both rows, but that seems wasteful - without partitioning we only need stxdinherit=false rows, and declaratively partitioned tables need only stxdinherit=true. So we no longer initialize pg_statistic_ext_data in CREATE STATISTICS, and instead make that a responsibility of ANALYZE. Which is what we do for regular statistics too. Patch by me, with extensive improvements and fixes by Justin Pryzby. Author: Tomas Vondra, Justin Pryzby Reviewed-by: Tomas Vondra, Justin Pryzby Discussion: https://postgr.es/m/20210923212624.GI831%40telsasoft.com
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
#include "catalog/pg_am.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_statistic_ext.h"
|
||||
#include "catalog/pg_statistic_ext_data.h"
|
||||
#include "foreign/fdwapi.h"
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
@@ -1276,6 +1277,87 @@ get_relation_constraints(PlannerInfo *root,
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try loading data for the statistics object.
|
||||
*
|
||||
* We don't know if the data (specified by statOid and inh value) exist.
|
||||
* The result is stored in stainfos list.
|
||||
*/
|
||||
static void
|
||||
get_relation_statistics_worker(List **stainfos, RelOptInfo *rel,
|
||||
Oid statOid, bool inh,
|
||||
Bitmapset *keys, List *exprs)
|
||||
{
|
||||
Form_pg_statistic_ext_data dataForm;
|
||||
HeapTuple dtup;
|
||||
|
||||
dtup = SearchSysCache2(STATEXTDATASTXOID,
|
||||
ObjectIdGetDatum(statOid), BoolGetDatum(inh));
|
||||
if (!HeapTupleIsValid(dtup))
|
||||
return;
|
||||
|
||||
dataForm = (Form_pg_statistic_ext_data) GETSTRUCT(dtup);
|
||||
|
||||
/* add one StatisticExtInfo for each kind built */
|
||||
if (statext_is_kind_built(dtup, STATS_EXT_NDISTINCT))
|
||||
{
|
||||
StatisticExtInfo *info = makeNode(StatisticExtInfo);
|
||||
|
||||
info->statOid = statOid;
|
||||
info->inherit = dataForm->stxdinherit;
|
||||
info->rel = rel;
|
||||
info->kind = STATS_EXT_NDISTINCT;
|
||||
info->keys = bms_copy(keys);
|
||||
info->exprs = exprs;
|
||||
|
||||
*stainfos = lappend(*stainfos, info);
|
||||
}
|
||||
|
||||
if (statext_is_kind_built(dtup, STATS_EXT_DEPENDENCIES))
|
||||
{
|
||||
StatisticExtInfo *info = makeNode(StatisticExtInfo);
|
||||
|
||||
info->statOid = statOid;
|
||||
info->inherit = dataForm->stxdinherit;
|
||||
info->rel = rel;
|
||||
info->kind = STATS_EXT_DEPENDENCIES;
|
||||
info->keys = bms_copy(keys);
|
||||
info->exprs = exprs;
|
||||
|
||||
*stainfos = lappend(*stainfos, info);
|
||||
}
|
||||
|
||||
if (statext_is_kind_built(dtup, STATS_EXT_MCV))
|
||||
{
|
||||
StatisticExtInfo *info = makeNode(StatisticExtInfo);
|
||||
|
||||
info->statOid = statOid;
|
||||
info->inherit = dataForm->stxdinherit;
|
||||
info->rel = rel;
|
||||
info->kind = STATS_EXT_MCV;
|
||||
info->keys = bms_copy(keys);
|
||||
info->exprs = exprs;
|
||||
|
||||
*stainfos = lappend(*stainfos, info);
|
||||
}
|
||||
|
||||
if (statext_is_kind_built(dtup, STATS_EXT_EXPRESSIONS))
|
||||
{
|
||||
StatisticExtInfo *info = makeNode(StatisticExtInfo);
|
||||
|
||||
info->statOid = statOid;
|
||||
info->inherit = dataForm->stxdinherit;
|
||||
info->rel = rel;
|
||||
info->kind = STATS_EXT_EXPRESSIONS;
|
||||
info->keys = bms_copy(keys);
|
||||
info->exprs = exprs;
|
||||
|
||||
*stainfos = lappend(*stainfos, info);
|
||||
}
|
||||
|
||||
ReleaseSysCache(dtup);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_relation_statistics
|
||||
* Retrieve extended statistics defined on the table.
|
||||
@@ -1299,7 +1381,6 @@ get_relation_statistics(RelOptInfo *rel, Relation relation)
|
||||
Oid statOid = lfirst_oid(l);
|
||||
Form_pg_statistic_ext staForm;
|
||||
HeapTuple htup;
|
||||
HeapTuple dtup;
|
||||
Bitmapset *keys = NULL;
|
||||
List *exprs = NIL;
|
||||
int i;
|
||||
@@ -1309,10 +1390,6 @@ get_relation_statistics(RelOptInfo *rel, Relation relation)
|
||||
elog(ERROR, "cache lookup failed for statistics object %u", statOid);
|
||||
staForm = (Form_pg_statistic_ext) GETSTRUCT(htup);
|
||||
|
||||
dtup = SearchSysCache1(STATEXTDATASTXOID, ObjectIdGetDatum(statOid));
|
||||
if (!HeapTupleIsValid(dtup))
|
||||
elog(ERROR, "cache lookup failed for statistics object %u", statOid);
|
||||
|
||||
/*
|
||||
* First, build the array of columns covered. This is ultimately
|
||||
* wasted if no stats within the object have actually been built, but
|
||||
@@ -1324,6 +1401,11 @@ get_relation_statistics(RelOptInfo *rel, Relation relation)
|
||||
/*
|
||||
* Preprocess expressions (if any). We read the expressions, run them
|
||||
* through eval_const_expressions, and fix the varnos.
|
||||
*
|
||||
* XXX We don't know yet if there are any data for this stats object,
|
||||
* with either stxdinherit value. But it's reasonable to assume there
|
||||
* is at least one of those, possibly both. So it's better to process
|
||||
* keys and expressions here.
|
||||
*/
|
||||
{
|
||||
bool isnull;
|
||||
@@ -1364,61 +1446,13 @@ get_relation_statistics(RelOptInfo *rel, Relation relation)
|
||||
}
|
||||
}
|
||||
|
||||
/* add one StatisticExtInfo for each kind built */
|
||||
if (statext_is_kind_built(dtup, STATS_EXT_NDISTINCT))
|
||||
{
|
||||
StatisticExtInfo *info = makeNode(StatisticExtInfo);
|
||||
/* extract statistics for possible values of stxdinherit flag */
|
||||
|
||||
info->statOid = statOid;
|
||||
info->rel = rel;
|
||||
info->kind = STATS_EXT_NDISTINCT;
|
||||
info->keys = bms_copy(keys);
|
||||
info->exprs = exprs;
|
||||
get_relation_statistics_worker(&stainfos, rel, statOid, true, keys, exprs);
|
||||
|
||||
stainfos = lappend(stainfos, info);
|
||||
}
|
||||
|
||||
if (statext_is_kind_built(dtup, STATS_EXT_DEPENDENCIES))
|
||||
{
|
||||
StatisticExtInfo *info = makeNode(StatisticExtInfo);
|
||||
|
||||
info->statOid = statOid;
|
||||
info->rel = rel;
|
||||
info->kind = STATS_EXT_DEPENDENCIES;
|
||||
info->keys = bms_copy(keys);
|
||||
info->exprs = exprs;
|
||||
|
||||
stainfos = lappend(stainfos, info);
|
||||
}
|
||||
|
||||
if (statext_is_kind_built(dtup, STATS_EXT_MCV))
|
||||
{
|
||||
StatisticExtInfo *info = makeNode(StatisticExtInfo);
|
||||
|
||||
info->statOid = statOid;
|
||||
info->rel = rel;
|
||||
info->kind = STATS_EXT_MCV;
|
||||
info->keys = bms_copy(keys);
|
||||
info->exprs = exprs;
|
||||
|
||||
stainfos = lappend(stainfos, info);
|
||||
}
|
||||
|
||||
if (statext_is_kind_built(dtup, STATS_EXT_EXPRESSIONS))
|
||||
{
|
||||
StatisticExtInfo *info = makeNode(StatisticExtInfo);
|
||||
|
||||
info->statOid = statOid;
|
||||
info->rel = rel;
|
||||
info->kind = STATS_EXT_EXPRESSIONS;
|
||||
info->keys = bms_copy(keys);
|
||||
info->exprs = exprs;
|
||||
|
||||
stainfos = lappend(stainfos, info);
|
||||
}
|
||||
get_relation_statistics_worker(&stainfos, rel, statOid, false, keys, exprs);
|
||||
|
||||
ReleaseSysCache(htup);
|
||||
ReleaseSysCache(dtup);
|
||||
bms_free(keys);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user