pgvector : la recherche vectorielle dans PostgreSQL
pgvector est une extension open source de PostgreSQL (licence PostgreSQL, permissive) qui ajoute le stockage et la recherche de vecteurs à une base que vous administrez déjà, avec des colonnes indexables jusqu'à 2 000 dimensions (4 000 en demi-précision). Pour un corpus local de quelques centaines de milliers de morceaux, c'est un service de moins à exploiter et des filtres SQL qui fonctionnent, sans synchronisation à maintenir avec vos données relationnelles.
pgvector est une extension de PostgreSQL qui ajoute le stockage et la recherche de vecteurs à une base que vous administrez déjà. Pour la plupart des projets de recherche documentaire locale, c'est un service de moins à faire tourner, une sauvegarde de moins à organiser, et des filtres SQL qui fonctionnent réellement — y compris sur les droits d'accès. Le projet, maintenu sous licence PostgreSQL et hébergé sur GitHub, comptait plus de 23 000 étoiles fin septembre 2026, à la version 0.8.6, compatible PostgreSQL 13 et plus récent.
#L'argument : ne pas ajouter de service
Une installation documentaire locale fait déjà tourner un serveur de modèle, une étape d'encodage et un stockage de documents. Ajouter une base vectorielle dédiée, c'est un conteneur de plus, un port de plus, une sauvegarde de plus, et une chose de plus qui peut se désynchroniser de vos données relationnelles le jour où un document est supprimé.
Si PostgreSQL est déjà là — et dans une application métier, il l'est presque toujours — pgvector supprime toute cette catégorie de problèmes. Vos morceaux de texte vivent dans une table à côté des documents dont ils viennent, avec des clés étrangères qui les maintiennent cohérents, et une suppression se propage comme vous l'attendez, sans tâche de nettoyage séparée à écrire ni à surveiller. Le projet ajoute au passage la recherche exacte et approximative, les vecteurs simple précision, demi-précision, binaires et creux, cinq distances (L2, produit scalaire, cosinus, L1, Hamming, Jaccard), et hérite gratuitement de la conformité ACID, de la récupération à un instant donné et des jointures de PostgreSQL.
#Comment ça marche en pratique
Tes documents, ton IA : un RAG local fiable sur tes PDF, notes et mails — sans rien envoyer dans le cloud.
- Espace en ligne à vie
- PDF + fichiers
- Mises à jour à vie
Vous stockez une colonne de vecteurs à côté de vos colonnes habituelles. Une requête trie les lignes par distance au vecteur de la question et renvoie les plus proches. Trois opérateurs de distance couvrent les cas courants, et celui que vous choisissez doit correspondre à la convention du modèle d'embedding : c'est la source la plus fréquente de résultats discrètement médiocres. Pour des vecteurs normalisés à longueur 1 (le cas d'OpenAI et de la plupart des modèles d'embedding récents), le produit scalaire est le plus rapide à calculer et donne le même classement que le cosinus.
| Élément | Ce que c'est | À surveiller |
|---|---|---|
| Colonne vecteur | Un tableau de flottants de dimension fixe | La dimension vient du modèle d'embedding et ne change pas sans tout réencoder |
| Opérateur de distance | Cosinus, produit scalaire ou euclidien (L2) | Doit correspondre au modèle |
| Index HNSW | Index en graphe, requêtes rapides | Construction lente et gourmande en mémoire ; le défaut raisonnable depuis la version 0.5 |
| Index IVFFlat | Index par partitions, peu coûteux à construire | À créer une fois des données représentatives présentes |
| Aucun index | Parcours exact de toutes les lignes | Parfaitement viable jusqu'à quelques dizaines de milliers de lignes |
#Le SQL minimal pour démarrer
- 01Activer l'extensionCREATE EXTENSION IF NOT EXISTS vector; — une seule commande, à exécuter une fois par base.
- 02Ajouter la colonneALTER TABLE chunks ADD COLUMN embedding vector(1024); — la dimension doit correspondre exactement à celle du modèle d'embedding utilisé.
- 03Charger les données avant d'indexerUn chargement en masse via COPY est plus rapide sans index existant ; créez l'index une fois une quantité représentative de lignes présente.
- 04Créer l'indexCREATE INDEX CONCURRENTLY ON chunks USING hnsw (embedding vector_cosine_ops); — l'option CONCURRENTLY évite de bloquer les écritures pendant la construction, longue sur une grande table.
- 05InterrogerSELECT contenu FROM chunks WHERE document_id IN (SELECT id FROM documents WHERE utilisateur_autorise($1)) ORDER BY embedding <=> $2 LIMIT 5; — le filtre d'habilitation et le tri par similarité dans la même requête.
#Les limites de dimension, concrètement
pgvector définit quatre types de colonnes, chacun avec sa propre limite de dimension indexable. Le type vector standard (simple précision, 4 octets par élément) s'indexe jusqu'à 2 000 dimensions, ce qui couvre la plupart des modèles d'embedding open source courants (384 à 1 024 dimensions). Un modèle plus large comme text-embedding-3-large d'OpenAI, à 3 072 dimensions par défaut, dépasse cette limite : la parade documentée est soit de réduire la dimension à la génération de l'embedding (l'API le permet), soit de passer au type halfvec, qui stocke en demi-précision (2 octets par élément, moitié moins de place) et s'indexe jusqu'à 4 000 dimensions. Le type bit (vecteurs binaires, distances de Hamming ou Jaccard) monte à 64 000 dimensions indexables, et sparsevec (vecteurs creux) à 1 000 éléments non nuls indexés — au-delà, PostgreSQL stocke toujours la colonne (jusqu'à 16 000 dimensions pour vector, halfvec et sparsevec) mais sans pouvoir l'indexer, ce qui ramène à un parcours exact.
#Le filtrage, et les droits d'accès
Une question réelle porte rarement sur la totalité du corpus : on veut les passages de ce service, postérieurs à cette date, dans les documents que cet utilisateur a le droit de lire. Dans une base vectorielle dédiée, c'est un filtre de métadonnées avec sa syntaxe et ses cas limites. Dans PostgreSQL, c'est une clause WHERE à côté d'un tri par similarité, jointe à votre table d'utilisateurs si nécessaire.
Un piège documenté par le projet lui-même mérite d'être connu avant de le découvrir en production : avec un index approximatif (HNSW ou IVFFlat), le filtre s'applique après le parcours de l'index, pas avant. Si une condition ne retient que 10 % des lignes et que le paramètre par défaut hnsw.ef_search vaut 40, seules 4 lignes en moyenne remontent — pas les dix demandées. La parade officielle, disponible depuis la version 0.8.0, s'appelle le parcours d'index itératif (SET hnsw.iterative_scan = strict_order), qui relance automatiquement le parcours jusqu'à trouver assez de résultats plutôt que de renvoyer un ensemble tronqué en silence.
#Là où ça s'arrête
- La mémoire à grande échelle
- Des millions de vecteurs en pleine précision, c'est volumineux ; halfvec et la quantification binaire réduisent l'empreinte, mais les moteurs dédiés poussent la compression plus loin nativement. C'est l'écart le plus net.
- Le temps de construction d'index
- Un index HNSW sur une très grande table est long et gourmand ; en production, le construire avec CREATE INDEX CONCURRENTLY évite de bloquer les écritures pendant l'opération.
- La concurrence
- De la recherche vectorielle lourde à côté de votre charge transactionnelle met les deux sur le même serveur. Des réplicas en lecture aident, séparer les rôles aide davantage.
- La dimension des vecteurs
- Les vecteurs indexés ont une borne selon leur type (2 000 pour vector, 4 000 pour halfvec). Les modèles courants passent ; un modèle à très grande dimension doit être réduit ou quantifié.
- La recherche hybride
- PostgreSQL sait faire de la recherche plein texte (tsvector) et vous pouvez la combiner à la distance vectorielle, mais l'ergonomie est à votre charge : il faut exécuter les deux requêtes séparément puis fusionner les classements, par exemple avec une fusion de rangs réciproques (Reciprocal Rank Fusion), plutôt qu'obtenir un score hybride natif en une seule requête.
- La montée en charge horizontale
- Au-delà d'un seul serveur, la voie documentée passe par des réplicas PostgreSQL en lecture ou par un outil de répartition comme Citus ou PgDog — une brique en plus, à l'inverse de l'argument de départ.
#pgvector ou une base dédiée
La question n'est pas laquelle est objectivement meilleure, mais laquelle correspond à votre situation aujourd'hui. pgvector gagne dès que PostgreSQL est déjà la base de vérité de l'application : facturation, comptes, documents source. Un moteur dédié gagne quand le volume de vecteurs ou le débit de requêtes dépasse ce qu'un seul serveur transactionnel peut absorber sans dégrader le reste de l'application, ou quand l'équipe préfère isoler le composant IA du reste du système d'information pour des raisons d'exploitation plutôt que de performance pure.
| Situation | Choix |
|---|---|
| PostgreSQL déjà en place, moins de quelques centaines de milliers de morceaux | pgvector, confortablement |
| Les vecteurs doivent rester cohérents avec des données relationnelles | pgvector : les transactions le font gratuitement |
| Filtrage fin sur des habilitations existantes | pgvector |
| Modèle d'embedding à plus de 4 000 dimensions sans réduction possible | Vérifier le type sparsevec, ou une base dédiée pensée pour ce cas |
| Des millions de vecteurs, beaucoup de requêtes | Un moteur dédié (Qdrant, Milvus) |
| Prototype dans un carnet de notes | N'importe lequel, ce choix est réversible |
- Qdrant : la base vectorielle dédiée
- Milvus, quand le volume dépasse ce que pgvector encaisse
- FAISS : la bibliothèque derrière la recherche vectorielle
- Construire la chaîne RAG complète
- Choisir son modèle d'embedding
- Le kit RAG local QuelLLM : tous les composants sur une page
- Source : dépôt officiel pgvector sur GitHub
- Source : documentation des index et des types pgvector
- Source : guide de montée en charge pgvector
#FAQ
pgvector est-il assez rapide pour du RAG ?+
pgvector ou Qdrant ?+
Quel index choisir, HNSW ou IVFFlat ?+
Puis-je filtrer par métadonnées ?+
Que se passe-t-il si je change de modèle d'embedding ?+
Mon modèle d'embedding fait plus de 2 000 dimensions, que faire ?+
Comment diagnostiquer une requête vectorielle lente ?+
Un retour, une erreur, une précision ? Faites-nous signe, ça améliore le guide pour tout le monde.