← Voltar para o Blog

pgvector ou banco vetorial dedicado: escolhendo pelo seu volume

A resposta honesta é que na maioria dos projetos o Postgres que você já tem resolve. Onde está a fronteira, o que muda ao cruzá-la, e como não descobrir isso tarde demais.

Equipe EasyOps Cloud · · 7 min de leitura

Todo projeto de busca semântica passa pela mesma decisão logo no começo: usar a extensão pgvector no Postgres que já existe, ou subir um banco vetorial dedicado.

A resposta que a maioria dos artigos dá é "depende". A resposta mais útil é que, para a esmagadora maioria dos projetos brasileiros que vejo, o Postgres resolve — e adicionar mais um banco à infraestrutura antes de precisar cobra um custo operacional que raramente é contabilizado.

O que vale é saber onde está a fronteira, para reconhecer quando ela for cruzada.

O que muda entre um e outro

Bancos dedicados são construídos em torno de uma única operação: encontrar os vizinhos mais próximos em um espaço de muitas dimensões. Eles otimizam layout de memória, compressão de vetor e paralelismo para isso.

O pgvector acrescenta essa capacidade a um banco relacional que já faz muitas outras coisas. O ganho é enorme em outra dimensão: o vetor fica na mesma linha que o resto do dado.

Essa diferença é mais importante do que parece. Com pgvector, uma busca semântica filtrada por cliente, por data e por status é uma consulta SQL comum:

SELECT id, titulo, conteudo,
       embedding <=> $1 AS distancia
FROM documentos
WHERE cliente_id = $2
  AND publicado_em > now() - interval '1 year'
  AND status = 'ativo'
ORDER BY embedding <=> $1
LIMIT 10;

Uma transação, um lugar, consistência garantida. Com banco separado, o mesmo resultado exige manter os metadados sincronizados nos dois sistemas — e sincronia entre bancos é a fonte de bug mais chata que existe: o documento apagado no Postgres que continua aparecendo na busca.

Os números que definem a fronteira

Como referência aproximada, em hardware modesto e sem GPU:

Volume de vetoresRecomendação
até ~1 milhãopgvector, com folga
1 a 10 milhõespgvector com índice bem ajustado, ou dedicado
acima de 10 milhõesBanco dedicado tende a compensar

O que empurra para o dedicado não é só a contagem. Três sinais valem mais:

  • O índice não cabe na memória. É o critério decisivo, e dá para calcular.
  • Busca concorrente alta. Dezenas de consultas por segundo simultâneas com outras cargas no mesmo Postgres começam a competir por recurso.
  • Necessidade de recursos específicos — busca híbrida nativa, múltiplos vetores por registro, quantização agressiva.

Vale dizer o óbvio que costuma ser esquecido: a maioria das bases de conhecimento corporativas tem dezenas de milhares de trechos, não milhões. Uma documentação inteira de produto, com todos os manuais, raramente passa de 100 mil vetores.

A conta de memória, que é a que importa

O tamanho do índice é previsível e vale calcular antes de escolher.

Um vetor de 1536 dimensões em ponto flutuante de 4 bytes ocupa cerca de 6 KB. Um milhão deles são aproximadamente 6 GB só de vetores, antes do índice.

O índice HNSW, que é o padrão para busca aproximada, acrescenta as conexões entre vizinhos — de 30% a 50% a mais. Chegamos a algo em torno de 8 a 9 GB para um milhão de vetores.

A regra prática: o índice precisa caber na RAM. Se ele não couber, cada busca vira leitura de disco e o tempo de resposta sai de milissegundos para segundos.

Isso dá uma alavanca óbvia de custo: reduzir a dimensão do embedding. Modelos que produzem 384 ou 768 dimensões cortam o consumo pela metade ou por um quarto, com perda de qualidade que em muitas tarefas é imperceptível. Vale testar antes de dimensionar máquina maior — é a otimização de melhor retorno nesse tema.

CREATE INDEX ON documentos
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

E ajuste a memória de trabalho do Postgres, ou a criação do índice fica insuportavelmente lenta:

SET maintenance_work_mem = '2GB';

O erro que faz o pgvector parecer ruim

Existe uma armadilha específica que leva muita gente a concluir, erradamente, que pgvector não escala.

Quando você combina filtro restritivo com busca vetorial, o planejador pode decidir usar o índice do filtro e varrer os vetores um a um. Ou usar o índice vetorial e descartar quase tudo pelo filtro depois. Nos dois casos, a consulta que respondia em 20 ms passa a levar segundos.

EXPLAIN ANALYZE
SELECT id FROM documentos
WHERE cliente_id = 42
ORDER BY embedding <=> $1 LIMIT 10;

Se aparecer Seq Scan no plano, é isso. As saídas:

  • Aumentar o `ef_search` para que a busca aproximada recupere mais candidatos antes do filtro:
SET hnsw.ef_search = 100;
  • Índice parcial por cliente, quando o número de clientes é pequeno e estável.
  • Particionar a tabela pelo campo mais usado no filtro.

Esse ajuste resolve a esmagadora maioria dos casos em que alguém concluiu que precisava trocar de banco.

Quando a busca vetorial não é a resposta

Uma constatação que economiza muito trabalho: parte relevante das buscas que motivaram o projeto seria melhor atendida por busca textual comum.

Busca vetorial encontra o que é semanticamente parecido. Ela é excelente para "documento sobre cancelamento de contrato" e ruim para "nota fiscal 84213", código de produto, nome próprio raro ou número de protocolo — casos em que o usuário quer correspondência exata e a similaridade semântica devolve dez documentos parecidos e nenhum certo.

O Postgres faz as duas coisas, o que é mais um argumento a favor de manter tudo no mesmo lugar:

-- Busca textual em português, com índice próprio
CREATE INDEX ON documentos
USING gin (to_tsvector('portuguese', conteudo));

SELECT id, titulo
FROM documentos
WHERE to_tsvector('portuguese', conteudo)
      @@ plainto_tsquery('portuguese', $1)
LIMIT 10;

A abordagem híbrida executa as duas buscas e combina os resultados, tipicamente intercalando por posição em cada lista. Ela costuma superar qualquer uma das duas isoladamente, e é o padrão em sistemas maduros de recuperação.

Vale começar por aí antes de investir em afinar embeddings: uma busca híbrida simples com pgvector e tsvector entrega mais qualidade percebida que trocar de modelo de embedding, e não adiciona nenhuma peça nova à infraestrutura.

O custo operacional de mais um banco

Se a decisão for pelo dedicado, conte o que ela traz junto: mais um serviço para manter atualizado, mais um backup para configurar e testar, mais um ponto de falha, mais uma credencial para gerenciar, e a sincronia entre os dois sistemas.

Nada disso é impeditivo. É trabalho, e trabalho recorrente. Para equipe pequena, esse custo frequentemente supera o ganho de desempenho que motivou a mudança.

Se for esse o caminho, vale isolar o serviço em máquina própria — a memória dedicada ao índice não deve disputar com o banco relacional — e incluir o novo volume na rotina de teste de restauração. Índice vetorial é reconstruível a partir dos textos originais, o que é uma vantagem: em caso de perda, o que precisa mesmo estar no backup são os documentos e os embeddings, não o índice.

Como decidir sem se arrepender

  • Comece com `pgvector`, mesmo que o plano de longo prazo seja outro. O custo de começar é quase zero e você aprende com dado real.
  • Meça o tamanho do índice e compare com a RAM disponível. Esse é o gatilho objetivo para reavaliar.
  • Guarde os embeddings, não só os textos. Recalcular um milhão de vetores custa tempo e dinheiro; migrar de banco com os vetores em mãos é uma cópia.
  • Isole a camada de busca no seu código atrás de uma interface. Se a troca vier, ela deve tocar um arquivo, não a aplicação inteira.

O resto da infraestrutura — pipeline de ingestão, estratégia de fragmentação, reindexação — pesa muito mais no resultado final que a escolha do banco, e é o que o artigo sobre infraestrutura para RAG cobre em detalhe. Trocar de banco vetorial não conserta um pipeline que fragmenta mal o texto.

Vale encerrar com a constatação que motivou este texto. A escolha do banco vetorial é, quase sempre, a decisão menos importante do projeto — e é a que consome mais tempo de discussão, porque é a única que se resolve comparando tabelas de características. As decisões que determinam se a busca vai funcionar são outras: como o texto é dividido, o que entra nos metadados, como o resultado é reordenado antes de chegar ao modelo, e o que acontece quando nada relevante é encontrado.

Se o tempo de análise for limitado, gaste-o ali. O banco pode ser trocado depois com relativa facilidade; um pipeline mal desenhado exige reindexar tudo e, pior, costuma só dar sinal de que está errado quando o usuário reclama do resultado.

Suba um servidor em minutos

Preço em real, suporte em português e dados no Brasil.

Criar conta