Query lenta e schema confuso: como pedir ajuda de banco de dados ao Claude Opus 5.5?

Pedir "otimize essa query" e receber um CREATE INDEX genérico é o padrão quando falta contexto. Para o Claude Opus 5.5 sugerir algo útil em banco de dados, o prompt precisa de três coisas: o plano de execução real (EXPLAIN (ANALYZE, BUFFERS)), o DDL com os índices que já existem e o volume de linhas das tabelas. Sem isso, a sugestão é chute em cima do nome das colunas. Lançado em 22 de setembro de 2026, o Opus 5.5 serve a janela de 1 milhão de tokens por padrão, então cabe plano e schema inteiros no pedido, sem recortes.
Colar a query no chat e escrever "otimize isso" é o caminho mais rápido pra receber um CREATE INDEX bonitinho que não resolve nada
Sem plano de execução, sem volume de linhas e sem a lista de índices que já existem, qualquer sugestão de otimização é chute estatístico em cima do nome das colunas
E o modelo não está errando por preguiça, ele está respondendo o que dá pra responder com o que você mandou
A boa notícia é que ficou mais fácil mandar contexto pra valer: o Claude Opus 5.5 foi lançado em 22 de setembro de 2026, primeiro modelo da família 5.5, e serve a janela completa de 1 milhão de tokens por padrão, sem header beta nenhum (Sonnet 5.5 e Haiku 5.5 foram anunciados para as semanas seguintes)
Traduzindo: cabe o plano de execução inteiro, o DDL das tabelas envolvidas e a contagem de linhas no mesmo prompt, em vez de você recortar trechinho de schema pra economizar espaço 🙂
Bora montar esse pedido do jeito certo?
O que você precisa ter antes de começar
Pouca coisa, mas cada item aqui muda a qualidade da resposta:
- Um banco PostgreSQL onde você pode rodar
EXPLAIN ANALYZE, de preferência com volume de dados parecido com produção - Um usuário de banco somente leitura pras consultas de diagnóstico, porque diagnóstico não precisa de permissão de escrita
- Acesso ao Claude Opus 5.5: API da Anthropic, Amazon Web Services, Google Cloud e Microsoft Azure, além dos planos Pro, Max, Team e Enterprise do Claude
Formação Claude Code
Domine Claude Code do absoluto zero até o avançado
- 120 aulas
- 4 projetos
- 9h 45min
E um aviso antes de você sair rodando comando: o ANALYZE do EXPLAIN não é simulação, ele executa a query de verdade pra medir o tempo real
Em SELECT isso é tranquilo
Em UPDATE ou DELETE você acabou de mexer nos dados achando que estava só medindo… Já viu o problema, né?
O outro detalhe é o ambiente: plano tirado de uma base de desenvolvimento com 200 linhas não vale nada, porque o planner escolhe estratégias diferentes conforme o volume
Como montar o pedido de otimização passo a passo
A ideia é simples: você faz o trabalho de coleta, o modelo faz o trabalho de leitura e hipótese
- Ache a query que realmente dói, com o pg_stat_statements
Antes de otimizar a query que você "acha" lenta, deixe o banco te dizer qual é a mais custosa. Isso é trabalho do módulo pg_stat_statements
No postgresql.conf:
shared_preload_libraries = 'pg_stat_statements'
pg_stat_statements.track = all
pg_stat_statements.track_planning = on
Depois do restart do servidor, no banco que você quer observar:
CREATE EXTENSION pg_stat_statements;
As estatísticas passam a viver na view pg_stat_statements, e é de lá que você tira a query campeã de tempo
Os parâmetros que interessam: pg_stat_statements.track aceita top, all ou none, pg_stat_statements.track_utility cuida dos comandos utilitários e pg_stat_statements.track_planning liga o rastreio das operações e da duração de planejamento. A documentação do pg_stat_statements tem a lista completa
O erro comum deste passo: achar que basta o CREATE EXTENSION. Não basta. O módulo precisa de memória compartilhada, então ele TEM que entrar em shared_preload_libraries e o servidor precisa reiniciar. O outro clássico é rodar o CREATE EXTENSION conectado no banco errado e depois jurar que a view está vazia
- Colete o plano com EXPLAIN (ANALYZE, BUFFERS)
Esse é o dado que separa análise de adivinhação:
EXPLAIN (ANALYZE, BUFFERS)
SELECT p.id, p.total, c.nome
FROM pedidos p
JOIN clientes c ON c.id = p.cliente_id
WHERE p.status = 'pendente'
AND p.criado_em >= now() - interval '30 days'
ORDER BY p.criado_em DESC
LIMIT 50;
O BUFFERS depende do ANALYZE, ele não funciona sozinho. Por isso a sintaxe da documentação é essa mesmo, os dois dentro dos parênteses
E o que esses números de buffer dizem? Eles mostram quantos blocos shared, local e temp foram lidos, acertados (hit), sujos (dirtied) e escritos
Um hit significa leitura evitada, porque o bloco já estava em cache
Junte tudo e você tem o mapa de quais partes da query são mais intensivas em I/O, que é exatamente a pergunta que "falta índice?" não responde
O erro comum deste passo: mandar pro modelo só o resumo ("deu 4 segundos") em vez do plano inteiro. O texto do plano é o insumo, copie ele completo, com os nós, os tempos e os buffers
- Traga o DDL com os índices existentes e o volume das tabelas
Aqui é onde a maioria dos pedidos morre. Sem o DDL, o modelo não tem como saber que a coluna que ele ia sugerir já está indexada
Monte um bloco com:
- a definição completa das tabelas envolvidas, incluindo constraints e todos os índices que já existem
- a contagem de linhas de cada tabela
- uma noção de seletividade nas colunas do
WHERE(quantos valores distintos, se tem coluna em que quase tudo é um único valor) - se a tabela é particionada, e por qual chave
O erro comum deste passo: mandar o schema "de memória", digitado na mão. Exporte o real. Schema de memória é ficção, e o modelo vai otimizar a sua ficção com muita competência
- Monte o prompt colando tudo de uma vez
Com 1 milhão de tokens de janela servidos por padrão, não tem motivo pra economizar contexto aqui
Um esqueleto que funciona:
Contexto: PostgreSQL, tabela pedidos com 48 milhões de linhas, clientes com 900 mil.
A query abaixo roda a cada 30s no dashboard e está em 4,2s.
SUA QUERY COMPLETA AQUI
[SAÍDA COMPLETA DO EXPLAIN (ANALYZE, BUFFERS)]
[DDL DAS TABELAS, COM TODOS OS ÍNDICES EXISTENTES]
O que eu quero:
1. leia o plano e diga onde está o tempo e onde está o I/O, citando os nós
2. liste hipóteses em ordem de impacto, dizendo qual evidência do plano sustenta cada uma
3. só sugira índice novo se ele não for redundante com os que já existem, e explique por que o planner usaria ele
4. diga o que você NÃO consegue concluir com os dados que eu mandei
O item 4 é o mais subestimado da lista. Pedir explicitamente "diga o que falta" transforma chute em pergunta, e pergunta você consegue responder com mais uma coleta
O erro comum deste passo: pedir "otimize" em vez de pedir "diagnostique". Otimizar é a segunda etapa, e quem otimiza sem diagnóstico produz índice decorativo
- Ajuste o parâmetro effort quando o assunto for schema
No Claude Opus 5.5 o adaptive thinking está sempre ligado e não pode ser desativado. O controle que você tem é o parâmetro effort, que define a profundidade do raciocínio
O padrão do modelo é medium (vale lembrar que no Opus 5 uma requisição sem effort rodava em high)
Para ler um plano de execução grande ou avaliar relações entre oito tabelas, subir o effort costuma fazer mais sentido que reescrever o prompt três vezes
O erro comum deste passo: assumir que a configuração antiga vale pro modelo novo e estranhar que a análise ficou mais rasa que antes, quando o que mudou foi só o padrão do parâmetro
Por que uma sugestão de índice sem plano de execução é chute
Se liga nos sintomas clássicos. Todos eles têm a mesma raiz: dado que ficou de fora do prompt
| Sintoma | Causa provável | O que faltou no prompt |
|---|---|---|
| O modelo sugeriu índice numa coluna que já tinha índice | Ele só viu o nome da coluna no WHERE |
O DDL completo, com todos os índices existentes |
| O índice foi criado e o planner ignorou ele | Baixa seletividade: com aquele volume o seq scan sai mais barato | Contagem de linhas e distribuição dos valores da coluna |
| A query continuou lenta depois do índice | O gargalo era I/O ou o join, não a busca da linha | A saída de BUFFERS, mostrando onde os blocos são lidos e escritos |
| A sugestão não considerou que a tabela é particionada | Nada no prompt dizia que existia particionamento | A informação de que a tabela é particionada e por qual chave |
Repara no padrão: nenhum desses casos é "o modelo é ruim em SQL"
São todos casos de resposta boa pra uma pergunta incompleta
Checklist de validação antes de aplicar
Recebeu a sugestão? Antes de rodar em produção, passa por aqui:
- O índice é redundante? Compare com a lista real de índices da tabela antes de criar mais um
- A tabela recebe escrita durante o dia? Um
CREATE INDEXcomum bloqueia escritas (mas não leituras) na tabela até terminar. OCREATE INDEX CONCURRENTLYconstrói o índice sem tomar locks que impeçamINSERT,UPDATEouDELETEconcorrentes, usando SHARE UPDATE EXCLUSIVE em vez de ACCESS EXCLUSIVE. Os detalhes estão na documentação do CREATE INDEX - A tabela é particionada? Build concorrente de índice em tabela particionada não é suportado. O caminho é construir o índice em cada partição individualmente e depois criar o índice particionado de forma não concorrente
- Você mediu de novo? Rode o mesmo
EXPLAIN (ANALYZE, BUFFERS)depois da mudança, no mesmo volume de dados, e confirme que o novo plano realmente usa o índice - O custo de escrita entrou na conta? Índice acelera leitura e cobra em toda escrita da tabela
Se a sugestão não passa nesse checklist, ela não era uma solução, era uma hipótese ainda não testada
Três cenários de banco em que o contexto muda a resposta
Cenário 1: query lenta pontual numa tabela grande
Aqui o pedido é focado: plano de execução e buffers
Você já sabe qual query é, já sabe que a tabela é grande, e o que você quer descobrir é onde o tempo vai
O prompt fica curto e o insumo fica gordo: query, plano completo, DDL das tabelas do join, volume
A pergunta certa é "qual nó do plano consome o tempo e o I/O", não "qual índice devo criar"
Cenário 2: modelagem confusa, chave e normalização
Esse é outro jogo. Índice não resolve modelagem torta
Quando o problema é schema (tabela que virou balaio, campo tipo que na verdade são três entidades, relacionamento sem chave, dado duplicado em três lugares), o insumo muda:
- DDL completo do recorte, não só de uma tabela
- os relacionamentos reais e a cardinalidade de cada um
- as regras de negócio que o schema deveria garantir
- as consultas que esse schema precisa servir
E seja explícito no pedido: "não sugira índice, avalie o desenho"
Se a resposta começar a apontar normalização e chaves compostas, vale casar isso com fundamento de modelagem de dados relacionais, porque decisão de schema você vai carregar por anos, diferente de um índice que se derruba em um comando
Cenário 3: investigação recorrente dentro do Claude Code
Quando isso deixa de ser um episódio e vira rotina, colar plano na mão cansa
Dá pra conectar o banco ao Claude Code por MCP, usando o servidor DBHub, da Bytebase:
claude mcp add --transport stdio db -- npx -y @bytebase/dbhub --dsn "postgresql://readonly:pass@host:5432/banco"
Repara no usuário da string de conexão: a própria documentação do Claude Code recomenda usar um usuário de banco somente leitura, pra que as queries que o Claude roda não possam modificar dados
E aqui tem uma pegadinha boa de saber: o claude mcp add salva a configuração sem validar credenciais
Ou seja, ele aceita um valor placeholder de boa e o servidor só falha quando tenta conectar, bem depois. Pra conferir, rode /mcp e veja se o servidor aparece como connected
Com o banco conectado, a parte que mais economiza tempo é registrar as convenções do schema no CLAUDE.md: nome de chave, padrão de soft delete, quais tabelas são particionadas, quais views são pesadas
Esses arquivos markdown são instruções persistentes de projeto, lidas no início de cada sessão. A recomendação é manter menos de 200 linhas por arquivo, porque arquivo longo consome mais contexto e derruba a aderência
Detalhe massa: o CLAUDE.md da raiz do projeto sobrevive à compactação, ele é relido do disco e reinjetado na sessão depois do /compact
E se a conversa começar a caminhar de diagnóstico pra mudança de verdade, aí o assunto passa a ser alterar o banco sem arriscar seus dados, que é uma preocupação diferente da de ler plano de execução
Conclusão
O resumo é meio anticlimático, mas é o que segura de pé: o Claude Opus 5.5 é muito bom em ler plano de execução e péssimo em adivinhar o seu schema
Plano de execução, DDL com índices existentes e volume de linhas. Com esses três, você recebe análise
Sem eles, você recebe chute bem escrito, e chute bem escrito é o tipo mais perigoso 😛
Sobre custo, o valor de API é US$ 4 por milhão de tokens de entrada e US$ 20 por milhão de tokens de saída, no identificador claude-opus-5-5
E tem um ponto que interessa justamente pra quem trabalha com banco: a leitura de cache caiu 60%, de US$ 0,50 para US$ 0,20 por milhão
Se você repete o mesmo schema gigante em vários prompts ao longo de uma investigação, esse é o número que pesa no fim do mês
Próximo passo? Habilita o pg_stat_statements, pega a query mais custosa da view e leva ela pro primeiro teste com o plano completo colado
Depois me conta se a primeira sugestão que você recebeu era índice ou pergunta… é um bom termômetro do seu prompt
Até o próximo post!
Perguntas frequentes
Por que o Claude Opus 5.5 erra a sugestão de índice mesmo sendo um modelo forte?
Porque o modelo responde só com o que foi mandado no prompt. Se falta plano de execução, DDL e volume de linhas, a sugestão vira chute em cima do nome das colunas, não análise de verdade.
Dá pra colar o plano de execução inteiro sem cortar nada no Claude Opus 5.5?
Dá. O Claude Opus 5.5 serve a janela completa de 1 milhão de tokens por padrão, sem precisar de header beta, então cabe o EXPLAIN (ANALYZE, BUFFERS) inteiro, o DDL das tabelas e a contagem de linhas no mesmo pedido.
Rodar EXPLAIN ANALYZE em produção é seguro pra pedir ajuda de otimização de query?
Depende do comando. Em SELECT é tranquilo, mas em UPDATE ou DELETE o ANALYZE executa a query de verdade, então você mexe nos dados achando que só estava medindo. Use um usuário somente leitura pra evitar esse problema nas consultas de diagnóstico.
Como o pg_stat_statements ajuda a escolher qual query levar pro Claude Opus 5.5?
Ele mostra qual query é realmente mais custosa, em vez de você chutar pela query que ‘parece’ lenta. Precisa entrar em shared_preload_libraries no postgresql.conf, reiniciar o servidor e depois rodar CREATE EXTENSION pg_stat_statements no banco desejado.
Quanto custa usar o Claude Opus 5.5 pra rodar esse tipo de diagnóstico via API?
O valor de API é US$ 4 por milhão de tokens de entrada e US$ 20 por milhão de tokens de saída, no identificador claude-opus-5-5, o mesmo que aparece na conclusão do post. Como o diagnóstico de query costuma mandar bastante contexto (plano, DDL, volume), o custo pesa mais no lado de entrada.
Dá pra criar o índice sugerido sem travar a tabela em produção?
Dá, usando CREATE INDEX CONCURRENTLY, que constrói o índice sem tomar locks que impeçam INSERT, UPDATE ou DELETE concorrentes. A ressalva é que esse build concorrente não é suportado em tabelas particionadas, sendo preciso criar o índice em cada partição separadamente.
Formações
Formação Vibe Coding
Do Prompt ao Produto: Crie Software Real com IA
- 474 aulas
- 20 projetos
- 39h 27min
Blog | Mais populares

Quando não vale a pena usar o Claude Opus 5.5 (e qual modelo usar no lugar)
Claude Opus 5.5 custa US$ 4/US$ 20 por milhão de tokens. Veja quando ele é desperdício e qual modelo usar no lugar em cada tarefa.

Checklist de segurança n8n VPS pública: guia essencial para proteger sua instalação
Checklist de segurança n8n VPS pública: guia essencial para proteger sua instalação A popularidade da automação de processos com o n8n está em alta, principalmente […]
O que significa “ChatGPT network error” e como resolver
O “ChatGPT Network Error” é uma ocorrência frequente na rotina de muitos usuários do ChatGPT. Porém, poucos compreendem seu significado, quando esse erro surge, etc. […]
