mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03:00
Avoid unnecessary relation stats query in pg_dump.
The few fields we need can be easily collected in getTables() and getIndexes() and stored in RelStatsInfo. Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us> Reported-by: Andres Freund <andres@anarazel.de> Co-authored-by: Corey Huinker <corey.huinker@gmail.com> Co-authored-by: Jeff Davis <pgsql@j-davis.com> Discussion: https://postgr.es/m/CADkLM=f0a43aTd88xW4xCFayEF25g-7hTrHX_WhV40HyocsUGg@mail.gmail.com
This commit is contained in:
@ -56,6 +56,7 @@
|
||||
#include "common/connect.h"
|
||||
#include "common/int.h"
|
||||
#include "common/relpath.h"
|
||||
#include "common/shortest_dec.h"
|
||||
#include "compress_io.h"
|
||||
#include "dumputils.h"
|
||||
#include "fe_utils/option_utils.h"
|
||||
@ -524,6 +525,9 @@ main(int argc, char **argv)
|
||||
pg_logging_set_level(PG_LOG_WARNING);
|
||||
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
|
||||
|
||||
/* ensure that locale does not affect floating point interpretation */
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
|
||||
/*
|
||||
* Initialize what we need for parallel execution, especially for thread
|
||||
* support on Windows.
|
||||
@ -6814,7 +6818,8 @@ getFuncs(Archive *fout)
|
||||
*
|
||||
*/
|
||||
static RelStatsInfo *
|
||||
getRelationStatistics(Archive *fout, DumpableObject *rel, char relkind)
|
||||
getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages,
|
||||
float reltuples, int32 relallvisible, char relkind)
|
||||
{
|
||||
if (!fout->dopt->dumpStatistics)
|
||||
return NULL;
|
||||
@ -6839,6 +6844,9 @@ getRelationStatistics(Archive *fout, DumpableObject *rel, char relkind)
|
||||
dobj->components |= DUMP_COMPONENT_STATISTICS;
|
||||
dobj->name = pg_strdup(rel->name);
|
||||
dobj->namespace = rel->namespace;
|
||||
info->relpages = relpages;
|
||||
info->reltuples = reltuples;
|
||||
info->relallvisible = relallvisible;
|
||||
info->relkind = relkind;
|
||||
info->postponed_def = false;
|
||||
|
||||
@ -6874,6 +6882,8 @@ getTables(Archive *fout, int *numTables)
|
||||
int i_relhasindex;
|
||||
int i_relhasrules;
|
||||
int i_relpages;
|
||||
int i_reltuples;
|
||||
int i_relallvisible;
|
||||
int i_toastpages;
|
||||
int i_owning_tab;
|
||||
int i_owning_col;
|
||||
@ -6924,7 +6934,7 @@ getTables(Archive *fout, int *numTables)
|
||||
"c.relowner, "
|
||||
"c.relchecks, "
|
||||
"c.relhasindex, c.relhasrules, c.relpages, "
|
||||
"c.relhastriggers, "
|
||||
"c.reltuples, c.relallvisible, c.relhastriggers, "
|
||||
"c.relpersistence, "
|
||||
"c.reloftype, "
|
||||
"c.relacl, "
|
||||
@ -7088,6 +7098,8 @@ getTables(Archive *fout, int *numTables)
|
||||
i_relhasindex = PQfnumber(res, "relhasindex");
|
||||
i_relhasrules = PQfnumber(res, "relhasrules");
|
||||
i_relpages = PQfnumber(res, "relpages");
|
||||
i_reltuples = PQfnumber(res, "reltuples");
|
||||
i_relallvisible = PQfnumber(res, "relallvisible");
|
||||
i_toastpages = PQfnumber(res, "toastpages");
|
||||
i_owning_tab = PQfnumber(res, "owning_tab");
|
||||
i_owning_col = PQfnumber(res, "owning_col");
|
||||
@ -7134,6 +7146,9 @@ getTables(Archive *fout, int *numTables)
|
||||
|
||||
for (i = 0; i < ntups; i++)
|
||||
{
|
||||
float reltuples = strtof(PQgetvalue(res, i, i_reltuples), NULL);
|
||||
int32 relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
|
||||
|
||||
tblinfo[i].dobj.objType = DO_TABLE;
|
||||
tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
|
||||
tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
|
||||
@ -7233,7 +7248,8 @@ getTables(Archive *fout, int *numTables)
|
||||
|
||||
/* Add statistics */
|
||||
if (tblinfo[i].interesting)
|
||||
getRelationStatistics(fout, &tblinfo[i].dobj, tblinfo[i].relkind);
|
||||
getRelationStatistics(fout, &tblinfo[i].dobj, tblinfo[i].relpages,
|
||||
reltuples, relallvisible, tblinfo[i].relkind);
|
||||
|
||||
/*
|
||||
* Read-lock target tables to make sure they aren't DROPPED or altered
|
||||
@ -7499,6 +7515,9 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
|
||||
i_oid,
|
||||
i_indrelid,
|
||||
i_indexname,
|
||||
i_relpages,
|
||||
i_reltuples,
|
||||
i_relallvisible,
|
||||
i_parentidx,
|
||||
i_indexdef,
|
||||
i_indnkeyatts,
|
||||
@ -7552,6 +7571,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
|
||||
appendPQExpBufferStr(query,
|
||||
"SELECT t.tableoid, t.oid, i.indrelid, "
|
||||
"t.relname AS indexname, "
|
||||
"t.relpages, t.reltuples, t.relallvisible, "
|
||||
"pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
|
||||
"i.indkey, i.indisclustered, "
|
||||
"c.contype, c.conname, "
|
||||
@ -7659,6 +7679,9 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
|
||||
i_oid = PQfnumber(res, "oid");
|
||||
i_indrelid = PQfnumber(res, "indrelid");
|
||||
i_indexname = PQfnumber(res, "indexname");
|
||||
i_relpages = PQfnumber(res, "relpages");
|
||||
i_reltuples = PQfnumber(res, "reltuples");
|
||||
i_relallvisible = PQfnumber(res, "relallvisible");
|
||||
i_parentidx = PQfnumber(res, "parentidx");
|
||||
i_indexdef = PQfnumber(res, "indexdef");
|
||||
i_indnkeyatts = PQfnumber(res, "indnkeyatts");
|
||||
@ -7725,6 +7748,9 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
|
||||
char contype;
|
||||
char indexkind;
|
||||
RelStatsInfo *relstats;
|
||||
int32 relpages = atoi(PQgetvalue(res, j, i_relpages));
|
||||
float reltuples = strtof(PQgetvalue(res, j, i_reltuples), NULL);
|
||||
int32 relallvisible = atoi(PQgetvalue(res, j, i_relallvisible));
|
||||
|
||||
indxinfo[j].dobj.objType = DO_INDEX;
|
||||
indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
|
||||
@ -7759,7 +7785,8 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
|
||||
indexkind = RELKIND_PARTITIONED_INDEX;
|
||||
|
||||
contype = *(PQgetvalue(res, j, i_contype));
|
||||
relstats = getRelationStatistics(fout, &indxinfo[j].dobj, indexkind);
|
||||
relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages,
|
||||
reltuples, relallvisible, indexkind);
|
||||
|
||||
if (contype == 'p' || contype == 'u' || contype == 'x')
|
||||
{
|
||||
@ -10383,18 +10410,6 @@ dumpComment(Archive *fout, const char *type,
|
||||
catalogId, subid, dumpId, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tabular description of the parameters to pg_restore_relation_stats()
|
||||
* param_name, param_type
|
||||
*/
|
||||
static const char *rel_stats_arginfo[][2] = {
|
||||
{"relation", "regclass"},
|
||||
{"version", "integer"},
|
||||
{"relpages", "integer"},
|
||||
{"reltuples", "real"},
|
||||
{"relallvisible", "integer"},
|
||||
};
|
||||
|
||||
/*
|
||||
* Tabular description of the parameters to pg_restore_attribute_stats()
|
||||
* param_name, param_type
|
||||
@ -10419,30 +10434,6 @@ static const char *att_stats_arginfo[][2] = {
|
||||
{"range_bounds_histogram", "text"},
|
||||
};
|
||||
|
||||
/*
|
||||
* getRelStatsExportQuery --
|
||||
*
|
||||
* Generate a query that will fetch all relation (e.g. pg_class)
|
||||
* stats for a given relation.
|
||||
*/
|
||||
static void
|
||||
getRelStatsExportQuery(PQExpBuffer query, Archive *fout,
|
||||
const char *schemaname, const char *relname)
|
||||
{
|
||||
resetPQExpBuffer(query);
|
||||
appendPQExpBufferStr(query,
|
||||
"SELECT c.oid::regclass AS relation, "
|
||||
"current_setting('server_version_num') AS version, "
|
||||
"c.relpages, c.reltuples, c.relallvisible "
|
||||
"FROM pg_class c "
|
||||
"JOIN pg_namespace n "
|
||||
"ON n.oid = c.relnamespace "
|
||||
"WHERE n.nspname = ");
|
||||
appendStringLiteralAH(query, schemaname, fout);
|
||||
appendPQExpBufferStr(query, " AND c.relname = ");
|
||||
appendStringLiteralAH(query, relname, fout);
|
||||
}
|
||||
|
||||
/*
|
||||
* getAttStatsExportQuery --
|
||||
*
|
||||
@ -10454,21 +10445,22 @@ getAttStatsExportQuery(PQExpBuffer query, Archive *fout,
|
||||
const char *schemaname, const char *relname)
|
||||
{
|
||||
resetPQExpBuffer(query);
|
||||
appendPQExpBufferStr(query,
|
||||
"SELECT c.oid::regclass AS relation, "
|
||||
"s.attname,"
|
||||
"s.inherited,"
|
||||
"current_setting('server_version_num') AS version, "
|
||||
"s.null_frac,"
|
||||
"s.avg_width,"
|
||||
"s.n_distinct,"
|
||||
"s.most_common_vals,"
|
||||
"s.most_common_freqs,"
|
||||
"s.histogram_bounds,"
|
||||
"s.correlation,"
|
||||
"s.most_common_elems,"
|
||||
"s.most_common_elem_freqs,"
|
||||
"s.elem_count_histogram,");
|
||||
appendPQExpBuffer(query,
|
||||
"SELECT c.oid::regclass AS relation, "
|
||||
"s.attname,"
|
||||
"s.inherited,"
|
||||
"'%u'::integer AS version, "
|
||||
"s.null_frac,"
|
||||
"s.avg_width,"
|
||||
"s.n_distinct,"
|
||||
"s.most_common_vals,"
|
||||
"s.most_common_freqs,"
|
||||
"s.histogram_bounds,"
|
||||
"s.correlation,"
|
||||
"s.most_common_elems,"
|
||||
"s.most_common_elem_freqs,"
|
||||
"s.elem_count_histogram,",
|
||||
fout->remoteVersion);
|
||||
|
||||
if (fout->remoteVersion >= 170000)
|
||||
appendPQExpBufferStr(query,
|
||||
@ -10521,34 +10513,21 @@ appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
|
||||
* Append a formatted pg_restore_relation_stats statement.
|
||||
*/
|
||||
static void
|
||||
appendRelStatsImport(PQExpBuffer out, Archive *fout, PGresult *res)
|
||||
appendRelStatsImport(PQExpBuffer out, Archive *fout, const RelStatsInfo *rsinfo)
|
||||
{
|
||||
const char *sep = "";
|
||||
const char *qualname = fmtQualifiedId(rsinfo->dobj.namespace->dobj.name, rsinfo->dobj.name);
|
||||
char reltuples_str[FLOAT_SHORTEST_DECIMAL_LEN];
|
||||
|
||||
if (PQntuples(res) == 0)
|
||||
return;
|
||||
float_to_shortest_decimal_buf(rsinfo->reltuples, reltuples_str);
|
||||
|
||||
appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
|
||||
|
||||
for (int argno = 0; argno < lengthof(rel_stats_arginfo); argno++)
|
||||
{
|
||||
const char *argname = rel_stats_arginfo[argno][0];
|
||||
const char *argtype = rel_stats_arginfo[argno][1];
|
||||
int fieldno = PQfnumber(res, argname);
|
||||
|
||||
if (fieldno < 0)
|
||||
pg_fatal("relation stats export query missing field '%s'",
|
||||
argname);
|
||||
|
||||
if (PQgetisnull(res, 0, fieldno))
|
||||
continue;
|
||||
|
||||
appendPQExpBufferStr(out, sep);
|
||||
appendNamedArgument(out, fout, argname, PQgetvalue(res, 0, fieldno), argtype);
|
||||
|
||||
sep = ",\n";
|
||||
}
|
||||
appendPQExpBufferStr(out, "\n);\n");
|
||||
appendPQExpBuffer(out, "\t'relation', '%s'::regclass,\n", qualname);
|
||||
appendPQExpBuffer(out, "\t'version', '%u'::integer,\n",
|
||||
fout->remoteVersion);
|
||||
appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages);
|
||||
appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", reltuples_str);
|
||||
appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer\n);\n",
|
||||
rsinfo->relallvisible);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -10643,15 +10622,11 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
|
||||
tag = createPQExpBuffer();
|
||||
appendPQExpBufferStr(tag, fmtId(dobj->name));
|
||||
|
||||
query = createPQExpBuffer();
|
||||
out = createPQExpBuffer();
|
||||
|
||||
getRelStatsExportQuery(query, fout, dobj->namespace->dobj.name,
|
||||
dobj->name);
|
||||
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
|
||||
appendRelStatsImport(out, fout, res);
|
||||
PQclear(res);
|
||||
appendRelStatsImport(out, fout, rsinfo);
|
||||
|
||||
query = createPQExpBuffer();
|
||||
getAttStatsExportQuery(query, fout, dobj->namespace->dobj.name,
|
||||
dobj->name);
|
||||
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
|
||||
|
@ -328,7 +328,7 @@ typedef struct _tableInfo
|
||||
Oid owning_tab; /* OID of table owning sequence */
|
||||
int owning_col; /* attr # of column owning sequence */
|
||||
bool is_identity_sequence;
|
||||
int relpages; /* table's size in pages (from pg_class) */
|
||||
int32 relpages; /* table's size in pages (from pg_class) */
|
||||
int toastpages; /* toast table's size in pages, if any */
|
||||
|
||||
bool interesting; /* true if need to collect more data */
|
||||
@ -438,6 +438,9 @@ typedef struct _indexAttachInfo
|
||||
typedef struct _relStatsInfo
|
||||
{
|
||||
DumpableObject dobj;
|
||||
int32 relpages;
|
||||
float reltuples;
|
||||
int32 relallvisible;
|
||||
char relkind; /* 'r', 'm', 'i', etc */
|
||||
bool postponed_def; /* stats must be postponed into post-data */
|
||||
} RelStatsInfo;
|
||||
|
Reference in New Issue
Block a user