segunda-feira, 2 de novembro de 2026 IA e tecnologia por Denis Ribeiro
Código Aberto

IA e tecnologia sem enrolação — por Denis Ribeiro

Tutoriais

Qdrant vs Weaviate vs Milvus 2026: escolha pelo time, não por benchmark

Comparação de arquitetura entre Qdrant, Weaviate, Milvus e pgvector em ambiente de produção
Foto: Rafael Minguet Delgado / Pexels

Todo comparativo de qdrant vs weaviate vs milvus que você encontra por aí termina do mesmo jeito: uma tabela de recall@10, QPS e latência em milissegundos, como se escolher banco de dados fosse escolher pneu de carro de corrida. Pgvector perde pro Qdrant em filtros compostos, que perde pro Milvus em volume, que perde pro Weaviate em não sei o quê. No final ninguém conta o que acontece três meses depois, quando a pessoa que configurou o cluster sai da empresa e sobra pra você entender por que o etcd não sobe. Este texto não é sobre qual banco “ganha” no benchmark da vez. É sobre qual banco não vira um problema de operação quando o projeto sai do notebook e vai pra produção.

O comparativo que todo mundo faz (e por que ele não ajuda a decidir nada)

Recall@10 e QPS são métricas boas se você está escrevendo um paper ou comparando índices HNSW puros em condições de laboratório. O problema é que decisão de produção não acontece em laboratório. Acontece com volume de dados crescendo sem aviso, com filtro composto que o PM pediu em cima da hora, com backup que precisa rodar às 3h da manhã sem travar a aplicação.

Nenhum desses benchmarks conta quem no seu time sabe debugar um cluster Raft que ficou sem quórum. Nem quanto tempo leva pra reindexar 50 milhões de vetores depois de trocar o modelo de embedding. Nem o que quebra quando o volume dobra de um mês pro outro. Essas perguntas não aparecem em tabela de recall porque recall mede o algoritmo, não o sistema. E você não vai operar um algoritmo: vai operar um sistema, com disco cheio, rede instável e gente de plantão.

A documentação oficial de cada um desses quatro projetos, aliás, é bem mais honesta sobre isso do que qualquer comparativo de blog. A doc de arquitetura do Milvus, por exemplo, descreve abertamente a separação entre compute e storage e a dependência de componentes externos. Não esconde a complexidade, só assume que você vai precisar dela. É esse tipo de trade-off declarado pelos próprios mantenedores que eu quero usar como critério aqui, não benchmark de marketing.

pgvector: a opção que você já tem rodando (e o que ela sacrifica em troca)

Se você já tem Postgres em produção (e estatisticamente você tem, porque é o banco relacional mais comum em stack de backend no Brasil e fora dele), instalar a extensão pgvector é uma linha de CREATE EXTENSION. Sem novo serviço, sem novo ponto de falha, sem aprender API nova. Você cria uma coluna vector, monta um índice HNSW ou IVFFlat, e já está fazendo busca por similaridade dentro da mesma transação que grava o resto dos seus dados. Isso é ouro operacional: um único backup, um único ponto de observabilidade, um único dia de plantão pra entender tudo.

Um padrão comum é o oposto da cautela: time sobe um protótipo com pgvector, funciona bem com 200 mil vetores, e migra pra um vector DB dedicado “porque é o que todo mundo usa em produção”, sem nunca ter sentido o limite real do Postgres. Isso é trocar simplicidade operacional por complexidade nova sem necessidade comprovada. A documentação do próprio pgvector é clara sobre onde o limite aparece de verdade: construção de índice HNSW é cara em CPU e memória, e em volumes muito grandes (dezenas de milhões de vetores) o tempo de reindexação e o uso de maintenance_work_mem viram gargalo real. Fora isso, pgvector não tem sharding nativo. Se seus dados não cabem numa única instância com réplicas de leitura, você vai ter que resolver particionamento na mão, e aí sim a conversa muda.

Pra filtro simples (WHERE categoria = 'x' AND vetor <-> consulta), o Postgres é excelente, porque você usa SQL normal com todo o planejador de query que já existe há décadas. Pra filtro composto muito dinâmico, com múltiplas combinações de atributos em alta cardinalidade, o otimizador às vezes escolhe mal entre usar o índice vetorial ou o índice relacional. Aí entra ajuste fino que exige entender EXPLAIN ANALYZE de verdade, não é “fire and forget”.

Qdrant: o equilíbrio entre simplicidade de deploy e filtros ricos (até onde vai esse equilíbrio)

Qdrant é escrito em Rust, sobe como binário único ou container, e isso já resolve metade da dor operacional antes de qualquer configuração: não tem dependência externa obrigatória pra rodar em modo single-node. A proposta de valor real dele, segundo a própria documentação, é o modelo de payload indexing. Você anexa metadados estruturados a cada vetor e cria índices específicos pra cada campo de filtro, combinando busca vetorial com filtro booleano complexo sem reescrever a query toda vez.

É o ponto ideal pra quem precisa de filtro rico (tipo “produtos da categoria X, com preço entre Y e Z, da marca W, ordenados por similaridade”) sem o peso de montar uma arquitetura distribuída enorme. Deploy em single-node resolve a maioria dos casos de times pequenos e médios: um container, um volume persistente, snapshot nativo pra backup.

Onde o equilíbrio começa a apertar é na escala horizontal de verdade. Cluster do Qdrant usa Raft pra consenso entre nós, o que é sólido pra consistência, mas significa que você precisa entender conceito de quórum, failover e rebalanceamento de shard quando o cluster cresce. Não é mais só “sobe outro container”. A documentação oficial é transparente sobre isso: sharding e replicação existem, mas operar um cluster multi-nó com consistência forte exige entender o comportamento do Raft sob partição de rede, coisa que não aparece no tutorial de cinco minutos do começo.

Weaviate: o preço do schema-first e do GraphQL quando seu time só quer subir um vetor e consultar

Weaviate vende organização: você define classes, propriedades tipadas, relações entre objetos, tudo antes de inserir o primeiro vetor. Pra quem vem de um mundo mais estruturado, times com forte disciplina de modelagem de dados, isso parece elegância. Em contexto certo, é.

O problema é um cenário recorrente: time escolhe Weaviate justamente pelo schema “organizado”, acha que vai ganhar ordem estrutural de graça, e esbarra em retrabalho toda vez que o formato do dado muda. Mudar o tipo de uma propriedade depois que a classe já está populada não é trivial. Em muitos casos você precisa recriar a classe e reindexar, porque o schema é imposto antes da escrita, não inferido depois dela. Se seu domínio de dado é estável (catálogo de produto bem definido, por exemplo), ótimo. Se seu domínio muda a cada sprint, o que é comum em produto em fase de validação, você vai gastar mais tempo migrando schema do que extraindo valor da busca semântica.

A API em GraphQL, documentada como padrão principal do Weaviate, também traz uma curva de aprendizado que a maioria dos times de backend acostumados a REST simples ou SDK direto não espera. Não é difícil, mas é mais uma camada de abstração entre você e o dado, e cada camada a mais é mais coisa pra debugar quando algo sai errado às 2h da manhã.

Milvus: a escolha de quem já tem equipe de infra dedicada (e um problema pra quem não tem)

Milvus é o banco vetorial pensado pra escala de bilhões de vetores com separação total entre camada de computação e camada de armazenamento. A própria documentação de arquitetura do projeto descreve componentes separados (proxy, query node, data node, index node) coordenados por etcd, com persistência em object storage compatível com S3 (tipicamente MinIO) e mensageria via Pulsar ou Kafka pra log de transações. É uma arquitetura de sistema distribuído de verdade, no mesmo espírito de um Kafka ou um Elasticsearch em cluster grande.

O padrão que se repete com frequência incômoda: time pequeno escolhe Milvus pela fama, porque aparece em todo artigo de “melhores vector databases” e tem número de estrela alto no GitHub, e descobre meses depois que não tem ninguém na equipe que saiba operar etcd em produção, muito menos diagnosticar um Pulsar engasgado consumindo I/O de disco além da conta. Isso não é defeito do Milvus. É descompasso entre a ferramenta e o time. Milvus foi desenhado pra quem já opera sistemas distribuídos como rotina e tem gente de plantão pra isso. Pra esse perfil, a arquitetura é uma vantagem gigante de escala horizontal real. Pra time de três devs full-stack cuidando de um SaaS, é um fardo de operação que ninguém pediu.

Existe a opção gerenciada (Zilliz Cloud, dos próprios criadores do Milvus) que tira boa parte dessa dor. Se a escala realmente exige Milvus, geralmente faz mais sentido pagar por isso do que montar a stack na mão.

A pergunta que decide tudo antes de qualquer benchmark: quem vai dar suporte a isso em produção

Antes de rodar qualquer teste de performance, vale olhar pra tabela abaixo e responder honestamente onde seu time se encaixa.

Critério pgvector Qdrant Weaviate Milvus
Dependência externa de infra Nenhuma (usa Postgres existente) Nenhuma obrigatória (binário único) Nenhuma obrigatória etcd + object storage + Pulsar/Kafka
Modelo de filtro SQL nativo (WHERE) Payload index dedicado Schema tipado + GraphQL Filtro em schema + partição
Escala horizontal nativa Não (particionamento manual) Sim, via Raft Sim, via sharding Sim, arquitetura distribuída desde o design
Esforço de reindexação em escala Alto acima de dezenas de milhões de vetores Moderado Moderado a alto quando schema muda Baixo (pensado pra isso)
Perfil de time ideal Time pequeno, já opera Postgres Time pequeno/médio, precisa de filtro rico Time com disciplina de modelagem de dado estável Time com infra dedicada e rotina de SRE

Se seu time tem menos de cinco pessoas de infra e seu volume está abaixo de alguns milhões de vetores, comece com pgvector. Sério. É a decisão mais chata e mais correta na maioria dos casos. Você só vai saber se precisa de mais quando sentir o limite de verdade, não antes.

Se você precisa de filtro composto rico e não quer administrar um ecossistema de três a quatro serviços externos, Qdrant é o ponto de equilíbrio mais razoável pra quem tem alguma maturidade de operação mas não tem squad de SRE dedicado.

Se seu domínio de dado é estável e seu time já pensa em schema antes de escrever código, típico de quem vem de forte disciplina de modelagem relacional, Weaviate paga o preço do schema-first com organização de longo prazo. Se seu dado muda toda semana, foge.

Se você tem gente que já opera Kafka, etcd ou Kubernetes em produção como rotina, e seu volume já está na casa das centenas de milhões ou bilhões de vetores, Milvus (ou sua versão gerenciada) é a ferramenta certa pro problema certo. Fora desse perfil, é complexidade que você importa sem precisar, e isso vale tanto pra pgvector quanto pra qualquer um dos outros três quando a escolha é feita por moda e não por necessidade real.

Fontes consultadas

  • Milvus (documentação oficial): Milvus Architecture Overview. link
  • Qdrant (documentação oficial): Indexing. link
  • Qdrant (documentação oficial): Horizontal Scaling. link
  • Qdrant (documentação oficial): Resilience. link
  • pgvector (GitHub oficial): pgvector, Open-source vector similarity search for Postgres. link
  • Weaviate (documentação oficial): Data structure. link
Publicidade