The PostgreSQL 19 first beta is imminent. Feature freeze hit on April 8, the PG19-Final commitfest closed on April 9, and the release notes are well into draft on pgsql-hackers. The headline list will include SQL/PGQ graph queries, and every other preview post is going to lead with them. I am not going to.
There are four other PG19 changes that will land harder on operations work than any graph-query syntax. Here they are.
64-bit MultiXact Members
PostgreSQL has had a “vacuum or die” failure mode bound up in the 32-bit MultiXact member counter since forever. When a high-concurrency workload accumulated enough shared row locks — SELECT ... FOR SHARE, foreign-key checks, the usual suspects — you could chew through the 4-billion-member space, the system would refuse new transactions, and the only recovery path was an emergency VACUUM of the affected database with the application offline.
PG19 widens the member counter to 64 bits. The wraparound math is still there in principle (at 2^64 you have other problems), but in practice the failure mode is gone. If you have ever been paged at 3 AM about multixact member exhaustion, this is the change you care about. If you have not, ask one of your colleagues about it.
Parallel Autovacuum Index Workers
autovacuum_max_parallel_workers lets autovacuum process indexes on a single table in parallel, the same way a manual VACUUM (PARALLEL n) does today. Mostly this is an obvious win, especially for the wide-and-many-indexes tables where serial index cleanup is the slow phase.
Watch the interaction with maintenance_work_mem. Each parallel worker takes its own slice. A busy autovacuum can now consume autovacuum_max_workers × autovacuum_max_parallel_workers × maintenance_work_mem in the worst case. The defaults will be fine. Custom-tuned systems with maintenance_work_mem cranked to 4 GB and a dozen autovac workers should redo the arithmetic before they cut the upgrade ticket.
Temporal FOR PORTION OF
UPDATE ... FOR PORTION OF (period) and the matching DELETE clause finally land. They let you modify a temporal row within a sub-range of its period, and PostgreSQL automatically splits the row to preserve the untouched portions on either side.
The semantics are reasonable. The surprises are in the trigger and foreign-key interactions: a FOR PORTION OF update can fire row triggers on rows that did not exist when the statement started, because the statement created them mid-execution. Cascading FK behavior on temporal tables is now meaningfully more interesting than it was a year ago. Test before you ship temporal logic to production. The feature is well-specified; the application-side ecosystem around it is not yet.
jit = off By Default
jit now defaults to off in PG19. This is a quiet change with loud consequences.
JIT was on by default starting in PG12, and a non-trivial chunk of analytic workloads have been silently relying on it for plan-time codegen on long-running queries. If you run OLTP, you almost certainly never benefited from JIT and have been paying its planning cost on every query that crossed the cost threshold. The new default is correct.
If you run OLAP — and a surprising number of people running PostgreSQL run OLAP and have not noticed — you want to explicitly set jit = on in postgresql.conf before the upgrade, benchmark, and then decide. The upgrade is the wrong moment to discover that a six-minute report now takes nineteen.
Beta 1 is the moment to start running these against real workloads. The four above are the ones that change how the database feels in production, not just what it can do on a slide.