Blog
35 articles · updated weekly See our Tools
All articles
Todos

PostgreSQL 19 Beta: async I/O que se escala sozinho, graph queries nativas e as breaking changes que vão te pegar de surpresa

PostgreSQL 19 Beta 1 traz async I/O com auto-scaling, SQL/PGQ para graph queries nativas, inserts 2x mais rápidos com foreign keys e autovacuum paralelo. Mas são as breaking changes — JIT desativado, lz4 como TOAST default, RADIUS removido — que você precisa testar antes do GA.

COVER · Todos

PostgreSQL 19 Beta: async I/O que se escala sozinho, graph queries nativas e as breaking changes que vão te pegar de surpresa

O anúncio do PostgreSQL 19 Beta 1 saiu no dia 4 de junho. Li o release notes completo — não por prazer, mas porque já fui pego de surpresa em uma major version antes. Naquela época, um comportamento que mudou silenciosamente quebrou um job de manutenção noturno que eu tinha esquecido de documentar. Dessa vez prefiro ser chato antes do GA.

O que segue é meu resumo das mudanças que importam — as que você vai querer testar antes de upgradar produção em setembro ou outubro.


Async I/O que finalmente se escala automaticamente

O PostgreSQL 18 trouxe o subsistema de async I/O como base. No 19, ele ficou prático.

O ponto central é io_method=worker com auto-scaling. Antes, você tinha que estimar quantos workers de I/O configurar. Agora, o Postgres escala automaticamente entre io_min_workers e io_max_workers conforme a demanda. É o tipo de feature que parece pequena mas que resolve um problema concreto: em ambientes com carga variável — jobs de batch noturnos, picos de leitura durante horário comercial — você não quer o mesmo número de workers o tempo todo.

O EXPLAIN ANALYZE ganhou suporte a estatísticas de async I/O via opção IO. Você consegue ver, por nó do plano, quantas leituras foram emitidas de forma assíncrona, quantas completaram e quantos bytes foram transferidos. Isso fecha uma lacuna de visibilidade real: quando uma query está lenta por causa de I/O e não de processamento, antes você precisava inferir isso pelo contexto. Agora dá para medir.

O read-ahead scheduler também foi refeito para requisições grandes — o prefetch window agora escala com o tamanho real do scan em vez de disparar um número fixo de read-aheads.

Onde você vai sentir primeiro: workloads de leitura sequencial pesada — analytics, data exports, relatórios noturnos. Se você roda Postgres em SSD NVMe com io_method=worker, vale benchmarkar antes e depois.


SQL/PGQ: graph queries sem sair do Postgres

Essa é a feature que mais chamou atenção no release — e com razão. É genuinamente útil para um conjunto de problemas que antes exigia um banco de dados de grafos separado.

SQL/PGQ é o padrão ISO/IEC 9075-16:2023, implementado no Postgres via dois novos construtos: CREATE PROPERTY GRAPH e GRAPH_TABLE. A ideia é declarar um grafo sobre tabelas relacionais existentes — sem migrar dados, sem mudar schema — e depois fazer consultas com sintaxe de pattern-matching que lembra Cypher.

Exemplo prático com schema de e-commerce:

CREATE PROPERTY GRAPH loja
  VERTEX TABLES (
    clientes LABEL cliente,
    produtos  LABEL produto,
    pedidos   LABEL pedido
  )
  EDGE TABLES (
    itens_pedido
      SOURCE  pedidos  DESTINATION produtos LABEL contém,
    pedidos_cliente
      SOURCE  clientes DESTINATION pedidos  LABEL fez
  );

SELECT nome_cliente
FROM GRAPH_TABLE (
  loja
  MATCH (c IS cliente)-[IS fez]->(p IS pedido WHERE p.data = current_date)
  COLUMNS (c.nome AS nome_cliente)
);

O que o Postgres faz internamente é um rewrite: a query de grafo é convertida em uma árvore de joins relacionais. Não é um storage engine de grafos — é metadata que mapeia tabelas existentes para a abstração vértice/aresta. O planner existente continua fazendo o trabalho. Isso é intencional: você ganha a ergonomia de graph traversal sem abrir mão de um engine relacional maduro.

Uma ressalva honesta: a implementação do PG19 não suporta quantified patterns (caminhos de comprimento variável). Então MATCH (a)-[*1..5]->(b) — o tipo de query recursiva para encontrar caminhos em uma rede social ou hierarquia organizacional — não está disponível ainda. Planejado para versão futura.

Para casos como "encontre todos os produtos comprados por clientes que também compraram X", "mapeie dependências entre módulos", ou "traverse conexões entre entidades em dados semi-estruturados" — funciona bem e é muito mais ergonômico do que escrever CTEs recursivas na mão.


Inserts 2x mais rápidos com foreign keys

O número de até 2x mais throughput em inserts com foreign key checks tem um contexto que vale entender.

O gargalo que foi resolvido estava na verificação de foreign keys durante inserts. Antes do PG19, cada linha inserida disparava uma verificação individual na tabela pai. Em workloads de alta escrita com foreign keys, esse round-trip por linha era o gargalo principal — especialmente sob alta concorrência.

A otimização agrega as verificações: batch deferred checks em vez de verificação individual por linha. O ganho é proporcional ao volume: quanto mais linhas por transação, mais pronunciada a melhora. Para OLTP com inserts unitários, o delta vai ser menor. Para bulk inserts ou sistemas de eventos que inserem centenas de linhas por transação, 2x é um número realista.

Se você mantém tabelas de eventos, logs estruturados, ou qualquer schema com foreign keys em tabelas de alta escrita, vale benchmarkar isso antes do upgrade. É o tipo de melhora onde os números do seu workload específico dizem mais do que qualquer benchmark sintético.


Autovacuum paralelo com scoring dinâmico

Autovacuum usando múltiplos workers em paralelo é algo que a comunidade Postgres queria há anos. O PG19 entrega via autovacuum_max_parallel_workers.

O que é mais interessante é o scoring system. O autovacuum agora prioriza tabelas usando uma pontuação que considera múltiplos fatores: volume de dead tuples, frequência de acesso, e risco de wraparound de transaction ID. Antes, a priorização era mais simples — basicamente vacuuma o que está mais bloated.

Na prática, isso significa que tabelas com risco de wraparound (que causam downtime se não forem varridas a tempo) passam à frente na fila automaticamente, sem você precisar configurar autovacuum_vacuum_cost_delay manualmente por tabela. Para bases grandes com dezenas de tabelas de tamanhos diferentes, isso reduz a quantidade de tuning manual de autovacuum necessário.


pg_plan_advice: controle sobre o planner sem gambiarras globais

Essa feature é para quem já perdeu horas brigando com o planner do Postgres — quando ele escolhe um plano ruim para uma query específica e a única saída disponível era SET enable_seqscan = off globalmente (o que é sempre uma péssima ideia em produção).

pg_plan_advice é uma extensão nova que permite estabilizar e controlar decisões do planner por query específica, sem afetar o comportamento global do banco. A ideia é similar aos hints do Oracle ou SQL Server, mas implementada de forma mais cirúrgica e sem quebrar o modelo de otimização do Postgres.

Ela precisa ser instalada e ativada como extensão. Mas para ambientes onde planos instáveis em queries críticas são um problema recorrente, isso elimina uma categoria inteira de workarounds.


As breaking changes que você precisa testar antes do GA

Aqui está o que pode te pegar de surpresa no upgrade:

JIT desativado por padrão. O JIT compilation (jit = on era o default desde o PG11) agora vem desligado. A razão declarada: o cost model do planner para decidir quando ativar JIT se mostrou não confiável — ele ativava JIT em queries que não se beneficiavam, adicionando latência de compilação desnecessária. Se você tem workloads analíticos pesados que dependiam de JIT implicitamente, vai precisar setar jit = on explicitamente nas sessões ou na configuração do banco.

Como verificar o impacto antes de migrar:

-- queries que estavam usando JIT no banco atual
SELECT query, calls, jit_generation_time
FROM pg_stat_statements
WHERE jit_generation_time > 0
ORDER BY jit_generation_time DESC
LIMIT 20;

lz4 como compressão TOAST padrão. O default_toast_compression muda de pglz para lz4. LZ4 é geralmente mais rápido em compressão e descompressão — então isso é uma melhora para a maioria dos casos. Com pg_upgrade, os dados existentes mantêm a compressão original. Só novos dados usarão lz4. Vale verificar se algum script assume o formato pglz internamente.

Remoção de RADIUS authentication. Se alguém ainda usa RADIUS no pg_hba.conf — improvável, mas acontece em ambientes corporativos mais antigos — isso foi removido, sem período de deprecation estendido. Audite o pg_hba.conf de todos os ambientes antes de planejar o upgrade.

MultiXact widened para 64-bit. O contador MultiXactOffset foi ampliado de 32-bit para 64-bit, eliminando o limite de ~4 bilhões de membros e o risco de wraparound associado. Silenciosamente positivo — sem mudança de comportamento visível, só um risco que deixa de existir. O pg_upgrade lida com isso, mas vale saber que está lá.


O que testar antes do GA em setembro/outubro

O beta está disponível para download agora. Áreas prioritárias:

  1. Queries analíticas com JIT: benchmarkar com jit = off vs jit = on explícito no seu workload real
  2. Tabelas com heavy foreign key inserts: medir throughput antes e depois com dados representativos
  3. pg_hba.conf: auditar todos os ambientes em busca de RADIUS
  4. Queries com planos sensíveis ao otimizador: pg_plan_advice pode ajudar a estabilizar planos problemáticos antes que o upgrade quebre SLAs
  5. Ciclo de dump e restore: testar pg_dump/pg_restore com os novos defaults de compressão

Três meses até o GA é tempo suficiente para encontrar surpresas — se você começar agora.


Nota: o conteúdo editorial acabou aqui. O que vem abaixo é uma indicação de ferramenta relacionada ao tema do post.


Ferramenta relacionada

A nova sintaxe SQL/PGQ (CREATE PROPERTY GRAPH, GRAPH_TABLE, MATCH) é suficientemente diferente do SQL padrão para valer formatar antes de colar em documentação ou compartilhar com o time. O Formatador SQL do Quick Tools suporta formatação com indentação configurável e funciona 100% no browser — útil para limpar queries de teste enquanto você experimenta o PG19 Beta.

RD
Author
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.
View profile