# Escreva SQL e migrations de banco de dados com IA

URL: https://agentvera.dev/pt/blog/write-sql-with-ai/ · Publicado: 2026-10-27

Como escrever SQL e migrations com agentes de código com segurança: passe o schema, use um usuário somente leitura, confira o EXPLAIN e teste numa cópia.

**Resumo:**

- Agentes de IA escrevem bom SQL quando veem o schema real, o plano da query e o tamanho das tabelas. Dê a eles um usuário de banco somente leitura, não suas credenciais de admin.
- Peça migrations em passos pequenos e reversíveis (expand, migrar dados, contract), use criação de índices sem bloqueio e rode toda migration primeiro numa cópia dos dados.
- Servidores MCP de banco, como o do Supabase, têm modo somente leitura. Nunca aponte um agente para a produção com acesso de escrita; gere o SQL, revise e aplique você mesmo.

**Para escrever SQL com IA com segurança, dê ao agente o seu schema real e um usuário de banco somente leitura, faça-o mostrar o plano da query e mantenha cada migration pequena, reversível e testada numa cópia dos dados antes de chegar perto da produção.** Um agente de código com IA escreve queries e migrations rápido. O risco não é ele escrever um SQL ruim de vez em quando, e sim um comando ruim rodar onde pode causar estrago.

Este guia mostra como pedir queries, como conferi-las com `EXPLAIN`, como pedir índices, como escrever migrations que não travam nem perdem dados, como os ORMs entram nisso e como conectar um agente a um banco via MCP sem entregar as chaves da produção. Os exemplos usam PostgreSQL; as ideias valem para MySQL e SQLite.

## Comece pelo schema, não pela pergunta

O motivo mais comum para um agente escrever uma query errada é ter chutado: uma coluna chamada `user_id` que na verdade é `account_id`, um status guardado como inteiro, uma flag de soft delete que ele não conhecia. Dê o schema primeiro.

Onde conseguir:

- **Arquivos de schema do ORM.** `prisma/schema.prisma`, seus arquivos de schema do Drizzle, `models.py` do Django, `db/schema.rb` do Rails. O agente consegue lê-los diretamente; indique-os no prompt.
- **Um dump só da estrutura.** `pg_dump --schema-only` grava tabelas, colunas, índices e constraints sem nenhum dado:

```bash
pg_dump --schema-only --no-owner "$DEV_DATABASE_URL" > schema.sql
```

- **Uma conexão de banco somente leitura** via servidor MCP, para o agente listar tabelas e inspecionar colunas sozinho (mais sobre isso abaixo).

Depois acrescente o que o schema não diz: o tamanho aproximado das tabelas, quais colunas costumam ser NULL e o que significam os termos do negócio. “Cliente ativo é quem fez um pedido nos últimos 90 dias” evita um chute errado.

Um prompt para uma query:

```text
Using schema.sql: write a PostgreSQL query that returns, for each country,
the number of active customers (an order in the last 90 days) and their
total order value this year. Exclude soft-deleted customers
(deleted_at IS NOT NULL). orders has about 20M rows, customers 400k.
Run it on the dev database, show me the first 10 rows and the EXPLAIN plan.
```

## Use um usuário somente leitura para o agente

Antes de um agente rodar qualquer coisa num banco, dê a ele um usuário próprio que não consegue alterar dados. No PostgreSQL 14 ou mais novo, o papel nativo `pg_read_all_data` deixa isso curto:

```sql
CREATE ROLE agent_ro LOGIN PASSWORD 'change-me';
GRANT pg_read_all_data TO agent_ro;
ALTER ROLE agent_ro SET default_transaction_read_only = on;
ALTER ROLE agent_ro SET statement_timeout = '30s';
```

`pg_read_all_data` dá acesso de leitura a todas as tabelas, sem direito de escrita. As duas linhas `ALTER ROLE` são uma segurança extra: as transações começam somente leitura, e uma query descontrolada é cancelada depois de 30 segundos. Em versões mais antigas ou para um acesso mais restrito, conceda `CONNECT`, `USAGE` no schema e `SELECT` nas tabelas que quiser.

Aponte esse usuário para um banco de desenvolvimento ou staging com dados realistas, não para a produção. Se precisar de números da produção, use uma réplica de leitura ou uma cópia recente anonimizada.

## Leia o plano da query

Uma query que retorna as linhas certas ainda pode levar minutos. Peça ao agente para rodar `EXPLAIN` em tudo que toca uma tabela grande e explicar o plano para você:

```sql
EXPLAIN (ANALYZE, BUFFERS)
SELECT c.country, count(DISTINCT c.id)
FROM customers c
JOIN orders o ON o.customer_id = c.id
WHERE o.created_at > now() - interval '90 days'
  AND c.deleted_at IS NULL
GROUP BY c.country;
```

`EXPLAIN` sozinho mostra o plano que o banco usaria. `ANALYZE` executa de fato a query e acrescenta tempos e contagens de linhas reais. Isso importa: `EXPLAIN ANALYZE` num `UPDATE` ou `DELETE` altera os dados de verdade. Coloque-os numa transação que você desfaz com rollback, ou rode só numa cópia.

O que pedir para o agente procurar:

- **Sequential scans em tabelas grandes** quando você filtra poucas linhas.
- **Linhas estimadas vs reais** muito distantes, o que indica estatísticas desatualizadas (`ANALYZE tablename` as atualiza).
- **Sorts ou hashes indo para o disco.**
- **Nested loops sobre muitas linhas** onde um hash join sairia mais barato.

Um bom prompt de acompanhamento: “Explique este plano em palavras simples. Qual etapa leva mais tempo e por quê? Proponha uma mudança e mostre o novo plano.”

## Peça índices, com o custo-benefício

Agentes adoram sugerir índices. Cada um acelera algumas leituras, deixa mais lenta toda escrita naquela tabela e ocupa espaço em disco. Peça a justificativa:

```text
The query above does a sequential scan on orders. Suggest at most one
index, explain which queries it helps and what it costs on writes,
and show the EXPLAIN plan with it on the dev database.
```

Numa tabela movimentada, crie o índice sem bloquear escritas:

```sql
CREATE INDEX CONCURRENTLY idx_orders_customer_created
  ON orders (customer_id, created_at);
```

`CONCURRENTLY` demora mais, mas não bloqueia inserts e updates enquanto roda. Ele não pode rodar dentro de um bloco de transação, o que importa porque muitas ferramentas de migration envolvem cada migration numa transação; veja como a sua ferramenta lida com isso (a maioria tem uma opção para desligar a transação numa migration específica). Se uma criação concorrente falhar, ela deixa para trás um índice inválido que você precisa remover e recriar.

## Escreva migrations seguras de rodar

Uma migration roda sobre dados vivos, muitas vezes enquanto o app está atendendo tráfego. Estes são os padrões para pedir ao seu agente e para conferir no que ele entregar.

### Expand, migrate, contract

Não renomeie nem remova num passo só. Para renomear `users.name` para `users.full_name`:

1. **Expand:** adicione `full_name` como coluna nullable. Faça deploy de código que escreve nas duas colunas.
2. **Migrate:** preencha `full_name` a partir de `name` em lotes. Passe as leituras para `full_name`.
3. **Contract:** numa versão posterior, quando nada mais ler `name`, remova-a.

Cada passo pode ir para deploy e ser revertido isoladamente. Um único `ALTER TABLE ... RENAME COLUMN` quebra toda instância do código antigo em execução no momento em que roda.

### Evite locks longos

Algumas DDLs pegam um lock que bloqueia leituras ou escritas enquanto rodam. Peça ao agente para sinalizá-las e usar a forma mais segura:

| Arriscado | Mais seguro |
| --- | --- |
| `CREATE INDEX` numa tabela grande | `CREATE INDEX CONCURRENTLY` |
| Adicionar uma foreign key num passo só | `ADD CONSTRAINT ... NOT VALID`, depois `VALIDATE CONSTRAINT` num passo separado |
| `SET NOT NULL` numa tabela grande | Adicione um `CHECK (col IS NOT NULL) NOT VALID`, valide-o e então aplique NOT NULL |
| Mudar o tipo de uma coluna | Adicione uma coluna nova, preencha, troque e remova a antiga |
| Um `UPDATE` gigante para um backfill | Lotes de alguns milhares de linhas |

Desde o PostgreSQL 11, adicionar uma coluna com default constante não reescreve a tabela, então isso costuma ser barato. Defina também um lock timeout no topo da migration, para ela falhar rápido em vez de ficar na fila atrás de uma query longa e bloquear tudo o que vem depois:

```sql
SET lock_timeout = '5s';
```

### Torne-a reversível

Toda migration deve ter um caminho de volta, seja uma down migration ou um passo de rollback por escrito. Peça explicitamente: “Escreva a migration up e down e me diga quais passos não podem ser desfeitos sem perda de dados.” Remover uma coluna não se desfaz com uma down migration; os dados já foram. Esse é mais um motivo para remover num passo posterior e separado, depois de um backup.

### Teste numa cópia

Rode a migration numa cópia dos dados antes da produção: um banco de staging restaurado de um backup recente, ou um banco local com dados falsos no volume da produção. Confira três coisas: que ela termina, quanto tempo leva e que o app continua funcionando com o novo schema. Depois rode a down migration e confira também.

## Usando um ORM: deixe-o gerar, peça ao agente para revisar

Se você usa um ORM, o fluxo mais seguro é: mude o model, deixe o ORM gerar a migration e peça ao agente para revisar o SQL gerado.

| ORM | Gerar uma migration | Aplicar | Ver o SQL |
| --- | --- | --- | --- |
| Prisma | `npx prisma migrate dev --name add_invoice --create-only` | `npx prisma migrate deploy` | o arquivo `migration.sql` que ele cria |
| Drizzle | `npx drizzle-kit generate` | `npx drizzle-kit migrate` | os arquivos SQL na sua pasta de migrations |
| Django | `python manage.py makemigrations` | `python manage.py migrate` | `python manage.py sqlmigrate app 0004` |
| Rails | `bin/rails generate migration AddFullNameToUsers` | `bin/rails db:migrate` | `db/schema.rb` e o arquivo da migration |

O `--create-only` do Prisma grava a migration sem aplicá-la, para você editar o SQL antes, por exemplo para adicionar `CONCURRENTLY` ou dividir um passo. O Drizzle também tem `drizzle-kit push`, que aplica mudanças de schema diretamente sem arquivos de migration; é prático para protótipos locais, mas use migrations geradas para tudo que for compartilhado.

Um prompt de revisão que funciona com qualquer um deles:

```text
Read the new migration in prisma/migrations/. For each statement, tell me:
does it lock the table, can it lose data, how long will it take on a
table with 20M rows, and is there a safer form? Don't change any files.
```

## Conectando um agente a um banco com MCP

Um servidor [MCP](/pt/glossary/mcp/ "O que é MCP") deixa o agente consultar o banco sozinho: listar tabelas, rodar um `SELECT`, ler um plano. Isso é útil, e também é onde mora o risco, então comece no modo somente leitura.

O **Supabase** tem um servidor MCP hospedado. Em outubro de 2026, adicionar `read_only=true` à URL faz toda query rodar como um usuário Postgres somente leitura, e `project_ref` amarra o servidor a um projeto:

```bash
claude mcp add --transport http supabase \
  "https://mcp.supabase.com/mcp?project_ref=<your-project-ref>&read_only=true"
```

A orientação do próprio Supabase é conectar um projeto de produção só quando a tarefa realmente precisa de dados de produção, e mesmo assim com escopo por projeto e modo somente leitura ativados; manter a aprovação manual das chamadas de ferramentas; e revisar os resultados antes de agir com base neles, porque as proteções contra prompt injection não são infalíveis.

**PostgreSQL puro:** use um servidor MCP de Postgres mantido, com o seu usuário `agent_ro` na connection string. [Melhores servidores MCP para programar](/pt/blog/best-mcp-servers-for-coding/ "Melhores servidores MCP para programar") lista opções e suas configurações de somente leitura. O antigo servidor Postgres de referência do projeto MCP foi arquivado.

As regras que vale escrever no seu `CLAUDE.md` ou `AGENTS.md`:

```markdown
## Database
- The database MCP server is read-only. Never ask for write access.
- Schema changes go through migrations in prisma/migrations, never direct DDL.
- Never run UPDATE or DELETE without a WHERE clause.
- Run new queries with EXPLAIN on the dev database before proposing them.
```

### Nunca dê a um agente acesso de escrita à produção

Esta é a regra que não se dobra. Linhas de dados podem conter texto que parece instrução (um ticket de suporte, a bio de um usuário), e um agente que as lê pode segui-las; isso é [prompt injection](/pt/glossary/prompt-injection/ "O que é prompt injection"). Um pedido mal interpretado pode virar um `DELETE` com o filtro errado. Com um usuário somente leitura, o pior caso é uma query lenta. Com acesso de escrita, é uma queda ou perda de dados.

A divisão segura: o agente escreve e testa o SQL com dados de desenvolvimento; você revisa; uma ferramenta de migration ou uma pessoa aplica na produção. [Segurança de agentes de código com IA](/pt/blog/ai-coding-agent-security/ "Segurança de agentes de código com IA") trata de sandbox e permissões de forma mais ampla.

## Fazendo isso no AgentVera

O AgentVera é um app desktop para macOS, Windows e Linux que roda Claude Code, Codex e outros agentes de CLI lado a lado. Alguns recursos foram feitos exatamente para este trabalho:

- **[Gerenciador de banco de dados](/pt/features/database-manager/ "Gerenciador de banco de dados"):** conexões PostgreSQL, MySQL/MariaDB e SQLite na mesma janela dos seus agentes, com uma visão de tabela editável, um editor SQL com `EXPLAIN`, um designer de tabelas que mostra a DDL antes de aplicá-la e um diagrama ER. Conexões marcadas como somente leitura também são abertas em modo somente leitura no lado do servidor, e uma conexão marcada como produção aparece em vermelho, com as alterações pedindo confirmação antes. Você pode deixar os agentes usarem uma conexão pela ferramenta embutida agentvera-db: o acesso vem desligado por padrão, começa em modo somente leitura quando você o liga, os agentes nunca veem a senha e toda query que rodam fica registrada. O gerenciador de banco de dados está nos planos Pro e Team.
- **[DB Guard](/pt/features/db-guard/ "DB Guard"):** quando um agente termina um turno, os arquivos de migration alterados são analisados em busca de riscos como `DROP`, `TRUNCATE`, `UPDATE` ou `DELETE` sem `WHERE`, `CREATE INDEX` sem `CONCURRENTLY`, novas constraints e passos de down faltando. Com uma conexão parecida com a produção selecionada, o risco é dimensionado pelo tamanho real das tabelas. Você pode testar a migration num banco shadow dentro de uma transação que sempre sofre rollback, ou mandar os achados de volta ao agente para corrigir.
- **[Gerenciador de MCP](/pt/features/mcp-manager/ "Gerenciador de MCP"):** configure um servidor MCP de banco uma vez e ele é conectado aos seus agentes a cada inicialização.
- **[Code review](/pt/features/code-review/ "Code review"):** um segundo modelo revisa o código de migrations e queries que o agente escreveu quando o turno dele termina.

[Baixe o AgentVera](/pt/download/ "Baixar o AgentVera") e experimente num banco de desenvolvimento.

## Conclusão

Dê ao agente o schema real e um usuário somente leitura com dados de desenvolvimento. Peça que ele rode `EXPLAIN` e explique o plano, que justifique cada índice e que escreva migrations em passos pequenos e reversíveis de expand and contract, com DDL sem bloqueio. Deixe o ORM gerar as migrations e o agente revisá-las, teste cada uma numa cópia e mantenha as escritas na produção nas suas próprias mãos. Instruções claras facilitam tudo isso; [como escrever prompts para agentes de código com IA](/pt/blog/prompts-for-ai-coding-agents/ "Prompts para agentes de código com IA") aprofunda contexto, planos e critérios de conclusão.

## Perguntas frequentes

**A IA consegue escrever SQL correto?** Muitas vezes, se ela vê o seu schema real e o formato dos dados. A maioria das queries erradas vem de nomes de coluna chutados, joins faltando ou NULLs desconhecidos. Dê ao agente o schema, algumas linhas de exemplo e o resultado esperado, e faça-o rodar a query num banco de desenvolvimento antes de confiar nela.

**É seguro conectar um agente de código ao meu banco de dados?** A um banco de desenvolvimento ou staging com um usuário somente leitura, sim, com cuidado. À produção com acesso de escrita, não. Um agente pode entender mal um pedido, seguir uma instrução injetada nos dados ou rodar um DELETE sem WHERE. Deixe as escritas atrás de uma migration que você revisa e aplica.

**Como passo o schema do meu banco para um agente de IA?** Aponte para o arquivo de schema que o seu ORM mantém (schema.prisma, arquivos de schema do Drizzle, models do Django) ou exporte só a estrutura, por exemplo com pg_dump --schema-only. Um servidor MCP de banco somente leitura também deixa o agente listar tabelas e colunas sozinho.

**Quem deve escrever a migration: a IA ou o ORM?** Deixe o ORM gerar a migration a partir da mudança no model e peça ao agente para revisar o SQL gerado em busca de locks, perda de dados e passos faltando. Escreva SQL cru à mão (ou com o agente) só para o que o ORM não consegue expressar, como índices concorrentes ou backfills de dados.

**O que é o padrão expand and contract?** Uma forma de mudar o schema sem downtime. Primeiro expand: adicione a nova coluna ou tabela ao lado da antiga. Depois migrate: faça deploy de código que escreve nas duas e preencha as linhas antigas. Por fim contract: quando nada mais ler a estrutura antiga, remova-a numa migration posterior.

---

**Sobre o AgentVera.** AgentVera é um app desktop para macOS, Windows e Linux, desenvolvido pela Solviera Teknoloji. Ele roda 18 agentes de programação com IA (Claude Code, Codex, Gemini CLI, Copilot, Cursor, Antigravity, opencode, Hermes, Qwen Code, Kimi Code, Kiro, Amp, Droid, Goose, Vibe, Crush, Aider, Cline) lado a lado, por projeto, em terminais reais com as instalações e logins de CLI do próprio usuário. O plano gratuito tem agentes ilimitados. Baixar: https://agentvera.dev/pt/download/ · Preços: https://agentvera.dev/pt/pricing/
