Cache the results of format_type() queries in pg_dump.

There's long been a "TODO: there might be some value in caching
the results" annotation on pg_dump's getFormattedTypeName function;
but we hadn't gotten around to checking what it was costing us to
repetitively look up type names.  It turns out that when dumping the
current regression database, about 10% of the total number of queries
issued are duplicative format_type() queries.  However, Hubert Depesz
Lubaczewski reported a not-unusual case where these account for over
half of the queries issued by pg_dump.  Individually these queries
aren't expensive, but when network lag is a factor, they add up to a
problem.  We can very easily add some caching to getFormattedTypeName
to solve it.

Since this is such a simple fix and can have a visible performance
benefit, back-patch to all supported branches.

Discussion: https://postgr.es/m/20210826084430.GA26282@depesz.com
This commit is contained in:
Tom Lane 2021-08-31 13:53:33 -04:00
parent 5f8dd5dc17
commit 2f1ed9d98c
2 changed files with 15 additions and 4 deletions

View File

@ -4981,6 +4981,7 @@ getTypes(Archive *fout, int *numTypes)
tyinfo[i].dobj.namespace =
findNamespace(fout,
atooid(PQgetvalue(res, i, i_typnamespace)));
tyinfo[i].ftypname = NULL; /* may get filled later */
tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
@ -18611,12 +18612,11 @@ findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
*
* This does not guarantee to schema-qualify the output, so it should not
* be used to create the target object name for CREATE or ALTER commands.
*
* TODO: there might be some value in caching the results.
*/
static char *
getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
{
TypeInfo *typeInfo;
char *result;
PQExpBuffer query;
PGresult *res;
@ -18633,6 +18633,11 @@ getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
return pg_strdup("NONE");
}
/* see if we have the result cached in the type's TypeInfo record */
typeInfo = findTypeByOid(oid);
if (typeInfo && typeInfo->ftypname)
return pg_strdup(typeInfo->ftypname);
query = createPQExpBuffer();
appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
oid);
@ -18645,6 +18650,10 @@ getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
PQclear(res);
destroyPQExpBuffer(query);
/* cache a copy for later requests */
if (typeInfo)
typeInfo->ftypname = pg_strdup(result);
return result;
}

View File

@ -167,9 +167,11 @@ typedef struct _typeInfo
DumpableObject dobj;
/*
* Note: dobj.name is the pg_type.typname entry. format_type() might
* produce something different than typname
* Note: dobj.name is the raw pg_type.typname entry. ftypname is the
* result of format_type(), which will be quoted if needed, and might be
* schema-qualified too.
*/
char *ftypname;
char *rolname; /* name of owner, or empty string */
char *typacl;
char *rtypacl;