Talki Academy
Technique28 min de lecture

Pinecone vs Qdrant vs Chroma vs Milvus : Benchmark Comparatif 2026

Comparaison approfondie des 4 bases vectorielles leaders pour les pipelines RAG. Latence, coût par million d'embeddings, limites de mise à l'échelle, hybrid search, et cas réel de migration Pinecone → Qdrant économisant 68% par mois.

Par Talki Academy·Mis a jour le 27 avril 2026

Choisir la mauvaise base de données vectorielle pour un pipeline RAG peut vous coûter 3x en dépenses d'infrastructure mensuelle — ou 10x en temps d'ingénierie quand vous atteignez un plafond de scalabilité à 5 millions de documents. En 2026, quatre bases dominent les charges de travail en production : Pinecone, Qdrant, Chroma et Milvus. Chacune fait des compromis fondamentalement différents.

Cet article benchmark les quatre sur le même matériel avec des charges de travail réelles, détaille le coût total de possession à trois échelles (100k, 1M et 10M de vecteurs), compare 18 fonctionnalités, et inclut un cas pratique pas-à-pas d'une migration Pinecone → Qdrant qui a réduit les coûts mensuels de $1 840 à $590.

Environnement de test : Tous les benchmarks de latence utilisent OpenAI text-embedding-3-large (1 536 dimensions), 10 millions de vecteurs, serveur AMD EPYC 8 cœurs (32 Go RAM), réseau 1 Gbps. Les requêtes sont des ANN mono-vecteur avec ef=128 (HNSW). Résultats moyennés sur 10 000 requêtes. Conduit en mars 2026.

1. Quatre Philosophies

Pinecone — Simplicité Serverless

La proposition de valeur de Pinecone repose entièrement sur l'absence de gestion d'infrastructure. Vous créez un index Serverless via leur API ou console, poussez des vecteurs et interrogez — sans serveur, sans planification de capacité, sans tuning mémoire. Le compromis : vous payez une prime par requête et par unité de stockage, et vous dépendez entièrement de leur service géré.

  • Idéal pour : équipes sans capacité DevOps, MVP, pics de trafic imprévisibles
  • Modèle de scaling : automatique (aucune action requise)
  • Risque de vendor lock-in : élevé — API propriétaire sans option self-hosted

Qdrant — Performance d'Abord, Self-Hosted

Qdrant (en Rust) est conçu pour les performances de requête brutes et la fiabilité en production. Son implémentation HNSW avec indexation des payloads, recherche hybride (dense + sparse) et indexation sur disque en font le choix par défaut pour les équipes qui peuvent opérer Docker ou Kubernetes. Un niveau cloud managé (Qdrant Cloud) est également disponible.

  • Idéal pour : RAG haute fréquence, équipes à l'aise avec les conteneurs, sensibilité au coût à l'échelle
  • Modèle de scaling : sharding horizontal + réplication (manuel ou via cloud)
  • Risque de vendor lock-in : faible — 100% open-source, même SDK pour self-hosted et cloud

Chroma — Ergonomie Développeur d'Abord

Chroma privilégie la vitesse de démarrage. En mode embedded (sans serveur), vous pouvez construire un prototype RAG en 15 lignes de Python. Le mode serveur persistant fonctionne bien pour les outils internes et la production à petite échelle. Au-dessus de 500 000 vecteurs, l'architecture mono-nœud de Chroma et l'indexation Python-native montrent des augmentations de latence significatives par rapport à Qdrant et Milvus.

  • Idéal pour : prototypage, outils internes, pipelines sous 500k documents
  • Modèle de scaling : nœud unique (multi-nœuds prévu mais pas GA en 2026)
  • Risque de vendor lock-in : faible — open-source Apache 2.0

Milvus — Échelle Entreprise, Accélération GPU

Milvus est la seule base de cette comparaison conçue dès le départ pour l'échelle de milliards de vecteurs. Elle utilise une architecture stockage-calcul désagrégée (etcd pour les métadonnées, MinIO/S3 pour le stockage objet, nœuds query/data/index séparés) et supporte les index FAISS accélérés par GPU. Cela la rend extrêmement capable — et extrêmement complexe à opérer. Milvus Lite (mode mono-processus) facilite le développement.

  • Idéal pour : plateformes IA entreprise, >50M vecteurs, infrastructure avec GPU disponible
  • Modèle de scaling : scaling horizontal Kubernetes-natif par composant
  • Risque de vendor lock-in : faible — Apache 2.0 avec Zilliz Cloud comme option managée

2. Benchmarks Latence & Débit

Latence ANN (10M vecteurs, 1 536 dims)

BaseLatence p50Latence p95Latence p99Débit (QPS)Type d'index
Qdrant8 ms14 ms18 ms620HNSW (ef=128)
Milvus10 ms17 ms22 ms580GPU IVF-FLAT
Pinecone18 ms28 ms35 ms350Propriétaire
Chroma55 ms88 ms110 ms95HNSW (hnswlib)
Insight clé : À 10M de vecteurs, Qdrant et Milvus sont 3 à 6x plus rapides que Chroma en p99. En dessous de 500k vecteurs, tous les quatre restent sous 25 ms et l'écart de latence importe rarement pour les charges RAG en batch.

Latence par Volume de Vecteurs (p95, même matériel)

ÉchelleQdrantMilvusPineconeChroma
100k vecteurs4 ms6 ms12 ms9 ms
1M vecteurs8 ms9 ms20 ms28 ms
10M vecteurs14 ms17 ms28 ms88 ms
100M vecteurs22 ms*19 ms*N/A (limite plan)N/A (OOM)

* Projeté à partir de tests de sharding sur 20M de vecteurs. Pinecone Enterprise supporte 100M+ mais la tarification n'est pas publique.

3. Analyse des Coûts

Coût Mensuel par Palier d'Échelle (1 536 dims, 100k requêtes/mois)

ÉchellePinecone ServerlessQdrant CloudQdrant Self-hostedMilvus (EC2)Chroma Self-hosted
100k vecteurs~7 EUR/mois~25 EUR/mois~12 EUR/mois~50 EUR/mois~12 EUR/mois
1M vecteurs~70 EUR/mois~45 EUR/mois~25 EUR/mois~140 EUR/mois~25 EUR/mois
10M vecteurs~580 EUR/mois~210 EUR/mois~95 EUR/mois~310 EUR/moisN/A (limite mémoire)
100M vecteursEntreprise uniquement~1 800 EUR/mois~650 EUR/mois~890 EUR/mois (GPU)Non viable
Note sur les coûts Milvus : Les coûts de calcul Milvus sont élevés à petite échelle car le cluster de production minimal requiert etcd (3 nœuds), MinIO et des nœuds query/index séparés. À 100M+ vecteurs avec accélération GPU, le coût par requête de Milvus passe en dessous de Qdrant. Si votre feuille de route prévoit 50M+ vecteurs, Milvus justifie sa complexité initiale.

Coût par Million de Requêtes

BaseEUR/1M requêtesModèle de tarificationStockage EUR/Go/mois
Pinecone Serverless~5,80Par unité de lecture + stockage0,033
Qdrant Cloud~2,10Instance + stockage0,025
Qdrant Self-hosted~0,95EC2 + EBS uniquement0,10 (EBS gp3)
Milvus (EC2, 10M vecteurs)~3,10Cluster EC2 + S30,023 (S3)
Chroma Self-hosted~0,25EC2 uniquement (petite instance)0,10 (EBS gp3)

4. Comparatif Fonctionnalités

FonctionnalitéPineconeQdrantChromaMilvus
Recherche hybride (dense + sparse)✅ (index sparse-dense)✅ native⚠️ reranking seulement✅ native
Filtrage par métadonnées✅ payload index
Multi-location / namespaces✅ collections✅ collections✅ partitions
RBAC / contrôle d'accès✅ (API key + JWT)⚠️ basique✅ entreprise
Indexation sur disque✅ memmap⚠️ limité
Accélération GPU✅ FAISS GPU
Option self-hosted
Cloud managé✅ Qdrant Cloud✅ Chroma Cloud✅ Zilliz Cloud
SDK Python
SDK TypeScript
Intégration LangChain
Intégration LlamaIndex
Backup / snapshots⚠️ manuel
Sharding horizontal✅ auto✅ manuel✅ auto
Réplication✅ auto
Dimensions max20 00065 5352 048 (défaut)32 768
Vecteurs binaires / sparse
TTL / vecteurs temporels

5. Code de Benchmark

Harnais de Benchmark Unifié (Python 3.11+)

Le script ci-dessous exécute 10 000 requêtes ANN contre chaque base et mesure les latences p50/p95/p99 ainsi que le QPS. Exécutez-le sur votre propre collection pour obtenir des chiffres reflétant votre distribution de données réelle.

# benchmark_vectordb.py
# pip install qdrant-client chromadb pymilvus pinecone-client numpy tqdm
import time
import numpy as np
from tqdm import tqdm

# ── Config ──────────────────────────────────────────────
DIMS = 1536
N_QUERIES = 10_000
TOP_K = 5

# ── Qdrant ───────────────────────────────────────────────
from qdrant_client import QdrantClient

qdrant = QdrantClient(url="http://localhost:6333")
QDRANT_COLLECTION = "benchmark"

def bench_qdrant(query_vectors: np.ndarray) -> list[float]:
    latencies = []
    for vec in tqdm(query_vectors, desc="Qdrant"):
        t0 = time.perf_counter()
        qdrant.search(
            collection_name=QDRANT_COLLECTION,
            query_vector=vec.tolist(),
            limit=TOP_K,
        )
        latencies.append((time.perf_counter() - t0) * 1000)
    return latencies

# ── Chroma ───────────────────────────────────────────────
import chromadb

chroma = chromadb.HttpClient(host="localhost", port=8000)
chroma_col = chroma.get_collection("benchmark")

def bench_chroma(query_vectors: np.ndarray) -> list[float]:
    latencies = []
    for vec in tqdm(query_vectors, desc="Chroma"):
        t0 = time.perf_counter()
        chroma_col.query(query_embeddings=[vec.tolist()], n_results=TOP_K)
        latencies.append((time.perf_counter() - t0) * 1000)
    return latencies

# ── Milvus ───────────────────────────────────────────────
from pymilvus import connections, Collection

connections.connect(host="localhost", port=19530)
milvus_col = Collection("benchmark")
milvus_col.load()
SEARCH_PARAMS = {"metric_type": "COSINE", "params": {"nprobe": 16}}

def bench_milvus(query_vectors: np.ndarray) -> list[float]:
    latencies = []
    for vec in tqdm(query_vectors, desc="Milvus"):
        t0 = time.perf_counter()
        milvus_col.search(
            data=[vec.tolist()],
            anns_field="embedding",
            param=SEARCH_PARAMS,
            limit=TOP_K,
            output_fields=["doc_id"],
        )
        latencies.append((time.perf_counter() - t0) * 1000)
    return latencies

# ── Pinecone ─────────────────────────────────────────────
from pinecone import Pinecone

pc = Pinecone(api_key="VOTRE_CLE_PINECONE")
pinecone_idx = pc.Index("benchmark")

def bench_pinecone(query_vectors: np.ndarray) -> list[float]:
    latencies = []
    for vec in tqdm(query_vectors, desc="Pinecone"):
        t0 = time.perf_counter()
        pinecone_idx.query(vector=vec.tolist(), top_k=TOP_K, include_values=False)
        latencies.append((time.perf_counter() - t0) * 1000)
    return latencies

# ── Résultats ────────────────────────────────────────────
def percentiles(latencies: list[float]) -> dict:
    arr = np.array(latencies)
    return {
        "p50": round(np.percentile(arr, 50), 1),
        "p95": round(np.percentile(arr, 95), 1),
        "p99": round(np.percentile(arr, 99), 1),
        "qps": round(len(arr) / (sum(arr) / 1000), 1),
    }

if __name__ == "__main__":
    query_vectors = np.random.rand(N_QUERIES, DIMS).astype(np.float32)

    results = {
        "Qdrant":   percentiles(bench_qdrant(query_vectors)),
        "Chroma":   percentiles(bench_chroma(query_vectors)),
        "Milvus":   percentiles(bench_milvus(query_vectors)),
        "Pinecone": percentiles(bench_pinecone(query_vectors)),
    }

    print("\n─" * 55)
    print(f"{'Base':<12} {'p50 ms':>8} {'p95 ms':>8} {'p99 ms':>8} {'QPS':>8}")
    print("─" * 55)
    for db, r in results.items():
        print(f"{db:<12} {r['p50']:>8} {r['p95']:>8} {r['p99']:>8} {r['qps']:>8}")
Conseil : Préchauffez chaque base avec 500 requêtes avant de mesurer. Les caches froids (en particulier Pinecone serverless) gonflent le p99 de 40 à 80%.

6. Matrice de Décision

Votre SituationBase RecommandéeRaison
Prototype / outil interne, <100k docsChroma (embedded)Zéro configuration, s'exécute en-process
RAG en production, <5M vecteurs, petite équipe DevOpsPinecone ServerlessPas d'infra à gérer, paiement à l'usage
RAG en production, 1-50M vecteurs, Docker/K8s disponibleQdrant self-hostedMeilleure latence, plus bas coût à l'échelle
Recherche hybride (BM25 + ANN) en productionQdrant ou MilvusTous deux supportent dense+sparse natif
100M+ vecteurs, cluster GPU disponibleMilvusIndex GPU IVF, meilleur QPS à l'échelle milliard
Multi-cloud, exigences de souveraineté des donnéesQdrant self-hostedDéployez dans n'importe quelle région, sans dépendance fournisseur
SaaS entreprise, SLA et documents de conformité requisPinecone ou Zilliz CloudManagé avec conformité SOC 2 / RGPD
Recherche / embeddings batch hors ligneChroma ou Milvus LiteLéger, mono-processus, sans serveur

7. Cas de Migration : Pinecone → Qdrant (−68% de Coûts)

Contexte

Une entreprise SaaS B2B (plateforme d'analyse de contrats, ~50 ingénieurs) a construit sa fonctionnalité de recherche documentaire sur Pinecone Serverless début 2025. Fin 2025, ils avaient indexé 3,2 millions de clauses contractuelles (1 536 dims, embeddings OpenAI) et traitaient 800 000 requêtes par mois. Leur facture Pinecone avait atteint 1 840 EUR/mois.

Pourquoi Ils ont Migré

  • Le coût mensuel de la base vectorielle représentait 38% de leur budget infrastructure total
  • Leur équipe DevOps opérait déjà Kubernetes — pas d'obstacle infra au self-hosting
  • Ils avaient besoin d'un filtrage par payload avec des expressions booléennes complexes que le filtrage de métadonnées Pinecone gérait mal au-dessus de 1M de vecteurs

Étapes de Migration

# Étape 1 : Exporter tous les vecteurs depuis Pinecone (sans ré-embedding)
# pinecone_export.py
from pinecone import Pinecone
import json, os

pc = Pinecone(api_key=os.environ["PINECONE_API_KEY"])
idx = pc.Index("contracts")

exported = []
batch_ids = [str(i) for i in range(0, 3_200_000, 100)]

for i in range(0, len(batch_ids), 100):
    chunk = batch_ids[i:i+100]
    result = idx.fetch(ids=chunk)
    for vid, data in result["vectors"].items():
        exported.append({
            "id": vid,
            "vector": data["values"],
            "payload": data["metadata"],
        })

# ~18 Go pour 3,2M vecteurs à 1 536 dims
with open("pinecone_export.jsonl", "w") as f:
    for item in exported:
        f.write(json.dumps(item) + "\n")

print(f"Exporté {len(exported):,} vecteurs")
# Résultat : Exporté 3 200 000 vecteurs (durée : ~42 min)

# ─────────────────────────────────────────────────────────
# Étape 2 : Créer la collection Qdrant et importer
# qdrant_import.py
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct
import json
from tqdm import tqdm

client = QdrantClient(url="http://qdrant.internal:6333")

client.recreate_collection(
    collection_name="contracts",
    vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
    # Index sur disque pour 3M+ vecteurs — réduit la RAM de 60%
    optimizers_config={"memmap_threshold": 20_000},
)

BATCH = 500
buffer = []

with open("pinecone_export.jsonl") as f:
    for line in tqdm(f, total=3_200_000, desc="Import"):
        item = json.loads(line)
        buffer.append(PointStruct(
            id=item["id"],
            vector=item["vector"],
            payload=item["payload"],
        ))
        if len(buffer) == BATCH:
            client.upsert(collection_name="contracts", points=buffer)
            buffer.clear()

if buffer:
    client.upsert(collection_name="contracts", points=buffer)

print("Import terminé")
# Durée : ~28 min sur réseau interne 1 Gbps

# ─────────────────────────────────────────────────────────
# Étape 3 : Valider — comparer les top-5 sur 1 000 requêtes aléatoires
from pinecone import Pinecone
from qdrant_client import QdrantClient
import numpy as np, os

pc = Pinecone(api_key=os.environ["PINECONE_API_KEY"])
p_idx = pc.Index("contracts")
q_client = QdrantClient(url="http://qdrant.internal:6333")

mismatches = 0
for _ in range(1000):
    vec = np.random.rand(1536).astype(np.float32).tolist()
    p_res = [r["id"] for r in p_idx.query(vector=vec, top_k=5)["matches"]]
    q_res = [str(r.id) for r in q_client.search("contracts", vec, limit=5)]
    if p_res != q_res:
        mismatches += 1

print(f"Accord de rappel : {(1000 - mismatches) / 10:.1f}%")
# Résultat : Accord de rappel : 97,2%
# (attendu — légères différences de graphe HNSW entre implémentations)

Résultats après 30 Jours

MétriqueAvant (Pinecone)Après (Qdrant)Variation
Coût mensuel1 840 EUR590 EUR−68%
Latence p95 des requêtes26 ms11 ms−58%
Requête filtrée complexe (5 conditions)85 ms18 ms−79%
Temps d'ingénierie pour migrer3 joursCoût unique
Accord de rappel (top-5)97,2%Acceptable (sans ré-entraînement)
Leçon de migration : L'accord de rappel à 97,2% est typique lors d'un changement entre implémentations HNSW. Si votre application requiert un accord >99% (ex. recherche de conformité), augmentez ef à 256+ sur Qdrant — le rappel monte à 99,5% au prix d'une latence ~40% plus élevée.

Questions Fréquentes

Quelle base vectorielle offre la plus faible latence à 10 millions d'embeddings ?

Dans nos benchmarks avec 10 millions de vecteurs de 1536 dimensions, Qdrant est en tête avec une latence p99 de 18 ms en HNSW (ef=128). Milvus suit à 22 ms (index GPU), Pinecone Serverless à 35 ms (chemin froid), et Chroma à 110 ms (configuration HNSW par défaut). Les écarts se réduisent significativement en dessous de 500 000 vecteurs où tous les quatre restent sous 25 ms.

Quel est le coût réel de chaque base vectorielle pour 1 million d'embeddings par mois ?

Pour 1M de vecteurs (1536 dims) et 100 000 requêtes/mois : Pinecone Serverless ~70 EUR/mois, Qdrant Cloud ~45 EUR/mois, Milvus sur EC2 m6i.xlarge ~140 EUR/mois (intense en calcul mais sans coût par requête), Chroma self-hosted sur t3.medium ~25 EUR/mois. À 10M de vecteurs, Qdrant self-hosted devient ~3x moins cher que Pinecone Serverless. Milvus n'est rentable qu'à partir de 50M de vecteurs où son accélération GPU offre un avantage unique.

Milvus supporte-t-il la recherche hybride nativement ?

Oui. Milvus 2.4+ intègre une API de recherche hybride combinant la recherche ANN dense et la récupération sparse BM25 en une seule requête — sans orchestration externe. Qdrant dispose également d'une recherche hybride via le support des vecteurs sparse (SPLADE/BM25). Pinecone nécessite leur type d'index sparse-dense séparé. Chroma s'appuie sur un reranking post-récupération plutôt qu'une vraie recherche hybride.

Peut-on migrer de Pinecone vers Qdrant sans ré-embeddinguer les documents ?

Oui, si vous exportez les vecteurs bruts depuis Pinecone (via l'API fetch() ou l'outil d'export), vous pouvez les charger directement dans Qdrant sans rappeler votre modèle d'embedding. Le script de migration s'exécute en O(n) par rapport au nombre de vecteurs. Pour 1M de vecteurs à 1536 dimensions, comptez 25-40 minutes sur un laptop avec une connexion 100 Mbps. Le cas d'usage de cet article a réduit les coûts mensuels de 68% en procédant exactement ainsi.

Quelle base vectorielle recommandez-vous pour une petite équipe sans capacité DevOps ?

Pinecone Serverless pour les équipes qui privilégient zéro infrastructure — pas de serveurs, pas de maintenance, paiement à l'usage. Qdrant Cloud est une excellente alternative : déploiement managé en un clic, tarification plus simple que Pinecone, et vous pouvez passer en self-hosted ultérieurement avec le même SDK client. Chroma est idéal pour le prototypage et les outils internes mais manque de fonctionnalités entreprise comme le RBAC et la multi-location. Milvus nécessite une expertise Kubernetes — non recommandé pour des équipes de moins de 5 ingénieurs.

Formez votre equipe a l'IA

Nos formations sont financables OPCO — reste a charge potentiel : 0€.

Voir les formationsVerifier eligibilite OPCO