Subject: [PATCH] Doc: clarify that pg_upgrade statistics transfer works cross-version

From: [email-masked]
Date: Mon, 23 Mar 2026 22:30:57 -0500

Hi hackers,

I initially assumed that PG18's statistics transfer during pg_upgrade
would only work when upgrading from PG18 to a future version. I hear
this misconception from others fairly often too.

In reality, it works when upgrading *to* PG18 from any older supported
version (PG14, 15, 16, 17), because pg_upgrade uses the new cluster's
pg_dump, which reads from standard catalog views (pg_class and
pg_stats) that exist in all PostgreSQL versions. The pg_dump docs
already note that "pg_dump can also dump from PostgreSQL servers older
than its own version" — so no changes needed there. The confusion
seems specific to the major upgrade context.

The attached patch adds a brief clarification to pgupgrade.sgml to address this.

I tested pg_dump --statistics-only from PG18 against PG16 and PG14 —
both work as expected, stats are transferred and restored correctly.

--
Nik
From 339ce77cac927e463324276a6691962c1de852d6 Mon Sep 17 00:00:00 2001
From: Nikolay Samokhvalov <[email-masked]>
Date: Tue, 24 Mar 2026 03:26:24 +0000
Subject: [PATCH] Doc: clarify that pg_upgrade statistics transfer works
 cross-version.

Clarify in pgupgrade.sgml that optimizer statistics transfer works
regardless of the old cluster's major version.  The new cluster's
pg_dump reads statistics from standard catalog views (pg_class and
pg_stats) in the old cluster, which exist in all supported PostgreSQL
versions.  The restore functions (pg_restore_relation_stats and
pg_restore_attribute_stats) only need to exist on the target cluster.

Tested with PG14->PG18 and PG16->PG18.
---
 doc/src/sgml/ref/pgupgrade.sgml | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml
index 38ca09b..d552907 100644
--- a/doc/src/sgml/ref/pgupgrade.sgml
+++ b/doc/src/sgml/ref/pgupgrade.sgml
@@ -833,10 +833,15 @@ psql --username=postgres --file=script.sql postgres
     <para>
      Unless the <option>--no-statistics</option> option is specified,
      <command>pg_upgrade</command> will transfer most optimizer statistics
-     from the old cluster to the new cluster.  This does not transfer
-     all statistics, such as those created explicitly with
-     <xref linkend="sql-createstatistics"/>, custom statistics added by
-     an extension, or statistics collected by the cumulative statistics system.
+     from the old cluster to the new cluster.  This works regardless of
+     the old cluster's major version, because the new cluster's
+     <command>pg_dump</command> reads statistics from standard catalog views
+     (<structname>pg_class</structname> and <structname>pg_stats</structname>)
+     that exist in all supported <productname>PostgreSQL</productname>
+     versions.  However, some statistics are not transferred: those created
+     with <xref linkend="sql-createstatistics"/>, custom statistics added by
+     an extension, and statistics collected by the cumulative statistics
+     system.
     </para>
 
     <para>
-- 
2.43.0

---

From: Laurenz Albe <[email-masked]>
Date: Tue, 24 Mar 2026 07:59:10 +0100

> both work as expected, stats are transferred and restored correctly.

I agree that it would be a good idea to explicitly mention that
statistics are transferred when upgrading from older PostgreSQL
versions.  However, I think that your patch offers too much detail,
like from which relations the statistics are extracted.  Anybody
who wants to know that level of detail probably has to read the
source code anyway.

How about adding a simple remark, like

--- a/doc/src/sgml/ref/pgupgrade.sgml
+++ b/doc/src/sgml/ref/pgupgrade.sgml
@@ -837,6 +837,8 @@ psql --username=postgres --file=script.sql postgres
      all statistics, such as those created explicitly with
      <xref linkend="sql-createstatistics"/>, custom statistics added by
      an extension, or statistics collected by the cumulative statistics system.
+     Transferring optimizer statistics works regardless of the old cluster's
+     major version.
     </para>
 
     <para>

Yours,
Laurenz Albe

---

From: Nikolay Samokhvalov <[email-masked]>
Date: Tue, 24 Mar 2026 05:36:42 -0700

On Mon, Mar 23, 2026 at 23:59 Laurenz Albe <[email-masked]> wrote:
...

> I think that your patch offers too much detail,

That would work too -- my goal was just to resolve confusion.

Nik

---

From: Bruce Momjian <[email-masked]>
Date: Tue, 24 Mar 2026 11:04:38 -0400

> That would work too -- my goal was just to resolve confusion.

I was under the same impression --- that it only worked with upgrades
_from_ PG 18 and later.  However, I can't find any documentation on this
limitation, so why did so many think this was true?  I don't think
adding anything to the docs is the right approach.

-- 
  Bruce Momjian  <[email-masked]>        https://momjian.us
  EDB                                      https://enterprisedb.com

  Do not let urgent matters crowd out time for investment in the future.

---

From: Laurenz Albe <[email-masked]>
Date: Tue, 24 Mar 2026 17:53:27 +0100

> adding anything to the docs is the right approach.

Bruce, you are confusing me.  Your first sentence suggests that you
(erroneously) thought that upgrading statistics only works when upgrading
*from* v18 or better.  But your last sentence suggests that you'd rather
not add anything to the documentation that could dispel that misconception.

Why?

Yours,
Laurenz Albe

---

From: Bruce Momjian <[email-masked]>
Date: Tue, 24 Mar 2026 14:11:54 -0400

> (erroneously) thought that upgrading statistics only works when upgrading

Right.

> not add anything to the documentation that could dispel that misconception.

So, we don't normally document cases where a limitation does not exist. 
I think the logical place to document this is in the PG 18 release
notes.  I am still confused why people, like myself, got this wrong. 
What is the source of the confusion?  Just unclear release notes?

---

From: Laurenz Albe <[email-masked]>
Date: Wed, 25 Mar 2026 07:03:01 +0100

> What is the source of the confusion?  Just unclear release notes?

I understand now, thanks.  I agree with you in principle, but I wouldn't
see that as a hard rule that should stand in the way of clarity.

Let me quote a precedent from https://www.postgresql.org/docs/current/upgrading.html

  Minor releases never change the internal storage format and are always
  compatible with earlier and later minor releases of the same major
  version number. For example, version 10.1 is compatible with version 10.0
  and version 10.6.

To me, that clarifies that there is no limitation to performing minor
updates with a simple restart.  I think that is useful information.

Perhaps you'd feel better if we phrase it as a limitation:

  Transferring optimizer statistics only work when upgrading to PostgreSQL
  version v18 or later, but there is no such limitation to the version of
  the old cluster.

I like my original suggestion better, though.

Yours,
Laurenz Albe

---

From: Bruce Momjian <[email-masked]>
Date: Wed, 25 Mar 2026 12:21:00 -0400

Right.

> I like my original suggestion better, though.

Uh, we added the feature in PG 18, so why would we say it only works in
PG 18 --- that is kind of obvious.  I am still asking, why did people,
like me, think it only worked for _old_ PG 18 servers.  If we find where
that was communicated, we can clarify it _there_.

---

From: Nikolay Samokhvalov <[email-masked]>
Date: Wed, 25 Mar 2026 18:13:23 -0700

two cents:

> > > So, we don't normally document cases where a limitation does not exist.

I see it rather as an undocumented feature, not an undocumented
"limitation that doesn't exist".

> that was communicated, we can clarify it _there_.

If you don't know anything about implementation, it is natural to
expect that something new will work only when both old and new
clusters support it. That's why I started with words that I see
everyone (includfing both of us) were originally confused. I bumped
into it in some blog posts and LinkedIn discussions after which
decided to clarify [1] since I couldn't find clarification anywhere on
surface – only in source code, diving into implementation, and the
depth of discussions [2] [3] [4].

It would be great to get it covered in the 2nd (after source code)
source of truth-- the docs.

[1] https://postgres.ai/blog/20260324-pg18-stats-upgrade-across-versions
[2] https://www.postgresql.org/message-id/flat/aC5F1LX6-uL0wRV1%40nathan#f71f3dcd5fd88ee970f0b1ea0a779298
[3] https://www.postgresql.org/message-id/flat/1322262.1741643606%40sss.pgh.pa.us#d666e5e99bbd955a4f258338b44389da
[4] https://www.postgresql.org/message-id/flat/Z_BcWVMvlUIJ_iuZ%40nathan#1f6ae665591cb5e5371552761aa90615

---

From: "David G. Johnston" <[email-masked]>
Date: Wed, 25 Mar 2026 19:33:42 -0700

On Wednesday, March 25, 2026, Nikolay Samokhvalov <[email-masked]> wrote:

> clusters support it.
But we don’t call out “new features” in the documentation.  Just
“features”.  And so when the pg_upgrade docs says “pg_upgrade supports
upgrades from 9.2.X and later” then unless there is a note to the contrary
(which there is not here) that applies to everything pg_upgrade does.

Put differently, read the docs as if you were unaware in which version that
capability was introduced.  This is the style/assumption the documentation
is written in/using.

David J.