Vector Database a Confronto: pgvector vs Pinecone vs Qdrant

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_search a 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.

Condividi

Articoli Recenti

Categorie popolari