Voltar para o blog
PostgreSQLIAPerformance

Query plans 81% mais rápidos que o Postgres com um modelo 4B

10 de outubro de 2026·6 min de leitura·Diego Horvatti

Um modelo de linguagem com só 4 bilhões de parâmetros aprendeu a montar query plans que rodam 81% mais rápido que os escolhidos pelo próprio Postgres. Quem conta é o Rohan Bansal, num post sobre o projeto QORL. Antes de comemorar ou de achar que é hype, vale entender o que é um query plan, por que o otimizador erra e o que esse resultado muda para quem escreve SQL todo dia.

O que é um query plan e por que o Postgres erra

Quando você manda um SELECT com cinco JOINs, o Postgres não executa na ordem que você escreveu. Ele monta um plano. Decide qual tabela ler primeiro, se usa índice ou faz seq scan, se o join vai ser nested loop, hash ou merge.

Para escolher, ele estima quantas linhas cada etapa vai devolver. A estimativa vem das estatísticas que o ANALYZE coleta. O problema é que essas estatísticas assumem que as colunas são independentes. Na vida real elas quase nunca são.

Exemplo clássico: uma tabela de endereços com cidade e estado. O Postgres acha que filtrar por cidade = 'Campinas' e estado = 'SP' reduz as linhas duas vezes. Na prática, quem é de Campinas já é de SP. A estimativa sai muito baixa, ele escolhe um nested loop achando que vai processar 50 linhas e acaba processando 500 mil.

Você já viu isso acontecer:

EXPLAIN ANALYZE
SELECT ...
-- Nested Loop (rows=12) (actual rows=480312)

Quando o rows estimado e o actual rows ficam separados por três ordens de grandeza, o plano já nasceu errado. Isso não é bug do Postgres. É um problema difícil de verdade. Tem até um paper famoso de 2015, "How Good Are Query Optimizers, Really?", que montou o benchmark JOB (Join Order Benchmark) em cima do IMDb justamente para expor esses erros de cardinalidade em todos os bancos grandes.

O que o QORL fez de diferente

A ideia de usar aprendizado de máquina para otimizar query plans não é nova. Neo (2019) e Bao (2021) já tentavam isso. O Bao, por exemplo, não substitui o otimizador. Ele escolhe um conjunto de "dicas" (desliga nested loop aqui, força hash join ali) e deixa o Postgres montar o plano dentro dessas regras.

O que chama atenção no QORL é usar um modelo de linguagem pequeno, de 4B, treinado para essa tarefa. Não é um GPT gigante chamado via API para cada query. É um modelo que roda numa máquina comum e que aprendeu, olhando a consulta, a propor um plano melhor que o do otimizador nativo.

O caminho mais comum para aplicar um plano externo no Postgres é a extensão pg_hint_plan, que aceita dicas em comentário:

/*+ Leading((t mi ci)) HashJoin(t mi) IndexScan(ci ci_movie_id_idx) */
SELECT ...
FROM title t
JOIN movie_info mi ON mi.movie_id = t.id
JOIN cast_info ci ON ci.movie_id = t.id
WHERE ...;

O modelo gera esse tipo de coisa e o banco obedece. Você não troca o Postgres, só dá uma segunda opinião para ele.

Leia o post original para ver os detalhes da métrica, porque "81% mais rápido" pode significar coisas bem diferentes: média, mediana, soma do tempo de um benchmark inteiro. Em benchmarks como o JOB, poucas queries patológicas costumam dominar o tempo total. Consertar três delas já mexe muito no número final.

O otimizador do Postgres não é burro. Ele só acredita demais nas próprias estatísticas.

Por que um modelo pequeno importa mais que um grande

Aqui está a parte que eu acho mais interessante, e não é o 81%.

Planejar uma query no Postgres leva microssegundos ou poucos milissegundos. Se você colocar um LLM de 70B na frente de cada consulta, o tempo de inferência come todo o ganho em qualquer query OLTP. Ninguém aceita esperar 800 ms para economizar 40 ms.

Um modelo de 4B muda essa conta. Ele cabe numa GPU modesta, ou até em CPU com quantização. Ainda não é rápido o bastante para rodar em toda query do seu app, mas passa a fazer sentido para:

  • relatórios analíticos que levam segundos ou minutos
  • jobs noturnos de ETL
  • dashboards com consultas pesadas e repetitivas
  • queries que você já sabe que dão problema

Nesses casos, gastar 200 ms pensando para economizar 20 segundos é negócio fechado.

O que muda no seu código hoje

Na prática, quase nada muda amanhã. E tudo bem. Não instale um modelo na frente do seu banco de produção porque leu um post. Mas o resultado mostra onde o dinheiro está, e você pode atacar o mesmo problema com ferramentas que já existem.

1. Meça antes de achar. Ative o pg_stat_statements e descubra quais queries consomem mais tempo total. Normalmente são cinco ou seis.

SELECT query, calls, total_exec_time, mean_exec_time
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;

2. Procure erro de estimativa. Rode EXPLAIN (ANALYZE, BUFFERS) nessas queries e compare rows com actual rows. Onde a diferença for grande, o otimizador está chutando.

3. Ensine a correlação para o Postgres. O problema de cidade e estado tem solução nativa desde o Postgres 10:

CREATE STATISTICS endereco_cidade_estado (dependencies, ndistinct)
ON cidade, estado FROM enderecos;

ANALYZE enderecos;

Muita gente nunca usou CREATE STATISTICS. É o jeito mais barato de corrigir boa parte dos planos ruins, e não exige IA nenhuma.

4. Aumente a amostra onde importa. Colunas com distribuição torta se beneficiam de mais amostragem:

ALTER TABLE pedidos ALTER COLUMN status SET STATISTICS 1000;
ANALYZE pedidos;

5. Use hints só como último recurso. O pg_hint_plan resolve, mas congela uma decisão. Quando os dados mudarem, o plano forçado pode virar o pior plano possível. E ninguém vai lembrar daquele comentário mágico daqui a um ano.

As objeções que valem a pena

"Então o otimizador vai ser substituído por IA?" Não tão cedo. O otimizador tradicional tem uma qualidade que modelo nenhum tem ainda: é previsível. Você consegue explicar por que ele escolheu o plano. Quando um modelo propõe um plano estranho, debugar fica bem mais difícil.

"E se o modelo errar feio?" Esse é o risco real. Uma rede que acerta 95% das vezes e erra para pior nos outros 5% pode derrubar produção. Por isso abordagens como o Bao trabalham com dicas e mantêm o Postgres no controle. O pior caso importa mais que a média. E sim, isso vale para quem nunca teve um incidente às 3 da manhã por causa de um nested loop, ainda.

"Funciona no meu schema?" Depende. Modelos treinados em benchmark tendem a aprender o benchmark. Seu e-commerce com 40 tabelas e dados sujos não é o IMDb. Generalização é a pergunta que todo trabalho desse tipo precisa responder, e é a primeira coisa que eu olharia antes de confiar.

Minha opinião

Gosto desse tipo de resultado porque ele é honesto sobre onde a IA pode ajudar. Não é um chatbot escrevendo SQL por você. É um modelo pequeno atacando um problema antigo, bem definido e com métrica clara: a query ficou mais rápida ou não.

Acho que o futuro aqui é híbrido. O otimizador tradicional continua no comando e um modelo leve sugere correções nas queries analíticas pesadas, onde o custo da inferência se paga. Até isso virar extensão estável do Postgres, o melhor investimento continua sendo o básico bem feito: pg_stat_statements, EXPLAIN ANALYZE e CREATE STATISTICS. Isso já resolve mais problema do que parece.

Se você curte ver esse tipo de otimização aplicada em projeto real, dá uma olhada no que eu venho construindo nos meus projetos.

Resumo para o LinkedIn

Um modelo de 4B montou query plans 81% mais rápidos que os do próprio Postgres.

O otimizador não é burro. Ele só acredita demais nas próprias estatísticas e acha que cidade e estado são colunas independentes.

O que mais me chamou atenção nem foi o número. Foi o tamanho do modelo: 4B roda em máquina comum e já compensa em relatório pesado, ETL e dashboard.

Mas antes de colocar IA na frente do banco, faça o básico: pg_stat_statements, EXPLAIN ANALYZE e CREATE STATISTICS. Isso já resolve mais plano ruim do que parece.

Escrevi o passo a passo completo no blog. Qual foi a pior query que você já teve que caçar?

#PostgreSQL #SQL #Performance #InteligenciaArtificial #BackendDev