mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 10:30:33 +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