Blog
35 artigos · atualizado semanalmente Veja nossas Ferramentas
Todos os artigos
All

PostgreSQL 19 Beta: Auto-Scaling Async I/O, Native Graph Queries, and the Breaking Changes That Will Surprise You

PostgreSQL 19 Beta 1 ships async I/O with auto-scaling, native SQL/PGQ graph queries, 2x faster foreign key inserts, and parallel autovacuum. The breaking changes — JIT off by default, lz4 TOAST, RADIUS removed — are what you need to test before GA.

COVER · All

PostgreSQL 19 Beta: Auto-Scaling Async I/O, Native Graph Queries, and the Breaking Changes That Will Surprise You

PostgreSQL 19 Beta 1 dropped on June 4th. I read through the full release notes — not for fun, but because I've been caught off-guard before by a major version change that silently altered behavior I'd forgotten was even configurable. Three months before the September/October GA is the right time to test, not the week before you upgrade.

Here's what actually matters in this release, and what you need to check before upgrading production.


Async I/O That Finally Scales Itself

PostgreSQL 18 introduced the async I/O subsystem as a foundation. PostgreSQL 19 makes it practical.

The key change is io_method=worker with automatic scaling. Previously you had to estimate how many I/O workers to configure. Now Postgres scales the count automatically between io_min_workers and io_max_workers based on actual demand. For environments with variable load — nightly batch jobs, read spikes during business hours — having a static worker count was always a compromise. Now it isn't.

EXPLAIN ANALYZE also gained async I/O statistics via the IO option. Per plan node, you can see how many reads were issued asynchronously, how many completed, and how many bytes were transferred. This closes a real visibility gap: when a query is slow because of I/O, not processing, you previously had to infer that from context. Now you can measure it directly.

The read-ahead scheduler was also reworked for large I/O requests — the prefetch window now scales with the actual scan size rather than firing a fixed number of read-ahead requests.

Where you'll feel this first: sequential read-heavy workloads — analytics, data exports, nightly reports. If you're running Postgres on NVMe SSD with io_method=worker, benchmark before and after.


SQL/PGQ: Graph Queries Without Leaving Postgres

This is the feature that got the most attention in the release announcement, and it deserves it.

SQL/PGQ is the ISO/IEC 9075-16:2023 standard, now implemented in Postgres via two new constructs: CREATE PROPERTY GRAPH and GRAPH_TABLE. You declare a property graph over existing relational tables — no data migration, no schema changes — and then query it with pattern-matching syntax that resembles Cypher.

Example with an e-commerce schema:

CREATE PROPERTY GRAPH shop
  VERTEX TABLES (
    customers LABEL customer,
    products  LABEL product,
    orders    LABEL "order"
  )
  EDGE TABLES (
    order_items
      SOURCE  orders    DESTINATION products LABEL contains,
    customer_orders
      SOURCE  customers DESTINATION orders   LABEL placed
  );

SELECT customer_name
FROM GRAPH_TABLE (
  shop
  MATCH (c IS customer)-[IS placed]->(o IS "order" WHERE o.ordered_when = current_date)
  COLUMNS (c.name AS customer_name)
);

Internally, Postgres rewrites the graph query into a tree of relational joins. This is not a graph storage engine — it's metadata that maps existing tables to the vertex/edge abstraction, with the existing planner doing all the work. That's by design: you get the ergonomics of graph traversal without giving up the reliability of a mature relational engine.

The honest caveat: PG19 doesn't support quantified patterns (variable-length paths). MATCH (a)-[*1..5]->(b) — the recursive query type you'd use for social network paths or org hierarchies — isn't available yet. That's planned for a future release.

For cases like "find all products bought by customers who also bought X", "map module dependencies", or "traverse entity connections in semi-structured data" — this works well and is significantly more ergonomic than hand-writing recursive CTEs.


2x Faster Inserts With Foreign Keys

The up-to-2x throughput improvement for foreign key inserts has a specific context worth understanding.

The bottleneck that was fixed is the per-row foreign key check during inserts. Before PG19, each inserted row triggered an individual lookup in the parent table. Under high-write concurrency with foreign keys, that per-row round-trip was the primary bottleneck.

The optimization batches the checks — deferred batch verification instead of per-row checking. The gain scales with volume: the more rows per transaction, the more pronounced the improvement. For single-row OLTP inserts, the delta will be smaller. For bulk inserts or event-driven systems inserting hundreds of rows per transaction, 2x is a realistic number.

If you maintain event tables, structured logs, or any schema with foreign keys on high-write tables, benchmark this before upgrading. Numbers from your specific workload will tell more than any synthetic benchmark.


Parallel Autovacuum With Dynamic Scoring

Parallel autovacuum is something the Postgres community wanted for years. PG19 delivers it via autovacuum_max_parallel_workers.

The more interesting addition is the scoring system. Autovacuum now prioritizes tables using a score that considers multiple factors: dead tuple volume, access frequency, and transaction ID wraparound risk. Previously, prioritization was simpler — vacuum the most bloated tables first.

In practice, tables with wraparound risk (which cause downtime if not vacuumed in time) automatically move to the front of the queue, without manual per-table autovacuum_vacuum_cost_delay tuning. For large databases with dozens of tables of varying sizes, this reduces the autovacuum tuning overhead meaningfully.


pg_plan_advice: Planner Control Without Global Settings

This feature is for anyone who's spent time fighting the Postgres planner — when it picks a bad plan for a specific query and the only available escape was SET enable_seqscan = off globally (which is always a bad idea in production).

pg_plan_advice is a new extension that lets you stabilize and control planner decisions for specific queries without affecting global behavior. Think Oracle-style hints but implemented more surgically, without breaking Postgres's optimization model.

It requires installation and activation as an extension. But for environments where unstable plans on critical queries are a recurring problem, it eliminates an entire category of workarounds.


The Breaking Changes You Need to Test Before GA

JIT disabled by default. JIT compilation (jit = on since PG11) now ships off. The stated reason: the cost model the planner uses to decide when to activate JIT proved unreliable — it was enabling JIT on queries that didn't benefit, adding unnecessary compilation latency. If you have heavy analytical workloads that implicitly relied on JIT, you'll need to set jit = on explicitly in sessions or in the database configuration.

Check which queries were using JIT before migrating:

SELECT query, calls, jit_generation_time
FROM pg_stat_statements
WHERE jit_generation_time > 0
ORDER BY jit_generation_time DESC
LIMIT 20;

lz4 as the new default TOAST compression. default_toast_compression changes from pglz to lz4. LZ4 is generally faster at both compression and decompression — a net improvement for most workloads. With pg_upgrade, existing data keeps its original compression. Only new data gets lz4. Check whether any scripts assume the pglz format internally.

RADIUS authentication removed. If any environment still uses RADIUS in pg_hba.conf — unlikely but common in older enterprise setups — it's gone. No extended deprecation window. Audit pg_hba.conf in all environments before scheduling the upgrade.

MultiXact widened to 64-bit. MultiXactOffset was expanded from 32-bit to 64-bit, eliminating the ~4 billion member wraparound limit. Silently positive — no visible behavior change, just a risk category that no longer exists. pg_upgrade handles it, but worth knowing it's there.


What to Test Before the September/October GA

The beta is available for download now. Priority areas:

  1. Analytical queries relying on JIT: benchmark with jit = off vs explicit jit = on on your actual workload
  2. High-volume foreign key inserts: measure throughput before and after on representative data
  3. pg_hba.conf: audit all environments for RADIUS
  4. Queries with planner-sensitive plans: pg_plan_advice can help stabilize problematic plans before the upgrade breaks SLAs
  5. Dump and restore cycles: test pg_dump/pg_restore with the new compression defaults

Three months until GA is enough time to find surprises — if you start now.


Note: the editorial content ends here. What follows is a mention of a related tool.


The new SQL/PGQ syntax (CREATE PROPERTY GRAPH, GRAPH_TABLE, MATCH) is different enough from standard SQL to be worth formatting before sharing with your team or pasting into documentation. The SQL Formatter at Quick Tools handles formatting with configurable indentation and runs entirely in the browser — useful while experimenting with PG19 Beta locally.

RD
Autor
Rafael Duarte
Desenvolvedor backend com passagem por fintech e SaaS B2B — trabalhou em times que escalaram APIs de zero a milhões de requisições. Carrega cicatrizes de produção suficientes para ter opiniões fortes sobre ferramentas, padrões e decisões de arquitetura. Não é acadêmico: leu a RFC do UUID quando precisou escolher entre v4 e v7 para uma tabela de alta escrita.
Ver perfil