July 17, 2025·4 min read·engineeringpostgresqlupgradesquery-planning

PostgreSQL 18 Beta 2 makes statistics transfer an explicit dump choice

Beta 2 changes dump defaults while retaining statistics restoration by default. The distinction affects how an upgrade rehearsal supplies the planner with information about the data.

An upgrade can preserve every row and still change how the planner understands those rows. PostgreSQL 18's statistics-transfer work addresses that gap, and Beta 2 adjusts which tools include statistics by default. This is a useful detail in the July 17 beta announcement, because it affects what an application rehearsal actually measures after data moves.

The announcement changes pg_dump and pg_dumpall to default to --no-statistics. pg_restore and pg_upgrade continue to default to restoring statistics. The tools have complementary responsibilities, so their defaults need not be identical. An archive creator decides what information the archive contains, while its consumer decides which available information to apply.

I value PostgreSQL's explainability, particularly the ability to compare planner estimates with the chosen execution plan. Statistics transfer is interesting because it preserves some of the information behind those estimates. It can make an upgrade's starting conditions less dependent on when analysis happens after the new server starts.

Statistics describe the data approximately

The existing planner-statistics documentation explains that the planner estimates how many rows a condition will return. Table-size information and column statistics support those estimates. ANALYZE updates column statistics, which remain approximate even when newly collected.

The same reference distinguishes statistics for individual columns from extended statistics covering relationships between columns. Independent column estimates cannot fully represent correlated values. Explicit statistics objects tell PostgreSQL which combinations warrant additional information, and ANALYZE collects it.

This makes a post-upgrade execution plan partly dependent on the available statistical information. Identical rows do not establish identical estimates if one environment has useful statistics and another lacks them. A migration comparison needs to identify that difference before assigning every plan change to new optimizer behavior.

The dump must opt in before the restore can use statistics

The pg_dump documentation at the Beta 2 tag describes --with-statistics as an explicit inclusion option. Without it, the new default excludes statistics. The resulting archive can still contain schema and data, so a successful dump does not establish that it contains planner information.

An illustrative export can request statistics explicitly. This command uses Beta 2's pg_dump and writes a custom-format archive for the named database:

pg_dump --format=custom --with-statistics \
  --file=app-with-statistics.dump app

The versioned documentation says this includes most optimizer statistics. It explicitly excludes some information, such as statistics created through CREATE STATISTICS and custom statistics supplied by an extension. Opting in therefore does not produce a complete copy of every statistical object or every extension-defined measurement.

That limitation matters when interpreting a rehearsal. A table whose important plans depend on extended statistics may still need analysis after restoration. The new option reduces the amount of missing information without changing the documented scope of what the dump can transfer.

Restore defaults cannot supply information absent from an archive

The Beta 2 pg_restore reference says statistics are restored by default if the archive contains them. --no-statistics suppresses the restoration commands even when statistical information is present. These are choices at consumption time, separate from the dump's inclusion choice.

The ordinary restoration command can consequently use the archive's included statistics. In this example, the destination database already exists and receives the contents of the named archive:

pg_restore --dbname=app_restore app-with-statistics.dump

An operator can reuse the same archive while choosing whether to restore its statistics. That is useful for a controlled comparison of startup conditions, provided the comparison records the choice. A default-enabled restore cannot recover statistics that the archive creator omitted.

pg_upgrade transfers a documented subset

The Beta 2 pg_upgrade reference transfers most optimizer statistics unless --no-statistics is specified. It repeats the limitations around extended and extension-provided statistics. It also says the upgrade will give instructions for regenerating information that was not transferred.

This is a different starting point from dumping data with the default options and then restoring it. Both are legitimate migration routes, but the statistical state of the destination can differ. A comparison that records only the source and destination server versions would omit a material input to query planning.

I find this a useful improvement for upgrade preparation because the scope is explicit. Preserving a subset gives the planner information immediately, while the remaining analysis work is still identified. It does not justify treating every post-upgrade estimate as equivalent to the source cluster's estimate.

Beta 2 remains a prerelease for application testing. The announcement asks users to run representative workloads outside production and notes that behavior and interfaces can still change. For this part of the release, the concrete question is whether the chosen migration route produces the statistical starting conditions intended for that workload. The dump options, archive contents and restoration choices now describe those conditions separately.