diff --git a/src/bin/pg_upgrade/info.c b/src/bin/pg_upgrade/info.c
index c1399c09b9..5c47e4463c 100644
--- a/src/bin/pg_upgrade/info.c
+++ b/src/bin/pg_upgrade/info.c
@@ -11,6 +11,8 @@
 
 #include "access/transam.h"
 #include "catalog/pg_class_d.h"
+#include "common/hashfn.h"
+#include "common/logging.h"
 #include "pg_upgrade.h"
 
 static void create_rel_filename_map(const char *old_data, const char *new_data,
@@ -26,6 +28,28 @@ static void free_rel_infos(RelInfoArr *rel_arr);
 static void print_db_infos(DbInfoArr *db_arr);
 static void print_rel_infos(RelInfoArr *rel_arr);
 
+static uint32 hash_string_pointer(const char *s);
+#define SH_PREFIX		spacehash
+#define SH_ELEMENT_TYPE	space_entry_t
+#define SH_KEY_TYPE		const char *
+#define SH_KEY			name
+#define SH_HASH_KEY(tb, key)	hash_string_pointer(key)
+#define SH_EQUAL(tb, a, b)		(strcmp(a, b) == 0)
+#define SH_SCOPE		extern
+#define SH_RAW_ALLOCATOR	pg_malloc0
+#define SH_DEFINE
+#include "lib/simplehash.h"
+
+/*
+ * Helper function for spacehash hash table.
+ */
+static uint32
+hash_string_pointer(const char *s)
+{
+	unsigned char *ss = (unsigned char *) s;
+
+	return hash_bytes(ss, strlen(s));
+}
 
 /*
  * gen_db_file_maps()
@@ -402,11 +426,13 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
 				i_relfilenumber,
 				i_reltablespace;
 	char		query[QUERY_ALLOC];
-	char	   *last_namespace = NULL,
-			   *last_tablespace = NULL;
 
 	query[0] = '\0';			/* initialize query string to empty */
 
+	/* TODO: What is a good initial size? */
+	dbinfo->db_namespaces = spacehash_create(16, NULL);
+	dbinfo->db_tablespaces = spacehash_create(16, NULL);
+
 	/*
 	 * Create a CTE that collects OIDs of regular user tables and matviews,
 	 * but excluding toast tables and indexes.  We assume that relations with
@@ -501,33 +527,29 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
 	for (relnum = 0; relnum < ntups; relnum++)
 	{
 		RelInfo    *curr = &relinfos[num_rels++];
+		bool 		found;
+		space_entry_t *sp;
 
 		curr->reloid = atooid(PQgetvalue(res, relnum, i_reloid));
 		curr->indtable = atooid(PQgetvalue(res, relnum, i_indtable));
 		curr->toastheap = atooid(PQgetvalue(res, relnum, i_toastheap));
 
 		nspname = PQgetvalue(res, relnum, i_nspname);
-		curr->nsp_alloc = false;
 
 		/*
 		 * Many of the namespace and tablespace strings are identical, so we
-		 * try to reuse the allocated string pointers where possible to reduce
-		 * memory consumption.
+		 * try to minimize allocated space by storing the names in a hash-
+		 * table from which they can be referenced.
 		 */
-		/* Can we reuse the previous string allocation? */
-		if (last_namespace && strcmp(nspname, last_namespace) == 0)
-			curr->nspname = last_namespace;
-		else
-		{
-			last_namespace = curr->nspname = pg_strdup(nspname);
-			curr->nsp_alloc = true;
-		}
+		sp = spacehash_insert(dbinfo->db_namespaces, nspname, &found);
+		if (!found)
+			sp->name = pstrdup(nspname);
+		curr->nspname = sp->name;
 
 		relname = PQgetvalue(res, relnum, i_relname);
 		curr->relname = pg_strdup(relname);
 
 		curr->relfilenumber = atooid(PQgetvalue(res, relnum, i_relfilenumber));
-		curr->tblsp_alloc = false;
 
 		/* Is the tablespace oid non-default? */
 		if (atooid(PQgetvalue(res, relnum, i_reltablespace)) != 0)
@@ -538,14 +560,10 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
 			 */
 			tablespace = PQgetvalue(res, relnum, i_spclocation);
 
-			/* Can we reuse the previous string allocation? */
-			if (last_tablespace && strcmp(tablespace, last_tablespace) == 0)
-				curr->tablespace = last_tablespace;
-			else
-			{
-				last_tablespace = curr->tablespace = pg_strdup(tablespace);
-				curr->tblsp_alloc = true;
-			}
+			sp = spacehash_insert(dbinfo->db_tablespaces, tablespace, &found);
+			if (!found)
+				sp->name = pstrdup(tablespace);
+			curr->tablespace = sp->name;
 		}
 		else
 			/* A zero reltablespace oid indicates the database tablespace. */
@@ -569,6 +587,9 @@ free_db_and_rel_infos(DbInfoArr *db_arr)
 	{
 		free_rel_infos(&db_arr->dbs[dbnum].rel_arr);
 		pg_free(db_arr->dbs[dbnum].db_name);
+
+		spacehash_destroy(db_arr->dbs[dbnum].db_namespaces);
+		spacehash_destroy(db_arr->dbs[dbnum].db_tablespaces);
 	}
 	pg_free(db_arr->dbs);
 	db_arr->dbs = NULL;
@@ -582,13 +603,7 @@ free_rel_infos(RelInfoArr *rel_arr)
 	int			relnum;
 
 	for (relnum = 0; relnum < rel_arr->nrels; relnum++)
-	{
-		if (rel_arr->rels[relnum].nsp_alloc)
-			pg_free(rel_arr->rels[relnum].nspname);
 		pg_free(rel_arr->rels[relnum].relname);
-		if (rel_arr->rels[relnum].tblsp_alloc)
-			pg_free(rel_arr->rels[relnum].tablespace);
-	}
 	pg_free(rel_arr->rels);
 	rel_arr->nrels = 0;
 }
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index 5f2a116f23..239c5c468a 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -133,15 +133,13 @@ extern char *output_files[];
 typedef struct
 {
 	/* Can't use NAMEDATALEN; not guaranteed to be same on client */
-	char	   *nspname;		/* namespace name */
+	const char *nspname;		/* namespace name */
 	char	   *relname;		/* relation name */
 	Oid			reloid;			/* relation OID */
 	RelFileNumber relfilenumber;	/* relation file number */
 	Oid			indtable;		/* if index, OID of its table, else 0 */
 	Oid			toastheap;		/* if toast table, OID of base table, else 0 */
-	char	   *tablespace;		/* tablespace path; "" for cluster default */
-	bool		nsp_alloc;		/* should nspname be freed? */
-	bool		tblsp_alloc;	/* should tablespace be freed? */
+	const char *tablespace;		/* tablespace path; "" for cluster default */
 } RelInfo;
 
 typedef struct
@@ -162,10 +160,29 @@ typedef struct
 	Oid			db_oid;
 	RelFileNumber relfilenumber;
 	/* the rest are used only for logging and error reporting */
-	char	   *nspname;		/* namespaces */
+	const char *nspname;		/* namespaces */
 	char	   *relname;
 } FileNameMap;
 
+/*
+ * space_entry_t
+ *
+ * Hash table entries for recording namespace and tablespace names.
+ */
+typedef struct space_entry_t
+{
+	uint32		status;			/* hash status */
+	const char *name;
+} space_entry_t;
+
+#define SH_PREFIX		spacehash
+#define SH_ELEMENT_TYPE	space_entry_t
+#define SH_KEY_TYPE		const char *
+#define SH_SCOPE		extern
+#define SH_RAW_ALLOCATOR	pg_malloc0
+#define SH_DECLARE
+#include "lib/simplehash.h"
+
 /*
  * Structure to store database information
  */
@@ -181,6 +198,8 @@ typedef struct
 	char	   *db_iculocale;
 	int			db_encoding;
 	RelInfoArr	rel_arr;		/* array of all user relinfos */
+	spacehash_hash  *db_namespaces;		/* hash of namespaces */
+	spacehash_hash  *db_tablespaces;	/* hash of tablespaces */
 } DbInfo;
 
 typedef struct
