diff options
author | Jeff Davis <jdavis@postgresql.org> | 2025-02-25 19:50:50 -0800 |
---|---|---|
committer | Jeff Davis <jdavis@postgresql.org> | 2025-02-25 19:52:11 -0800 |
commit | 6ee3b91bad269b8f1acee38607bd17923efd6e06 (patch) | |
tree | 8217ff1be54a98dd281e695340e692e990dfa418 | |
parent | 8f427187db78a549af316a69d54f5969db5f4951 (diff) | |
download | postgresql-6ee3b91bad269b8f1acee38607bd17923efd6e06.tar.gz postgresql-6ee3b91bad269b8f1acee38607bd17923efd6e06.zip |
pg_dump: prepare attribute stats query.
Follow precedent in pg_dump for preparing queries to improve
performance. Also, simplify the query by removing unnecessary joins.
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=dRMC6t8gp9GVf6y6E_r5EChQjMAAh_vPyih_zMiq0zvA@mail.gmail.com
-rw-r--r-- | src/bin/pg_dump/pg_backup.h | 1 | ||||
-rw-r--r-- | src/bin/pg_dump/pg_dump.c | 123 |
2 files changed, 58 insertions, 66 deletions
diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h index 350cf659c41..e783cc68d89 100644 --- a/src/bin/pg_dump/pg_backup.h +++ b/src/bin/pg_dump/pg_backup.h @@ -72,6 +72,7 @@ enum _dumpPreparedQueries PREPQUERY_DUMPOPR, PREPQUERY_DUMPRANGETYPE, PREPQUERY_DUMPTABLEATTACH, + PREPQUERY_GETATTRIBUTESTATS, PREPQUERY_GETCOLUMNACLS, PREPQUERY_GETDOMAINCONSTRAINTS, }; diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index a1823914656..0de6c959bb0 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -10415,10 +10415,8 @@ dumpComment(Archive *fout, const char *type, * param_name, param_type */ static const char *att_stats_arginfo[][2] = { - {"relation", "regclass"}, {"attname", "name"}, {"inherited", "boolean"}, - {"version", "integer"}, {"null_frac", "float4"}, {"avg_width", "integer"}, {"n_distinct", "float4"}, @@ -10435,60 +10433,6 @@ static const char *att_stats_arginfo[][2] = { }; /* - * getAttStatsExportQuery -- - * - * Generate a query that will fetch all attribute (e.g. pg_statistic) - * stats for a given relation. - */ -static void -getAttStatsExportQuery(PQExpBuffer query, Archive *fout, - const char *schemaname, const char *relname) -{ - resetPQExpBuffer(query); - 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, - "s.range_length_histogram," - "s.range_empty_frac," - "s.range_bounds_histogram "); - else - appendPQExpBufferStr(query, - "NULL AS range_length_histogram," - "NULL AS range_empty_frac," - "NULL AS range_bounds_histogram "); - - appendPQExpBufferStr(query, - "FROM pg_stats s " - "JOIN pg_namespace n " - "ON n.nspname = s.schemaname " - "JOIN pg_class c " - "ON c.relname = s.tablename " - "AND c.relnamespace = n.oid " - "WHERE s.schemaname = "); - appendStringLiteralAH(query, schemaname, fout); - appendPQExpBufferStr(query, " AND s.tablename = "); - appendStringLiteralAH(query, relname, fout); - appendPQExpBufferStr(query, " ORDER BY s.attname, s.inherited"); -} - - -/* * appendNamedArgument -- * * Convenience routine for constructing parameters of the form: @@ -10513,17 +10457,17 @@ appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname, * Append a formatted pg_restore_relation_stats statement. */ static void -appendRelStatsImport(PQExpBuffer out, Archive *fout, const RelStatsInfo *rsinfo) +appendRelStatsImport(PQExpBuffer out, Archive *fout, const RelStatsInfo *rsinfo, + const char *qualified_name) { - const char *qualname = fmtQualifiedId(rsinfo->dobj.namespace->dobj.name, rsinfo->dobj.name); char reltuples_str[FLOAT_SHORTEST_DECIMAL_LEN]; float_to_shortest_decimal_buf(rsinfo->reltuples, reltuples_str); appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n"); - appendPQExpBuffer(out, "\t'relation', '%s'::regclass,\n", qualname); appendPQExpBuffer(out, "\t'version', '%u'::integer,\n", fout->remoteVersion); + appendPQExpBuffer(out, "\t'relation', '%s'::regclass,\n", qualified_name); 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", @@ -10536,13 +10480,18 @@ appendRelStatsImport(PQExpBuffer out, Archive *fout, const RelStatsInfo *rsinfo) * Append a series of formatted pg_restore_attribute_stats statements. */ static void -appendAttStatsImport(PQExpBuffer out, Archive *fout, PGresult *res) +appendAttStatsImport(PQExpBuffer out, Archive *fout, PGresult *res, + const char *qualified_name) { for (int rownum = 0; rownum < PQntuples(res); rownum++) { const char *sep = ""; appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n"); + appendPQExpBuffer(out, "\t'version', '%u'::integer,\n", + fout->remoteVersion); + appendPQExpBuffer(out, "\t'relation', '%s'::regclass,\n", + qualified_name); for (int argno = 0; argno < lengthof(att_stats_arginfo); argno++) { const char *argname = att_stats_arginfo[argno][0]; @@ -10607,6 +10556,7 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo) DumpableObject *dobj = (DumpableObject *) &rsinfo->dobj; DumpId *deps = NULL; int ndeps = 0; + const char *qualified_name; /* nothing to do if we are not dumping statistics */ if (!fout->dopt->dumpStatistics) @@ -10622,15 +10572,56 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo) tag = createPQExpBuffer(); appendPQExpBufferStr(tag, fmtId(dobj->name)); - out = createPQExpBuffer(); + query = createPQExpBuffer(); + if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS]) + { + appendPQExpBufferStr(query, + "PREPARE getAttributeStats(pg_catalog.name, pg_catalog.name) AS\n" + "SELECT s.attname, s.inherited, " + "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, "); + + if (fout->remoteVersion >= 170000) + appendPQExpBufferStr(query, + "s.range_length_histogram, s.range_empty_frac, " + "s.range_bounds_histogram "); + else + appendPQExpBufferStr(query, + "NULL AS range_length_histogram," + "NULL AS range_empty_frac," + "NULL AS range_bounds_histogram "); - appendRelStatsImport(out, fout, rsinfo); + appendPQExpBufferStr(query, + "FROM pg_stats s " + "WHERE s.schemaname = $1 " + "AND s.tablename = $2 " + "ORDER BY s.attname, s.inherited"); + + ExecuteSqlStatement(fout, query->data); + + fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS] = true; + resetPQExpBuffer(query); + } + + appendPQExpBufferStr(query, "EXECUTE getAttributeStats("); + appendStringLiteralAH(query, dobj->namespace->dobj.name, fout); + appendPQExpBufferStr(query, ", "); + appendStringLiteralAH(query, dobj->name, fout); + appendPQExpBufferStr(query, "); "); - query = createPQExpBuffer(); - getAttStatsExportQuery(query, fout, dobj->namespace->dobj.name, - dobj->name); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); - appendAttStatsImport(out, fout, res); + + out = createPQExpBuffer(); + + qualified_name = fmtQualifiedId(rsinfo->dobj.namespace->dobj.name, + rsinfo->dobj.name); + + appendRelStatsImport(out, fout, rsinfo, qualified_name); + appendAttStatsImport(out, fout, res, qualified_name); + PQclear(res); ArchiveEntry(fout, nilCatalogId, createDumpId(), |