Database Vettoriali a Confronto: Eseguire la Stessa Pipeline RAG su pgvector, Qdrant, Pinecone e Weaviate
Il Setup dei Test
Dataset: 2,3M chunk di documenti da una base di conoscenza per supporto clienti. Dimensione media del chunk: 512 token. Embedded con text-embedding-3-small (1536 dimensioni).
Query: 10.000 query reali di utenti raccolte dai log di produzione (anonimizzate). Mix di brevi ("reset password"), medie ("come configurare SSO con Azure AD") e lunghe ("il nostro team sta migrando da on-premise a cloud e dobbiamo capire le implicazioni della residenza dei dati per la conformità GDPR").
Hardware:
- pgvector: RDS
db.r7g.xlarge(4 vCPU, 32GB RAM), PostgreSQL 16 con pgvector 0.8 - Qdrant: cluster 3 nodi su
c7g.xlarge(4 vCPU, 8GB RAM ciascuno), Qdrant 1.13 - Pinecone: Serverless (Standard), us-east-1
- Weaviate: cluster 3 nodi su
c7g.xlarge, Weaviate 1.28
Ricerca: Top-10 vicini più prossimi, similarità coseno, con filtro metadati (categoria = valore specifico, riducendo i candidati del ~80%).
Numeri Grezzi: Latenza e Throughput
Latenza Query (10K query, ms)
| Database | p50 | p95 | p99 | p99.9 |
|---|---|---|---|---|
| pgvector (HNSW) | 8,2 | 14,1 | 22,3 | 41,7 |
| pgvector (IVF) | 12,4 | 24,8 | 38,1 | 67,2 |
| Qdrant | 3,1 | 5,8 | 8,4 | 14,2 |
| Pinecone Serverless | 18,4 | 32,1 | 48,7 | 142,3 |
| Weaviate | 5,7 | 11,2 | 18,9 | 33,4 |
Qdrant vince sulla latenza grezza, e non di poco. Il loro engine basato su Rust con storage memory-mapped è genuinamente veloce. Ma guarda il p99.9 di Pinecone — quei 142ms di coda sono il cold start serverless che ti morde. Per applicazioni interattive, quella coda è un problema.
pgvector con HNSW è sorprendentemente competitivo. Con 8,2ms di p50, è abbastanza veloce per qualsiasi applicazione RAG. Il divario si allarga nella coda, ma per la maggior parte dei casi d'uso, è più che adeguato.
Throughput (query/secondo, 100 connessioni concorrenti)
| Database | QPS (senza filtro) | QPS (con filtro) | Delta |
|---|---|---|---|
| pgvector (HNSW) | 2.840 | 2.120 | -25,4% |
| Qdrant | 8.420 | 7.180 | -14,7% |
| Pinecone | 1.200 | 980 | -18,3% |
| Weaviate | 4.100 | 3.250 | -20,7% |
La differenza di performance con il filtraggio è rivelatrice. pgvector perde il 25% di throughput con i filtri perché li applica post-ricerca HNSW (una limitazione nota). Qdrant integra il filtraggio nell'algoritmo di ricerca, quindi la penalità è minore. Weaviate si colloca a metà strada.
Il tetto di throughput di Pinecone è notevolmente più basso di quanto ci si aspetterebbe per un servizio managed. L'architettura serverless privilegia l'ottimizzazione del costo per query rispetto al throughput grezzo.
HNSW vs IVF: Quando Vince Ciascuno
pgvector 0.8 supporta sia indici HNSW che IVF-Flat. La scelta conta più di quanto la maggior parte delle persone realizzi.
HNSW (Hierarchical Navigable Small World)
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 256);
-- Al momento della query
SET hnsw.ef_search = 100;
Pro: Query veloci, recall elevato, nessun passo di addestramento Contro: Alto uso di memoria (~1,5x i dati vettoriali), build degli indici lenti
Tempo di build HNSW per 2,3M vettori a 1536 dimensioni: 47 minuti sulla nostra istanza RDS. Uso memoria: 14,2GB solo per l'indice.
IVF-Flat (Inverted File con quantizzazione Flat)
CREATE INDEX ON documents
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 1500);
-- Al momento della query
SET ivfflat.probes = 40;
Pro: Uso di memoria inferiore (~0,3x), build degli indici più veloci Contro: Richiede addestramento (il parametro lists necessita tuning), recall inferiore alla stessa latenza
Tempo di build IVF: 12 minuti. Memoria: 4,1GB. Ma il recall alla stessa latenza era 91,2% vs 97,8% di HNSW.
Raccomandazione
Usare HNSW a meno che la memoria sia il vincolo principale. La differenza di recall (97,8% vs 91,2%) significa che per ogni 100 query, IVF manca ~7 risultati rilevanti che HNSW trova. In una pipeline RAG, quei chunk mancati impattano direttamente la qualità delle risposte.
Quantizzazione: Il Tradeoff Memoria vs Qualità
Con 2,3M vettori a 1536 dimensioni (float32), i dati vettoriali grezzi sono circa 13,4GB. La quantizzazione riduce questo drammaticamente:
pgvector: halfvec (float16)
-- pgvector 0.8 supporta halfvec nativamente
ALTER TABLE documents
ALTER COLUMN embedding TYPE halfvec(1536);
CREATE INDEX ON documents
USING hnsw (embedding halfvec_cosine_ops);
Riduzione memoria: 50%. Impatto sul recall: -0,8% (trascurabile). Questo è una scelta evidente per gli utenti pgvector.
Qdrant: Quantizzazione Binaria con Rescoring
{
"collection_name": "documents",
"vectors": {
"size": 1536,
"distance": "Cosine",
"quantization_config": {
"binary": {
"always_ram": true
}
}
}
}
La quantizzazione binaria riduce ogni float32 a un singolo bit. 32x di riduzione memoria. Ma il recall grezzo scende a ~85%. Il trucco è il rescoring: Qdrant prima cerca nell'indice binario per ottenere un set di candidati (diciamo, top-100), poi rivaluta quei candidati contro i vettori a precisione piena. Recall finale: 94,7% con una frazione della memoria.
Nei test di benchmark:
| Modalità Qdrant | Memoria | Latenza p50 | Recall@10 |
|---|---|---|---|
| Precisione piena | 14,8GB | 3,1ms | 98,2% |
| Binario (senza rescore) | 0,46GB | 1,2ms | 84,9% |
| Binario + rescore 100 | 0,46GB + 14,8GB disco | 4,8ms | 94,7% |
| Scalare (int8) | 3,7GB | 2,8ms | 96,1% |
La quantizzazione scalare (int8) è il punto ottimale per la maggior parte dei workload: 75% di riduzione memoria con solo il 2,1% di perdita di recall.
La Questione della Ricerca Ibrida
Le pipeline RAG reali non fanno solo ricerca vettoriale. Serve matching di keyword, filtraggio metadati, e spesso entrambi combinati.
pgvector: Il Vantaggio Sleale
WITH vector_results AS (
SELECT id, content,
1 - (embedding <=> $1::vector) AS vector_score
FROM documents
WHERE category = $2
ORDER BY embedding <=> $1::vector
LIMIT 20
),
text_results AS (
SELECT id, content,
ts_rank(search_vector, plainto_tsquery($3)) AS text_score
FROM documents
WHERE category = $2
AND search_vector @@ plainto_tsquery($3)
LIMIT 20
)
SELECT COALESCE(v.id, t.id) AS id,
COALESCE(v.content, t.content) AS content,
COALESCE(v.vector_score, 0) * 0.7 +
COALESCE(t.text_score, 0) * 0.3 AS combined_score
FROM vector_results v
FULL OUTER JOIN text_results t ON v.id = t.id
ORDER BY combined_score DESC
LIMIT 10;
Questa è la caratteristica più significativa di pgvector: ricerca ibrida in una singola query, con tutta la potenza del query planner di PostgreSQL. Nessuna orchestrazione esterna, nessun indice keyword separato, nessuna fusione risultati nel codice applicativo.
Weaviate: Ibrido Built-in
{
Get {
Document(
hybrid: {
query: "configurazione SSO Azure AD"
alpha: 0.7
fusionType: relativeScoreFusion
}
where: {
path: ["category"]
operator: Equal
valueText: "authentication"
}
limit: 10
) {
content
_additional { score }
}
}
}
Weaviate ha la migliore storia di ricerca ibrida tra i database vettoriali dedicati. Il parametro alpha controlla il peso vettoriale vs keyword.
Analisi dei Costi (La Parte Che Decide)
Per 2,3M vettori a 1536 dimensioni, in esecuzione 24/7:
| Database | Costo Mensile | Note |
|---|---|---|
| pgvector (RDS r7g.xlarge) | $412 | Include calcolo + storage |
| pgvector (Neon Pro) | $69-190 | Scala a zero, paga per query |
| pgvector (Supabase Pro) | $75-200 | Include altre feature Postgres |
| Qdrant Cloud (3 nodi) | $720 | Cluster dedicato |
| Qdrant (self-hosted EC2) | $390 | 3x c7g.xlarge |
| Pinecone Serverless | $280-650 | Dipende dal volume di query |
| Weaviate Cloud | $580 | Managed 3 nodi |
pgvector su Neon o Supabase è assurdamente economico per workload piccoli-medi. E poiché è solo Postgres, non stai pagando per un servizio separato — i tuoi vettori vivono accanto ai tuoi dati relazionali.
Per workload ad alto throughput (>1000 QPS sostenuto), Qdrant self-hosted su istanze ARM è il vincitore nel rapporto prezzo-prestazioni.
Il pricing serverless di Pinecone è attraente a bassi volumi ma scala in modo imprevedibile. In un caso, i pattern di query sono cambiati e la fattura è saltata di 2,3x.
Raccomandazioni Pratiche
Per la maggior parte delle startup e MVP: pgvector su Supabase o Neon. Hai un database vettoriale e un database relazionale in uno. La ricerca ibrida funziona immediatamente. La latenza è abbastanza buona. Puoi sempre migrare dopo se lo superi, e in pratica, la maggior parte dei prodotti non lo farà mai.
Per produzione ad alto throughput e sensibile alla latenza: Qdrant. L'engine Rust è genuinamente più veloce, le opzioni di quantizzazione ti danno controllo fine sul tradeoff memoria/recall, e il filtraggio è ben integrato. Self-hostalo su istanze Graviton per il miglior rapporto prezzo-prestazioni.
Per team che vogliono tutto managed e non si preoccupano del costo: Pinecone. Funziona, è semplice, e non devi pensare all'infrastruttura. Sappi solo che stai pagando un premium per quella semplicità, e i cold start serverless ti morderanno.
Per applicazioni heavy in ricerca ibrida: Weaviate se vuoi un DB vettoriale dedicato, pgvector se vuoi la flessibilità di SQL.
La Verità Scomoda
Ecco cosa nessuno nello spazio dei database vettoriali vuole ammettere: per il 90% delle applicazioni RAG, pgvector è sufficiente. I database vettoriali dedicati sono più veloci, ma "più veloce" significa 3ms vs 8ms — entrambi sono invisibili per l'utente finale che sta aspettando 800ms perché l'LLM generi una risposta.
Il vero differenziatore è a scala (>10M vettori), a throughput estremo (>5000 QPS), o quando serve latenza p99 sotto i 5ms per applicazioni in tempo reale. Se sei tu, Qdrant o Weaviate valgono la complessità operativa. Se non lo sei — ed essere onesti se lo è — usa semplicemente pgvector e dedica il tuo tempo di ingegneria a ciò che realmente sposta l'ago: migliori strategie di chunking, migliori prompt e migliore valutazione.
La scelta noiosa è spesso quella giusta.