PostgreSQL 18 VACUUM and ANALYZE Inheritance Change: What to Check
PostgreSQL 18 changes VACUUM and ANALYZE behavior for inherited parent tables. Learn how to audit maintenance scripts before a managed database upgrade.
ArmorDB Engineering
ArmorDB engineering
On this page 7 sections
PostgreSQL 18 includes a small-looking maintenance change that can surprise teams with inheritance trees or older partition-style schemas: VACUUM and ANALYZE now process inheritance children when they are run on a parent relation. To keep the previous parent-only behavior, the release notes point to the new ONLY option.
The problem is not that the new behavior is bad. It is usually closer to what operators expect when they say they are maintaining a logical table. The risk is that maintenance scripts written for earlier PostgreSQL versions may do more work after an upgrade than they did before. In managed PostgreSQL, where autovacuum, provider defaults, and application-owned jobs all meet in production, that difference belongs in the upgrade runbook.
What changed in PostgreSQL 18
The official PostgreSQL 18 release notes say that VACUUM and ANALYZE now process the inheritance children of a parent, and that the previous behavior can be requested with the ONLY option. The change matters most for schemas that use table inheritance directly, older partitioning patterns, or maintenance jobs that target parent tables as convenient names for a larger logical dataset.
PostgreSQL table inheritance lets a child table inherit columns from a parent and participate in queries against the parent unless ONLY is used. Declarative partitioning is the modern path for most partitioned workloads, but many production databases still contain inheritance-based designs, historical migrations, or extension-managed table layouts. A major upgrade is exactly when those older assumptions become visible again.
| Maintenance command | PostgreSQL 17-era assumption to check | PostgreSQL 18 behavior to plan for | Practical action |
|---|---|---|---|
VACUUM parent_table | May have been treated as parent-only in scripts | Processes inheritance children unless ONLY is used | Estimate table count, dead tuples, and runtime before the window |
ANALYZE parent_table | Stats refresh may have covered less data than the name implied | Refresh can include child relations | Watch planning changes for inherited or partition-like queries |
VACUUM ONLY parent_table | Not always present in legacy scripts | Requests the old parent-only scope | Use when the job truly must skip children |
| Autovacuum | Provider and server settings may already maintain children independently | Manual jobs can now overlap more naturally with logical table scope | Avoid stacking broad manual maintenance on top of busy autovacuum periods |
| Upgrade rehearsal | Empty staging may hide scope changes | Production-shaped child tables expose runtime and lock behavior | Test against a restored database, not only a fresh schema |
Why this matters for managed databases
Managed PostgreSQL does not remove the need to understand maintenance scope. The provider may configure autovacuum, expose logs, protect backups, and make upgrades easier to schedule. The application team still owns custom maintenance scripts, data-retention jobs, migration tasks, and the queries whose plans depend on current statistics.
The operational surprise usually appears as time, not syntax. A nightly VACUUM parent_table that used to finish quickly may now touch many child tables. An ANALYZE that used to refresh a narrow parent relation may now update statistics for a wider dataset, which can improve plans but also change them. Those are manageable outcomes if they are expected. They are poor surprises if they happen during a deploy window that also includes schema changes, backfills, or a traffic spike.
For teams using ArmorDB or another managed platform, treat this as a script-audit item before a PostgreSQL 18 upgrade. Look for scheduled SQL, migration framework hooks, and runbook commands that mention parent tables. If the intent is logical maintenance across the whole hierarchy, the PostgreSQL 18 default may be helpful. If the intent is a metadata-only parent operation or a carefully scoped emergency command, write ONLY explicitly so the command documents its boundary.
A practical pre-upgrade audit
Start by finding inheritance and partition-like structures. In many applications, the obvious partitioned tables are known by name, but old inheritance hierarchies can hide in audit logs, time-series tables, multi-tenant tables, or extension-managed schemas. A staging query against pg_inherits can show which parent relations have children:
SELECT
parent.relname AS parent_table,
child.relname AS child_table
FROM pg_inherits
JOIN pg_class parent ON parent.oid = pg_inherits.inhparent
JOIN pg_class child ON child.oid = pg_inherits.inhrelid
ORDER BY parent.relname, child.relname;
Next, search deployment jobs for direct VACUUM and ANALYZE calls. Do not stop at application migrations. Check cron jobs, maintenance containers, admin notebooks, support scripts, and one-off runbooks copied into incident docs. For each command, decide whether the right scope is parent-only, whole hierarchy, or per-child maintenance with separate scheduling.
Then rehearse on a restored environment with production-shaped data. The important observations are simple: how many relations are touched, how long the command runs, whether it competes with normal traffic, and whether query plans change afterward. If the test environment is tiny, it will prove syntax but not operational shape.
What to change in runbooks
The safest runbooks make scope visible. Prefer VACUUM ONLY parent_table when the command intentionally excludes children. Prefer an explicit list or generated per-child maintenance plan when each child needs separate timing. Use the plain parent command when the goal is to maintain the logical table and the runtime has been tested.
Avoid mixing this upgrade check with unrelated tuning. If a query gets faster or slower after PostgreSQL 18, separate the maintenance-scope question from planner, statistics, index, and version-change questions. ANALYZE scope can change statistics freshness; it does not automatically explain every plan change. Capture representative plans before the upgrade, refresh statistics in the staged way you expect to use in production, and compare the high-value queries that users actually feel.
This is also a good time to review broad maintenance jobs next to connection pooling. Long maintenance commands use database connections like any other session. If the application is already near its connection limit, schedule maintenance away from peak traffic and review PgBouncer guidance so background jobs do not compete unnecessarily with request traffic. For high-risk changes, confirm backup posture through /docs/backups before the maintenance window.
Common mistakes
The first mistake is assuming the parent table name tells you the amount of work. In inherited schemas, the parent may be a small catalog-like relation while children contain nearly all rows. The command target can look small while the logical scope is large.
The second mistake is adding ONLY everywhere as a reflex. That recreates older behavior, but it may preserve a bug: child tables that were not being vacuumed or analyzed as intended by custom jobs. Use ONLY when the old scope is genuinely correct, not merely because it avoids thinking about the hierarchy.
The third mistake is rehearsing on a fresh PostgreSQL 18 database. Fresh schemas rarely include the uneven child sizes, stale statistics, dead tuples, old indexes, and traffic patterns that make maintenance behavior matter. Use a restore when the change is operational rather than purely syntactic.
Takeaway
PostgreSQL 18 makes VACUUM and ANALYZE on inherited parent tables behave more like logical-table maintenance by including children by default. That is a useful change, but it changes the scope of legacy scripts. Before upgrading a managed database, inventory inheritance relationships, audit scheduled maintenance commands, add ONLY where parent-only behavior is required, and rehearse broad maintenance on production-shaped data.
Sources and further reading
- PostgreSQL 18 release notes
- PostgreSQL
VACUUMreference - PostgreSQL
ANALYZEreference - PostgreSQL table inheritance documentation
- PostgreSQL declarative partitioning documentation
Written by ArmorDB Engineering
Practical notes on PostgreSQL operations, security, and infrastructure decisions for teams building production applications.
Updated Aug 27, 2026
Keep exploring
Related reading
News & Trends · 6 min read
PostgreSQL 18 ANALYZE VERBOSE: Better Maintenance Observability
PostgreSQL 18 adds WAL, CPU, and read detail to ANALYZE VERBOSE, giving production teams a clearer view of table statistics maintenance.
Read articleNews & Trends · 7 min read
PostgreSQL 18 Upgrade Checklist for Managed Databases
A practical PostgreSQL 18 upgrade checklist covering compatibility changes, checksums, MD5 deprecation, pg_upgrade statistics, COPY behavior, and managed rollout planning.
Read articleNews & Trends · 7 min read
PostgreSQL 18 TLS Configuration Changes: What Managed Database Teams Should Check
PostgreSQL 18 adds TLS 1.3 cipher configuration and changes elliptic-curve settings, which makes upgrade reviews a good time to document database transport security.
Read article