恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
向量数据库选型与调优:Milvus、Qdrant、pgvector全解析
首页
资讯中心
/
向量数据库选型与调优:Milvus、Qdrant、pgvector全解析
向量数据库选型与调优:Milvus、Qdrant、pgvector全解析
发布时间:2026/10/20 6:01:03
有这两年在做AI应用或基础架构的朋友估计都躲不开一个词向量数据库。大模型RAG、语义检索、以图搜图这些场景铺开之后传统数据库那套精确匹配的玩法在模糊语义查询面前显得特别无力于是专门为高维向量做存储和检索的数据库就成了标配。这篇文章我打算把市面上常用的向量数据库一次性讲透不仅告诉你它们各自是什么更会结合我实际跑过的场景聊聊选型思路、部署要点、参数调优和一些踩坑记录。不管你是刚接触这个概念想挑一个上手还是已经在用某个产品打算横向对比这篇应该都能给你省下不少时间。1. 向量数据库到底解决什么问题1.1 传统数据库做不到的模糊语义匹配先说清楚一个事情为什么传统的关系型数据库做不了这个事。SQL里我们查一条记录靠的是精确条件比如where name 张三或者范围条件比如where age 18。这种匹配逻辑建立在“值相等”的基础上。但当你问“找一张跟这张图片风格类似的图”或者“找一段语义上差不多的话”时问题就变成了“相似”而不是“相等”。相似度怎么衡量目前工业界最通用的做法是先把图片、文本、音频这些非结构化数据用模型转成一个固定维度的浮点数数组业内管这个叫“嵌入向量”或“Embedding”。比如一段话通过模型处理后变成128维或1024维的向量语义接近的内容在高维空间里的距离就越近。向量数据库干的事情就是把这些向量存起来然后在你给一个查询向量时以最快的速度返回“距离最近”的一批向量及对应的原始数据。这里面有个核心矛盾高维空间里暴力计算距离是可以的但如果数据量上万、上百万甚至上亿暴力比对的计算量会大到完全不可接受。向量数据库的价值正是用各种索引结构和近似检索算法把“大海捞针”变成“沿着索引路径快速定位”这也是它和传统数据库最根本的分水岭。1.2 必须搞懂的三个基础概念理解向量数据库之前有三个概念绕不开分别是嵌入向量、距离度量和最近邻检索。嵌入向量听起来高大上其实可以理解成“对原始内容做了一次特征压缩”。一张猫的图片、一段关于猫的文字如果来自同一套模型体系它们在语义上应该被映射到高维空间中比较接近的位置。所以嵌入向量的质量直接决定了后续检索效果的上限这个认知非常重要——我见过很多团队在检索效果不好时拼命调数据库参数最后发现是模型选错了白费功夫。距离度量则是定义“什么叫近”。最常用的有欧氏距离、余弦相似度和点积。欧氏距离直接计算空间中的直线距离适合低维稠密向量余弦相似度看的是方向一致程度对向量模长不敏感文本语义场景用得最多点积更适合带归一化处理的场景。选哪个度量标准一定要和生成Embedding时使用的模型配套否则检索出来的结果会完全乱掉。最近邻检索kNN就是找“最近的K个邻居”的算法问题。精确kNN在数据量小时没问题数据量大时得靠近似最近邻ANN来提速。向量数据库的核心技术栈基本就是围绕ANN索引在演进比如HNSW图算法、IVF倒排思想、PQ乘积量化这些。理解这些索引类型是后续调优的前提。1.3 向量检索的大致流程一个完整的向量检索流程可以拆成四步数据预处理把原始内容通过Embedding模型转成向量。写入存储把向量和原始数据或源内容ID一起写入向量数据库同时建立索引。查询下发用户输入一个查询同样转成向量带上希望返回的条数K。近似检索数据库在索引结构里快速找到K个最近邻返回结果。这个流程看起来不复杂但实际工程里要处理的问题特别多写入性能和数据源打通、索引构建的内存开销、数据更新和删除的一致性、版本控管、以及把向量搜索和标量过滤组合在一起的条件检索。不同数据库在这些环节上做了不同取舍下面逐个拆解。2. 主流向量数据库的分类与定位2.1 三类形态专业库、扩展插件、托管服务市面上叫“向量数据库”的东西其实形态差异巨大先有个分类意识会帮助你快速判断。第一类是完整的独立数据库系统典型代表有Milvus、Qdrant、Weaviate、Chroma它们自研或深度定制了存储引擎和索引模块根据自己的场景来决定部署和运维方案。第二类是寄生在已有数据库上的扩展最典型的是pgvector它利用PostgreSQL本身的能力加上向量字段和索引支持不用额外部署一套新服务。第三类是全托管的SaaS服务比如Pinecone这类云产品开箱即用、免运维但对网络环境和成本有更高要求。这三类没有绝对的优劣更多是取舍。独立数据库功能全面、性能上限高但意味着要运维一套新的基础设施扩展插件部署简单、能复用现有技术栈但性能和高级功能可能受限托管服务最省事不过长期使用费用可观而且数据要出企业内网合规敏感的项目需要谨慎。2.2 几个常用产品的定位速览我按使用场景给大家分一下层Milvus定位是“大规模生产级检索平台”。数据量到千万级以上、查询并发高、需要水平扩展、又要跟模型和业务做复杂集成时Milvus基本是首选。它架构上把数据插入、索引构建、查询和存储分离支持分布式部署适用于广告推荐、问答引擎、图片检索这类重场景。Chroma则是“开发者的轻量玩具到工具链桥梁”。安装只需要一个pip命令本地起服务大概不要五分钟适合快速做原型验证、搭RAG Demo、写教学项目。数据量在百万级以下时Chroma的体验非常愉悦但如果想扛高并发和亿级数据它就不太合适了。Qdrant走的是“性能极致”路线。Rust语言实现单个节点就能处理相当大的数据量尤其它的Payload过滤机制做得很精致能在向量检索的同时高效完成标量条件过滤这对电商场景“根据品类价格过滤再按语义排序”之类的需求非常友好。pgvector最大的优势是“没有引入新东西”。如果公司已经有PostgreSQL了加一个插件就能获得向量能力SQL生态完全复用对DBA来说几乎零学习成本。适合数据量中等、不想为了向量检索专门维护一套集群的团队。Weaviate在对象存储和“混合检索”上做了很多功夫比如GraphQL接口对多模态和知识图谱结合的场景有一定优势。但它的社区规模和生态相比前几个稍弱国内很多团队用的不多。2.3 一张表看懂大致的选型方向如果现在还不确定选哪个可以先从下面这张表快速建立概念数据库部署形态适合数据规模核心优势主要局限Milvus独立服务/分布式千万级以上扩展性强、功能全、生态较完善部署运维成本较高Qdrant独立服务/单机-集群百万到亿级性能高、过滤机制强大集群生态相对年轻Chroma嵌入式/本地服务百万级以下上手极快、文档友好生产级能力偏弱pgvectorPostgres插件百万到千万级复用现有SQL和运维高级索引与扩展性有限Weaviate独立服务百万到千万级混合检索、GraphQL社区与生态相对小这个表只能代表大部分常规场景真实选型还要考虑查询模式、写入压力、团队背景等。后面我会单独拿一节讲选型背后的深度考量。3. 核心产品实操拆解这一部分我把用得最多的几个产品逐个演示一遍包括安装、初始化、建集合、写入和检索。代码不会贴特别多但关键调用方式都会给到你照着跑一遍就能对每个产品形成直观感受。3.1 Milvus分布式架构扛大规模检索Milvus上手的第一感觉是“重但完整”。2.x版本以后底层存储用对象存储计算层和存储层可以独立扩缩容生产环境一般用Docker Compose或者Kubernetes部署。开发环境最省事的做法是直接用Docker跑Standalone模式docker run -d --name milvus \ -p 19530:19530 \ -p 9091:9091 \ milvusdb/milvus:latest standalone启动需要组件齐全实际项目里我推荐直接用官方提供的milvus-standalone-docker-compose.yml一次性连同etcd和MinIO一起拉起来。Python环境安装pymilvus客户端后建集合和写入数据是这样from pymilvus import connections, CollectionSchema, FieldSchema, DataType, Collection connections.connect(hostlocalhost, port19530) fields [ FieldSchema(nameid, dtypeDataType.INT64, is_primaryTrue, auto_idFalse), FieldSchema(nameembedding, dtypeDataType.FLOAT_VECTOR, dim768), # 维度要和模型输出对齐 FieldSchema(namecategory, dtypeDataType.VARCHAR, max_length64), ] schema CollectionSchema(fieldsfields, descriptiondemo collection) collection Collection(nameimage_search, schemaschema) collection.create_index(embedding, {index_type: HNSW, metric_type: COSINE, params: {M: 16, efConstruction: 200}})插入时直接传入向量列表和标量字段import numpy as np dim 768 vectors np.random.random([1000, dim]).tolist() data [ list(range(1000)), vectors, [fcat_{i} for i in range(1000)], ] collection.insert(data) collection.flush()检索时如果直接collection.search()会拿到结果但如果数据还没建好索引Milvus会自动用暴力检索兜底数据量大时响应会明显变慢。所以务必在插入足够数据后再手动create_index。collection.load() res collection.search( data[vectors[0]], anns_fieldembedding, param{metric_type: COSINE, params: {ef: 64}}, limit10, output_fields[id, category], )Milvus的索引构建是异步的这意味着刚插入的数据不一定立刻能查到必须等索引构建完成。这个特性在生产上会带来一些数据可见性延迟设计业务时要对“写入后立刻检索返回”有预期管理。3.2 Chroma零运维起步的原型利器Chroma我愿称之为“矢量数据库界的一匹黑马”。它的目标就是给AI应用开发者一个最简单的持久化方案甚至不需要启动服务直接用本地模式跑起来pip install chromadb写一个完整的RAG底座的代码量少得感人import chromadb client chromadb.PersistentClient(path./chroma_data) # 持久化到本地目录 collection client.get_or_create_collection(docs) collection.add( documents[深度学习入门指南, 向量数据库实践手册], embeddingsNone, # 如果不传embedding客户端会调用默认模型 ids[doc_1, doc_2], metadatas[{source: tutorial}, {source: manual}], ) results collection.query( query_texts[机器学习怎么学], n_results2, )这里有个容易搞混的点embeddingsNone时Chroma会尝试加载默认的Embedding模型来做文本转向量但这个方法依赖网络下载模型在受限网络环境下会遇到各种问题。我的习惯是自己在外部统一生成向量再传入这样文本处理流程的可控性更高。Chroma也支持本地服务模式在命令行执行chroma run就能起HTTP服务端口默认8000。不过从我的实测看它的HTTP接口能力比Python内嵌模式弱一些所以如果项目是Python技术栈直接用PersistentClient更舒服。3.3 Qdrant用Rust换来的过滤性能Qdrant给我的感觉就是“精致”。它把向量和payload标量元数据放在同一个存储引擎里管理检索时能在遍历候选集的过程中同步应用过滤条件这比“先全量向量检索再过滤标量字段”的做法高效得多。本地启动Qdrant非常轻量docker run -d --name qdrant \ -p 6333:6333 \ qdrant/qdrant创建集合要指定向量尺寸和距离函数然后就可以往里面写数据from qdrant_client import QdrantClient from qdrant_client.models import Distance, VectorParams, PointStruct client QdrantClient(hostlocalhost, port6333) client.create_collection( collection_nameproducts, vectors_configVectorParams(size512, distanceDistance.COSINE), ) points [ PointStruct( idi, vector[0.1] * 512, # 实际项目中用模型生成的向量 payload{category: electronics, price: i * 10}, ) for i in range(100) ] client.upsert(collection_nameproducts, pointspoints)检索时把过滤条件直接放进请求里这一步是Qdrant拿手戏hits client.query_points( collection_nameproducts, query[0.1] * 512, # 支持传原始向量 query_filter{must: [{key: category, match: {value: electronics}}, {key: price, range: {gte: 100}}]}, limit10, )如果查询时只传文本不传向量Qdrant也能配合FastEmbed等工具做内嵌向量化不过工程上更推荐“查询向量提前算好请求里只带向量”这样延迟更可控。Qdrant的另一个优点是单机性能确实好Rust写出来的底层没有GC停顿在高并发下有稳定的尾延迟表现。这在推荐系统这类对延迟敏感的场景里很重要。3.4 pgvector让PostgreSQL顺手拥有向量能力如果公司现有的数据基础设施已经是PostgreSQL那pgvector可能是你“性价比”最高的选择。它不需要引入新服务只需要在数据库里启用扩展CREATE EXTENSION IF NOT EXISTS vector;建表时指定向量列维度固定。支持降维不需要的数据用注释标记即可CREATE TABLE items ( id bigserial PRIMARY KEY, content text, embedding vector(768) );插入数据跟普通SQL没有区别只是向量列需要使用字符串格式的数组INSERT INTO items (content, embedding) VALUES (向量数据库实践, [0.1,0.2,0.3,...]::vector);创建HNSW索引CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);查询K个最近邻SELECT content, 1 - (embedding [0.1,0.2,...]::vector) AS similarity FROM items ORDER BY embedding [0.1,0.2,...]::vector LIMIT 10;这里是余弦距离算符也可以用-做欧氏距离用#做负内积。索引类型和算子必须对应上否则查询会无法走索引。pgvector的局限主要体现在两个地方一是它的索引构建和更新与PostgreSQL自身的VACUUM、WAL机制耦合在一起大数据量下索引构建会比较慢二是水平扩展能力依赖PostgreSQL自身的分库分表方案不像Milvus那样原生支持分布式。所以数据量在两千万以内时它很香超过这个量级就要认真评估了。4. 选型背后的关键考量与参数调优4.1 从数据规模和查询量反推方案很多人在选型时问“哪个最好”但正确答案是“哪个最适合你的场景”。我做选型评估时会先把下面几个数字拉出来量化向量总量级多少条记录要存储单条向量维度通常是256、512、768还是1024QPS预期峰值查询是多少对延迟的要求是多少写入频率是离线批量灌入还是实时持续写入过滤需求查询时要不要配合标签、类目、价格范围等标量条件这几个参数定出来后方案的轮廓就清晰了。比如数据量只有十万条、查询量一天几千次那就没必要上一套分布式Milvus集群Chroma或pgvector就能轻松满足。如果数据量到了千万级、查询QPS上千、还需要复杂过滤逻辑那Qdrant或Milvus才值得考虑。一个容易被忽略的坑是向量维度。很多人做POC时用128维验证效果不错一到生产换成了768维内存开销瞬间变成6倍。向量维度直接影响索引占用的内存和查询延迟选Embedding模型时就要把“上线后的存储成本”纳入评估。4.2 索引类型选择HNSW、IVF适用的场景差异几乎所有向量数据库都支持多种索引类型最常用的是HNSW和IVF。理解这两者的差异会让你在调参时更有方向。HNSW是一种基于多层图的近似最近邻算法。它的核心思想是维护一个分层的图结构在查询时从顶层开始逐层向下搜索找到离查询点最近的节点后再进入下一层精细搜索。HNSW的召回率高、查询速度快但索引构建占用内存较大而且对写入速度有一定影响。适用于数据规模中等、查询性能要求高、对内存不太敏感的场景。IVF则借鉴了传统搜索引擎的倒排索引思路。它先把向量空间聚类成很多桶比如nlist1024个簇查询时只搜索距离查询点最近的几个簇比如nprobe8从而大幅减少计算量。IVF的内存占用比HNSW低构建速度也快但在同等召回率下查询延迟通常不如HNSW。从我跑过的基准测试来看如果内存不是瓶颈大多数场景无脑选HNSW都能获得更好的体验。IVF更适合超大规模数据、内存受限或者对召回率要求不那么极致的场景。还有一个常见优化是PQ乘积量化。它把向量切分成若干子空间每个子空间做量化压缩能显著减少内存占用但会带来一定的精度损失。数据量极大、内存吃紧时可以上PQ但建议先在部分数据上做精度测试确认召回率达到业务底线再投入使用。4.3 参数调优的关键指标HNSW索引里有几个参数直接影响性能分别是M、efConstruction和ef。M表示每个节点最多连接的邻居数量。M越大图越稠密召回率越高但内存和构建时间都会上升。常见取值在16到64之间我一般从16起调看召回率不够再往上加。efConstruction控制索引构建时的搜索宽度。它越大构建越耗时但图质量越好。建议设置在100到200之间默认值偏低的话可以手动调高。ef是查询时的搜索宽度。它控制搜索过程中的候选集规模ef越大召回率越高但查询越慢。这个参数可以动态调整业务对延迟敏感就调小对召回敏感就调大。这几个参数的关系类比一下就是M决定了路网的密度efConstruction决定了修路时多仔细ef决定了导航时愿意探索多少条岔路。很多文章只给结论不给直觉这里我把背后的取舍逻辑讲透后续不管换哪个产品你都能举一反三。另外还要特别提一下“归一化”。很多向量数据库在构建索引时会默认对你传入的向量做归一化如果你的业务里又手动归一化了一遍距离计算会受影响。不同产品对归一化的处理不同比如Qdrant默认不做归一化需要在代码里显式处理。这种细节在文档里往往不明显但一旦匹配模式有问题召回结果会非常诡异。5. 常见问题与排查技巧实录5.1 维度不匹配引发的检索失败这是我见过最多的新手失误建集合时定义了768维加载模型时用了个输出512维的Embedding接口写入和查询时直接报错或者干脆静默返回空结果。排查思路其实很简单任何报错信息先看维度相关字段确认集合配置和输入向量的shape是不是一致。更稳的做法是写一个小脚本统一管理模型和数据库的向量维度配置并把维度及时同步到schema里避免分开手工配置造成漂移。5.2 内存与磁盘资源失控向量索引吃内存的速度经常超出预期。举个例子100万条768维的向量每条768个float32就是约3KB裸数据就要3GB内存HNSW索引算上图的邻接关系后通常会扩大到裸数据的1.5到2.5倍。如果有过滤器或存了大量原文内存占用会更夸张。调优思路有三种压缩向量精度比如float16代替float32降低维度比如做PCA降维启用量化索引PQ或Scalar Quantization。此外要建好监控分片数、索引内存、查询峰值都配上告警防止服务在流量高峰期被拖垮。5.3 召回率和精度不达标如果返回的结果明显不符合预期先说一句大多数时候问题不在数据库而在Embedding模型。两个文本语义相似如果模型表达力不足再好的检索索引也救不回来。排查时可以做一个简单实验手动挑几条测试数据计算它们的向量相似度看看模型本身的语义距离是否符合直觉。如果模型侧没问题再去看距离算法和索引参数。召回率低通常是ef设太小或者归一化处理出了问题。这种“先质疑模型再折腾数据库”的排查顺序能节省大量时间。5.4 过滤条件拖垮性能在向量检索的同时加上大量标量过滤条件性能下降是一定的因为数据库需要先粗筛候选集再做向量距离计算。不同数据库对过滤的处理策略不同Qdrant的过滤能力做得好Milvus较新版本也有“先过滤后检索”的优化但Chroma在过滤场景下性能就弱一些。如果你的业务查询经常带过滤条件就要在选型阶段就把这个因素考虑进去。另一个优化思路是反向倒置在写入时就把数据按某个热门维度拆成多个集合查询时直接定向到相应集合绕开过滤。5.5 删除数据后空间不释放向量数据库的删除操作在很多产品里是软删除实际存储空间不会马上回收。比如Milvus的delete本质是给记录打标记空间回收依赖后续的compaction。如果频繁删除插入导致性能越来越差就该主动触发合并或重建索引。这个点很容易被忽视因为常规数据库的delete语义是即刻的。在生产项目里我吃过这个亏大量数据更新后明明文档说已经删除但查询总能拉到旧数据后来才发现是删除的可见性和compaction周期问题。建议在数据写入量大但删除少的场景使用“分区重建”策略而不是频繁单条删除。最后再分享一点个人的实操心得我实际用过Milvus、Chroma、Qdrant和pgvector最大的感受是没有任何一个产品可以通吃所有场景关键是先想清楚自己的数据规模、查询模式、运维能力再决定选型。如果你正在做POC我的建议是别一开始就切到分布式方案先用Chroma把完整流程跑通、评估好模型效果再上生产级的Qdrant或Milvus。这个过渡路径最平滑也能让团队在早期避免被运维复杂度拖住节奏。另外不管选哪个产品建议在架构设计阶段就把向量维度、索引参数、监控告警这些事拉通定义好这些前期决策在数据量上来之后想改代价往往是推倒重来。做技术选型最怕的不是选错而是没想清楚为什么选。希望这篇文章能帮你在“为什么”这件事上省点力气。