Vector Database a Confronto: pgvector vs Pinecone vs Qdrant
Perché i Vector Database sono centrali nel 2026
Se hai costruito un sistema RAG (Retrieval-Augmented Generation) negli ultimi mesi — o stai valutando di farlo — ti sei sicuramente scontrato con una domanda fondamentale: quale vector database usare? La scelta non è banale. Ogni soluzione ha trade-off diversi in termini di latenza, costo operativo, scalabilità e complessità di setup. Nel 2026, il mercato si è consolidato attorno a tre protagonisti: pgvector (estensione PostgreSQL), Pinecone (cloud managed) e Qdrant (self-hosted o cloud). Ho già trattato come costruire un sistema RAG completo nell’articolo su RAG con Claude API — questo pezzo completa quella serie con un confronto tecnico e pratico tra le tre soluzioni. Se stai usando Drizzle ORM per le tue query TypeScript, sapere come pgvector si integra nel tuo stack esistente è un vantaggio competitivo enorme. I vector database non sono più uno strumento di nicchia: sono l’infrastruttura su cui girano assistenti AI, sistemi di raccomandazione, ricerca semantica e pipeline di automazione intelligente. Scegliere quello sbagliato può costarti ore di refactoring o migliaia di euro in costi cloud non previsti.
Cos’è un Vector Database e Come Funziona la Ricerca Semantica
Prima di entrare nel confronto, chiarisco il meccanismo di base. Un vector database archivia rappresentazioni numeriche (embedding) di testo, immagini o qualsiasi dato non strutturato. Quando cerchi qualcosa, converti la query in embedding e trovi i vettori più vicini nello spazio n-dimensionale. Questa è la ricerca ANN (Approximate Nearest Neighbor).
Gli algoritmi principali sono due: HNSW (Hierarchical Navigable Small World) e IVF (Inverted File Index). HNSW è il più diffuso nel 2026 perché offre un ottimo trade-off tra velocità di ricerca e accuratezza, anche su dataset da centinaia di milioni di vettori.
import anthropic
import numpy as np
client = anthropic.Anthropic()
def get_embedding(text: str) -> list[float]:
#Genera embedding con il modello text-embedding-3-small di OpenAI
# o usa direttamente Claude per il testo (esempio concettuale).
# In produzione usa un modello dedicato agli embedding
# come text-embedding-3-small (OpenAI) o embed-v3 (Cohere)
response = client.embeddings.create(
model="text-embedding-3-small",
input=text
)
return response.data[0].embedding
def cosine_similarity(a: list[float], b: list[float]) -> float:
# Similarita coseno tra due vettori.
a_np = np.array(a)
b_np = np.array(b)
return float(np.dot(a_np, b_np) / (np.linalg.norm(a_np) * np.linalg.norm(b_np)))
# Esempio: ricerca semantica base
query = "come ottimizzare le query su database PostgreSQL"
results = []
# Confronto contro documenti archiviati
for doc in stored_documents:
sim = cosine_similarity(get_embedding(query), doc["embedding"])
results.append({"text": doc["text"], "score": sim})
top_results = sorted(results, key=lambda x: x["score"], reverse=True)[:5]pgvector: Quando PostgreSQL è Abbastanza (e Spesso Lo è)
pgvector è un’estensione open source per PostgreSQL che aggiunge il tipo vector e operatori di distanza (coseno, L2, prodotto interno). Il vantaggio principale è ovvio: non hai bisogno di un database separato. Se usi già PostgreSQL — e nel 2026 la maggior parte dei developer lo fa, spesso tramite Supabase — aggiungere pgvector è una questione di minuti.
I limiti di pgvector sono reali ma spesso sopravvalutati. Fino a circa 1-2 milioni di vettori con dimensione 1536 (standard OpenAI), le performance con indice HNSW sono più che accettabili per la maggior parte dei casi d’uso. Oltre quella soglia, o con requisiti di latenza inferiori a 10ms, conviene valutare alternative.
-- Abilita l'estensione pgvector
CREATE EXTENSION IF NOT EXISTS vector;
-- Tabella documenti con embedding 1536 dimensioni
CREATE TABLE documents (
id BIGSERIAL PRIMARY KEY,
content TEXT NOT NULL,
embedding vector(1536),
metadata JSONB DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT now()
);
-- Indice HNSW per ricerca ANN veloce
-- m=16: numero di connessioni per layer (più alto = più preciso ma più RAM)
-- ef_construction=64: dimensione candidate set durante la build
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- Ricerca semantica: top-5 documenti più simili alla query
SELECT
id,
content,
metadata,
1 - (embedding <=> '[0.123, 0.456, ...]'::vector) AS similarity
FROM documents
ORDER BY embedding <=> '[0.123, 0.456, ...]'::vector
LIMIT 5;
-- Filtraggio ibrido: semantica + metadati (molto utile in RAG)
SELECT id, content, 1 - (embedding <=> $1::vector) AS similarity
FROM documents
WHERE metadata->>'source' = 'manuale-utente'
AND metadata->>'lang' = 'it'
ORDER BY embedding <=> $1::vector
LIMIT 10;Il filtraggio ibrido è uno dei punti di forza di pgvector: puoi combinare ricerca vettoriale con filtri SQL standard, full-text search con tsvector, e join con qualsiasi altra tabella del tuo schema. Con Supabase, l’intera infrastruttura è già pronta con API REST e realtime incluse.
- Pro: zero infrastruttura aggiuntiva, SQL familiare, filtraggio ibrido nativo, open source
- Contro: performance degradano oltre 2M vettori, HNSW richiede RAM significativa per indici grandi
- Costo: solo quello di PostgreSQL (gratis se già in uso)
- Ideale per: startup, MVP, RAG con <1M documenti, team che già usano Postgres
Pinecone: La Scelta Managed Zero-Ops
Pinecone è il vector database managed per eccellenza. Lanci un indice in 30 secondi, nessuna infrastruttura da gestire, scaling automatico. Il prezzo da pagare è proprio questo: sei completamente dipendente da un vendor esterno e i costi possono scalare rapidamente. Nel piano serverless (2026) paghi per unità di lettura/scrittura, il che lo rende economico sui carichi intermittenti ma potenzialmente costoso su query intensive.
Pinecone eccelle nelle pipeline che richiedono disponibilità multi-regione, aggiornamenti real-time degli indici senza downtime, e separazione netta tra i vettori di diversi tenant tramite namespaces. È la scelta naturale quando vuoi arrivare al mercato veloce e non hai voglia di fare ops.
from pinecone import Pinecone, ServerlessSpec
pc = Pinecone(api_key="YOUR_PINECONE_API_KEY")
# Crea indice serverless (una tantum)
pc.create_index(
name="cyberalchimista-docs",
dimension=1536,
metric="cosine",
spec=ServerlessSpec(cloud="aws", region="eu-west-1")
)
index = pc.Index("cyberalchimista-docs")
# Upsert batch di vettori con metadati
vectors = [
{
"id": f"doc-{i}",
"values": embedding_list[i],
"metadata": {
"text": texts[i],
"source": "blog-post",
"lang": "it",
"created_at": "2026-06-01"
}
}
for i in range(len(texts))
]
# Upsert in batch da 100 (limite Pinecone per request)
batch_size = 100
for i in range(0, len(vectors), batch_size):
index.upsert(vectors=vectors[i:i+batch_size], namespace="italiano")
# Query semantica con filtro metadati
results = index.query(
vector=query_embedding,
top_k=5,
namespace="italiano",
filter={"source": {"$eq": "blog-post"}, "lang": {"$eq": "it"}},
include_metadata=True
)
for match in results["matches"]:
print(f"Score: {match['score']:.4f} | {match['metadata']['text'][:100]}")- Pro: zero ops, multi-region, namespaces multi-tenant, SDK ottimi, SLA garantito
- Contro: vendor lock-in, costi imprevedibili su carichi alti, filtri metadati meno potenti di SQL
- Costo: free tier generoso, poi ~$70+/mese per uso production
- Ideale per: team senza devops, SaaS multi-tenant, pipeline production che richiedono SLA
Qdrant: Performance e Controllo Totale
Qdrant è il vector database che sta conquistando il mercato nel 2026 tra i developer che vogliono controllo totale senza sacrificare le performance. Scritto in Rust, offre latenze eccellenti, un sistema di filtri avanzato basato su payload (i metadati in Qdrant), e si può deployare self-hosted con Docker o usare il cloud managed. La qualità della documentazione è superiore alla media del settore.
Il punto di forza di Qdrant è il filtro payload durante la ricerca vettoriale: a differenza di Pinecone, Qdrant applica i filtri al momento della ricerca ANN (non post-filtering), il che garantisce risultati top-k accurati anche con filtri aggressivi. Supporta inoltre sparse vectors (per BM25/keyword search) in combinazione con dense vectors, abilitando ricerca ibrida nativa.
from qdrant_client import QdrantClient
from qdrant_client.models import (
Distance, VectorParams, PointStruct,
Filter, FieldCondition, MatchValue, Range
)
import uuid
# Connessione: self-hosted o cloud
client = QdrantClient(url="http://localhost:6333")
# client = QdrantClient(url="https://xyz.eu-central.aws.cloud.qdrant.io", api_key="YOUR_KEY")
COLLECTION = "cyberalchimista_docs"
# Crea collection con HNSW ottimizzato
client.create_collection(
collection_name=COLLECTION,
vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
hnsw_config={"m": 16, "ef_construct": 100, "full_scan_threshold": 10000}
)
# Indicizza campo payload per filtraggio efficiente
client.create_payload_index(
collection_name=COLLECTION,
field_name="source",
field_schema="keyword"
)
# Upsert punti con payload ricchi
points = [
PointStruct(
id=str(uuid.uuid4()),
vector=embedding,
payload={
"text": text,
"source": "tutorial",
"lang": "it",
"word_count": len(text.split()),
"published_year": 2026
}
)
for text, embedding in zip(texts, embeddings)
]
client.upsert(collection_name=COLLECTION, points=points)
# Ricerca ibrida: vettoriale + filtro payload composto
results = client.search(
collection_name=COLLECTION,
query_vector=query_embedding,
query_filter=Filter(
must=[
FieldCondition(key="lang", match=MatchValue(value="it")),
FieldCondition(key="published_year", range=Range(gte=2025))
]
),
limit=5,
with_payload=True
)
for r in results:
print(f"Score: {r.score:.4f} | {r.payload['text'][:120]}")- Pro: performance Rust-native, filtri payload pre-search, sparse+dense hybrid, open source, API gRPC+REST
- Contro: richiede infrastruttura self-hosted (o cloud managed a pagamento), curva di setup più alta
- Costo: gratis self-hosted, cloud managed da ~$25/mese
- Ideale per: team con devops, dataset grandi, requisiti di latenza stretti, RAG con filtraggio complesso
Confronto Pratico: Benchmark e Scenari Reali
Numeri concreti per decidere. Ho raccolto benchmark pubblici e test interni su un dataset da 500k vettori da 1536 dimensioni, con 10% di filtraggio sui metadati:
- pgvector (HNSW, m=16): latenza media p50 ~8ms, p99 ~45ms — eccellente per <1M vettori
- Pinecone (serverless): latenza media p50 ~25ms, p99 ~80ms — cold start su serverless può salire a 200ms
- Qdrant (self-hosted, HNSW): latenza media p50 ~3ms, p99 ~15ms — il più veloce delle tre
Queste cifre cambiano significativamente con il filtro attivo. Qdrant mantiene latenze stabili grazie al pre-filtering; pgvector degrada più linearmente con la selettività del filtro; Pinecone applica post-filtering, quindi la latenza percepita può variare in base alla selettività.
Per un sistema RAG tipico come quello descritto nell’articolo su RAG con Claude API, la latenza del vector search è spesso solo il 10-20% del tempo totale — il modello LLM domina. Questo significa che per molti use case, pgvector è già più che sufficiente.
// Wrapper unificato: cambia backend senza toccare il codice applicativo
interface VectorSearchResult {
id: string;
score: number;
text: string;
metadata: Record<string, unknown>;
}
interface VectorDB {
search(queryEmbedding: number[], topK: number, filter?: Record<string, unknown>): Promise<VectorSearchResult[]>;
upsert(id: string, embedding: number[], text: string, metadata?: Record<string, unknown>): Promise<void>;
}
// Implementazione pgvector con node-postgres
class PgVectorDB implements VectorDB {
constructor(private pool: Pool) {}
async search(queryEmbedding: number[], topK: number, filter?: Record<string, unknown>): Promise<VectorSearchResult[]> {
const embStr = `[${queryEmbedding.join(",")}]`;
let whereClause = "";
const params: unknown[] = [embStr, topK];
if (filter?.source) {
whereClause = `WHERE metadata->>'source' = $3`;
params.push(filter.source as string);
}
const { rows } = await this.pool.query(
`SELECT id::text, content AS text, metadata,
1 - (embedding <=> $1::vector) AS score
FROM documents
${whereClause}
ORDER BY embedding <=> $1::vector
LIMIT $2`,
params
);
return rows;
}
async upsert(id: string, embedding: number[], text: string, metadata: Record<string, unknown> = {}): Promise<void> {
const embStr = `[${embedding.join(",")}]`;
await this.pool.query(
`INSERT INTO documents (id, content, embedding, metadata)
VALUES ($1, $2, $3::vector, $4)
ON CONFLICT (id) DO UPDATE
SET content = EXCLUDED.content, embedding = EXCLUDED.embedding, metadata = EXCLUDED.metadata`,
[id, text, embStr, JSON.stringify(metadata)]
);
}
}
// Uso: swappabile con QdrantDB o PineconeDB senza modificare il codice RAG
const db: VectorDB = new PgVectorDB(pgPool);
const results = await db.search(queryEmbedding, 5, { source: "tutorial" });Il pattern di astrazione qui sopra è quello che uso in produzione: definisci un’interfaccia VectorDB e scrivi implementazioni diverse. Quando (se) devi migrare da pgvector a Qdrant, cambi solo l’implementazione, non tutto il codice applicativo. Se stai costruendo un’automazione attorno a questi strumenti, l’articolo su Tool Use con Claude API mostra come collegare vector search a un agente AI con strumenti reali.
Come Scegliere: Matrice Decisionale
La scelta dipende da tre variabili: dimensione del dataset, requisiti ops e budget. Ecco la mia matrice decisionale aggiornata al 2026:
- Stai prototipando o hai <500k vettori: parti con pgvector su Supabase. Zero configurazione, gratis fino a 500MB, SQL che conosci già. Aggiungi complessità solo quando ne hai veramente bisogno.
- Hai un SaaS multi-tenant e non vuoi fare ops: Pinecone è la scelta più sicura. Namespaces per isolare i tenant, SLA garantito, SDK pronti. Il costo è prevedibile sul piano dedicato.
- Hai >1M vettori, filtri complessi o latenza critica: Qdrant self-hosted. Richiede un’istanza dedicata (anche un VPS da $20/mese basta per dataset medi), ma le performance parlano da sole.
- Vuoi Qdrant senza ops: il cloud managed di Qdrant è maturo nel 2026 e parte da ~$25/mese per cluster small.
Un errore comune che vedo nei progetti di automazione — come quelli descritti nell’articolo su n8n + Claude per automatizzare il business — è sovra-ingegnerizzare l’infrastruttura vettoriale prima di aver validato il caso d’uso. Inizia sempre con la soluzione più semplice e migra quando i dati lo richiedono.
🔧 Pro tip: se usi Supabase, pgvector è già abilitato. Esegui
CREATE EXTENSION vector;nella SQL Editor e sei operativo in 60 secondi. Nessun account aggiuntivo, nessuna API key da gestire.
FAQ e Domande Frequenti
pgvector è abbastanza veloce per la produzione?
Sì, nella maggior parte dei casi. Con un indice HNSW ben configurato e dataset fino a 1-2 milioni di vettori, pgvector raggiunge latenze p50 di 5-15ms, più che sufficienti per sistemi RAG dove il bottleneck è il modello LLM (che risponde in 1-5 secondi). I problemi emergono oltre i 5 milioni di vettori o con requisiti di throughput molto alti (>1000 QPS simultanee). In quei casi, Qdrant o Pinecone sono scelte migliori.
Posso migrare da Pinecone a Qdrant senza riscrivere tutto?
Sì, se hai progettato con un layer di astrazione come quello mostrato sopra. La migrazione richiede: 1) creare la collection Qdrant equivalente, 2) riesportare i vettori da Pinecone (tramite API fetch), 3) re-importarli in Qdrant, 4) aggiornare la configurazione. I metadati si mappano quasi 1-a-1 (metadata Pinecone → payload Qdrant). Il punto critico è che i filtri hanno sintassi diversa: i filtri Pinecone usano operatori MongoDB-like ($eq, $in), mentre Qdrant ha la sua struttura. Pianifica qualche ora di lavoro per la migrazione dei filtri.
Cosa sono i sparse vectors e quando servono?
I sparse vectors rappresentano il testo con pesi per ogni termine del vocabolario (come BM25/TF-IDF), producendo vettori con migliaia di dimensioni ma quasi tutti a zero. Combinati con dense vectors (gli embedding densi standard), abilitano la ricerca ibrida: semantica per la comprensione del contesto + keyword per i termini tecnici specifici. Qdrant supporta sparse+dense natively dal 2024. pgvector non supporta sparse vectors nativamente (dovresti combinarlo con un full-text search PostgreSQL separato). Pinecone supporta sparse-dense hybrid dal 2023. La ricerca ibrida migliora significativamente la precision su query che contengono termini tecnici, nomi propri o codici specifici.
Quale modello di embedding usare con questi database?
Nel 2026, i modelli più usati sono text-embedding-3-small di OpenAI (1536 dims, ottimo rapporto costo/qualità), text-embedding-3-large (3072 dims, migliore accuracy), e embed-v3 di Cohere (1024 dims, multilingua eccellente per l’italiano). Per progetti dove la privacy è critica, nomic-embed-text (open source, eseguibile in locale con Ollama) è un’ottima alternativa. La dimensione del vettore deve corrispondere alla configurazione del database: se cambi modello di embedding, devi ricreare l’indice e ricalcolare tutti gli embedding. Pianifica questa dipendenza dall’inizio del progetto.
Conclusione
Non esiste un vector database migliore in assoluto. Esiste quello giusto per il tuo contesto. pgvector è la scelta pragmatica per chi usa già PostgreSQL e vuole partire subito senza overhead operativo. Pinecone è il percorso di minima resistenza per team che vogliono zero ops e massima disponibilità. Qdrant è la scelta degli ingegneri che vogliono performance native, controllo totale e nessun vendor lock-in. Il mio consiglio: inizia con pgvector (gratuito, integrato, sufficiente per l’80% dei progetti), aggiungi Qdrant quando i dati crescono, considera Pinecone solo se il tuo team non ha budget operativo o competenze DevOps. In ogni caso, astrai sempre il layer vettoriale con un’interfaccia — migrare sarà molto più semplice.
Suggerimenti e Risorse
🔧 Tool: Leggi la guida RAG con Claude API per un esempio end-to-end completo di sistema RAG con vector search integrato.
💡 Consiglio: configura sempre
ef_searcha runtime su pgvector e Qdrant: valori più alti aumentano l’accuracy della ricerca a scapito della latenza. Il default è spesso troppo conservativo per uso production.
🎯 Strategia: Integra il vector database come tool in un agente Claude per costruire un assistente AI che recupera informazioni dal tuo knowledge base in modo autonomo e contestuale.

