向量数据库对比分布式数据库

接入与开发

帮选型者分清向量库和传统分布式数据库各自负责什么,什么时候要一起上,什么时候只用一套就够。

很多人一开始会问「我把资料存进向量库,是不是就不用数据库了」,或者反过来「我们已经有分布式数据库了,还需要再搭一套向量库吗」。这个问题卡人的地方不在概念,而在数据怎么落地、一次查询要走几个组件、运维要不要多养一套集群。这篇按职责、写入、查询、扩容、成本几个维度把两者的分工拆开,最后给一份可直接照着走的选型对照表和落地顺序。

很多人一开始会问「我把资料存进向量库,是不是就不用数据库了」,或者反过来「我们已经有分布式数据库了,还需要再搭一套向量库吗」。这两个问法其实都默认了对方可以被替掉,但真实情况是它们回答的是两个不同的问题:一个问「哪些内容和这段话最像」,另一个问「满足这些条件的那一行在哪」。先把这个区别想清楚,后面的选型才有意义。

这个问题卡人的地方不在概念,而在数据怎么落地、一次查询要走几个组件、运维要不要多养一套集群。这篇按职责、写入、查询、扩容、成本几个维度把两者的分工拆开,中间给排查顺序和迁移步骤,最后给一份可直接照着走的选型对照表和落地顺序。全程只讲判断标准,不给你一个「标准答案架构」。

先把职责分清:一个是按相似度找,一个是按条件查

向量库的核心能力是近似最近邻检索。你给它一段文本、一张图或者一段音频的向量表示,它返回的是「和这个最接近的若干条」,结果是按相似度排序的、近似而非精确的。分布式数据库的核心是精确匹配、事务与多版本一致性,它回答的是「满足这些条件的那些行在哪」,结果要么命中要么不命中,中间没有「差不多」这回事。

相似度检索
按向量距离排序返回 Top-K,结果允许近似,换索引参数结果会变
条件查询
按字段精确过滤、排序、聚合,结果稳定可复现,和索引实现无关
事务
多条写入要么全成要么全败,跨行跨表也保持一致
强过滤
先按权限、时间、状态这些字段把范围圈小,再做后续处理
  • 判断落点看三个问题:要不要事务、要不要按条件强过滤、要不要跨表 join。
  • 三个里有两个以上是「要」,那多半还是得让分布式数据库当主库,向量能力作为附带或旁路。
  • 如果只做纯语义检索、结构化字段很少、也接受最终一致,那单上一套向量库就够了。
  • 最怕的是「三个都想要,但只搭了一套组件」,后面一定会用业务代码去补数据库该干的事。

一次查询到底走几个组件:把链路画出来再谈选型

典型链路是「结构化条件先筛一遍候选集,再拿候选集去向量库算相似度,最后回到主库取完整字段」。把这条链路画成一张图、标出每一步的输入输出,能避免选完才发现少了某一环。比如权限过滤到底放在检索前还是检索后,会直接决定你需不需要向量库支持带条件的近似检索。

  1. 第一步:画出完整链路从请求进来到响应返回,列出每一个组件、每一次网络调用,标出各自负责什么。
  2. 第二步:标出过滤位置确认权限、时间、状态这些字段是在检索前生效还是检索后兜底,前者对向量库的条件过滤能力有要求。
  3. 第三步:确定真源位置原文和结构化字段放哪、向量放哪,谁可以被重建、谁丢了就麻烦。
  4. 第四步:给每段打点过滤耗时、召回耗时、回表耗时分别记录,别只记一个端到端总耗时。

常见坑是只把向量写进向量库、原文留在别处,导致每次召回都要回主库查询一次。QPS 一上来延迟翻倍,排查时又看不出是哪一段慢,因为总耗时里混着过滤、召回、回表三段。落地时给每段单独打点,具体该记哪些字段可以对照 /tools/verify#probes 的做法再定。

一致性与写入顺序:先写哪边,出错了怎么办

两边都写就一定会遇到「一边成功一边失败」。这不是概率问题,是必然会发生的工程事实。所以必须先明确谁是真源:一般让分布式数据库当唯一真相,向量库当可重建的派生物。可重建意味着向量库允许丢、允许滞后、允许数量对不上,只要重建脚本能按条件批量重放就行,而不是靠人工补数据。

写入顺序发生什么后果
先主库、再异步推向量主库提交成功,推送任务失败或延迟向量库短暂滞后,重放任务可补齐,可接受
先向量库、再写主库主库事务回滚向量库里留下孤儿数据,越攒越多,只能靠对账清理
两边同步双写任一侧异常调用方要处理半成功状态,业务代码复杂度上升
只写向量库主库没落库没有真源,向量库本身就成了唯一副本,丢失不可恢复
  • 写入顺序推荐「先主库落库、再由异步任务推向量」,反过来的话事务回滚后向量库里会留下孤儿数据。
  • 重建脚本要能按业务条件批量筛选重放,不是只能全量重建,否则一次模型更换就要停服。
  • 上线前先验证一次「停掉向量库、业务是否还能降级返回」,如果不能,那说明向量库已经被当成了真源。
  • 孤儿数据的清理要对账,至少按时间窗口比对两边的数量差异,而不是靠感觉。

扩容方式不一样:一个靠分片,一个靠索引参数和内存

分布式数据库扩容主要是加节点、重分片。关注点是分片键选得好不好、跨片查询多不多、再平衡期间业务是否受影响。向量库的容量和延迟更吃内存和索引参数,同样的数据量调一组参数可能就意味着必须加机器;反过来,放宽召回质量又能省下不少资源。两者的扩容逻辑不在一个维度上,所以不能拿「数据库能加机器」的思路去估向量库。

维度分布式数据库向量库
扩容手段加节点、重分片、读写分离加内存、调索引参数、改分片或分层
瓶颈通常在分片键、热点写入、跨片查询内存占用、召回延迟、索引构建时间
性能与什么强相关查询并发和数据分布数据量、维度、召回质量要求
扩容前的动作压测分片方案、演练再平衡量出延迟基线,确认是数据涨了还是参数没调

扩容前最好先量出你当前的延迟基线,不要凭感觉判断「慢是因为数据变多了」。有时候是索引参数没跟上,有时候是过滤条件变复杂了,有时候单纯是并发涨了。可以用 /tools/speed-test 这类方式建立基线,把改参数前后、加机器前后的数字放在一起比,而不是只记住一个「感觉变慢了」。

成本与运维:多养一套集群值不值

除了软硬件,还要算人。多一套组件就多一套备份、监控、升级和值班流程。小团队经常低估这块,觉得「多搭一个服务而已」,结果半年后发现半夜告警多了一类、版本升级要停两次、权限体系要维护两套。如果数据量不大、查询并发也不高,很多分布式数据库自带的向量能力够用,省下的运维精力比性能收益更值钱。

  • 真要把向量库单独拆出来,通常出现在数据量上千万级、召回延迟要求稳定、或者结构化和向量查询负载互相拖累的时候。
  • 如果只是「未来可能会大」,先别拆,把数据模型留出扩展位,等指标真的顶不住再说。
  • 评估时把备份恢复演练也算进去,不只是算日常跑起来的资源开销。
  • 团队里有没有人能看懂向量库的监控指标,是一个很实际的判断依据,没人看得懂就先别单独上。

从「全放一个库」到「拆出向量库」的迁移顺序

  1. 第一步:抽接口不动架构把向量检索逻辑抽成一个独立接口层,主库实现和向量库实现都对着同一套方法,后面换实现只改一层。
  2. 第二步:双写并比对同一批 query 走两条路径,看召回结果差异是否在可接受范围;差异过大先查分块方式和嵌入模型是否一致,别急着上向量库。
  3. 第三步:灰度切读先切离线批处理再切在线,出问题把开关拨回去就行;切流比例按你们自己的流量曲线定,别照搬别人的数字。
  4. 第四步:保留回退路径切换后至少留一段时间的双路可切能力,确认稳定后再下线旧路径,不要一次性删掉。

这个顺序的重点是「每一步都可回退」。迁移最容易出事的不是性能,而是某个环节切过去之后发现回不来。把接口层放在前面,把双写比对放在中间,把灰度切读放在后面,出问题时你只是拨一个开关,而不是连夜重建数据。

一张对照表:什么情况下只用一个,什么情况下两个都要

场景特征只用分布式数据库只用向量库两个都要
事务与一致性要求强要求无要求或可最终一致强要求且要稳定召回
查询主要形态条件过滤为主纯语义检索为主先过滤再召回,两者交替
结构化字段很多且经常变很少或基本不变多且要参与过滤
数据量与并发可控,单库能扛量不大,召回延迟要求稳定都在涨,单组件开始互相拖累
团队运维能力没有专职运维向量组件能维护向量库且接受最终一致两边都有人能看懂

两种都可以的情况:先选运维成本低的那种,把数据模型留出扩展位,等指标真的顶不住再拆。这比一上来就上重型架构更容易活下来,因为早期你连真实查询长什么样都还没摸清。具体产品的当前能力对比,去 /stacks/vector-dbs 和 /stacks 看当时的目录,别用半年前的印象做决定。

选型不是选谁更强,是选谁的责任边界更清楚,以及在出问题时你能不能快速定位到是哪一环。

选完之后怎么验证选对了,别只看跑分

准备一小批真实 query,固定住,改架构前后都跑一遍,比召回率和端到端延迟的变化,而不是只看某一项跑分。跑分高的方案在你们真实数据上可能表现一般,因为分块方式、字段分布、查询习惯都不一样。固定 query 集的价值在于,它让「有没有变好」这件事可复现。

  • 把召回质量、P95 延迟、单位数据量的资源占用三项同时记录,只优化其中一项很容易把另外两项弄坏。
  • 每次调整只动一个变量,比如只换索引参数,别同时换模型又换分块。
  • 向量库这类组件版本迭代快,参数和默认值会变,具体产品的能力对比到 /stacks/vector-dbs 看当时的目录。
  • 上线后定期复跑那批固定 query,发现指标漂移时先查数据分布变化,而不是先怀疑组件。

验证阶段还要注意一个问题:召回质量怎么定义。如果只是看「返回的前几条像不像」,那不同人会给出不同结论。最好把它拆成可量化的几项,比如命中率、排序相关性、以及人工抽检的通过比例,具体口径在团队内先对齐再跑,否则改完架构也吵不出结论。

下一步如果你正卡在「要不要再搭一套向量库」这一步,先把你们真实查询里有多少是条件过滤、多少是语义召回统计出来,再去 /stacks/vector-dbs 和 /tools/speed-test 对着当时的目录和基线看,比直接问「哪个更好」有用得多。

常见问题

已经有分布式数据库了,还有必要单独上向量库吗?

看你现在的瓶颈在哪。如果数据量不大、并发不高、结构化过滤为主,分布式数据库自带的向量能力通常够用,先别拆。真正需要独立向量库的信号是:召回延迟要求稳定、数据量到千万级、或者结构化和向量查询互相拖累。达不到这些条件,多一套集群主要是多一份运维负担。

向量库里要不要也存原文和权限字段?

建议存一份元数据副本,原文可以存也可以只存主库主键,取决于你愿不愿意接受回表查询。存副本查询快但有一致性问题,只存主键数据干净但每次召回都要回主库。折中做法是把高频过滤字段放进向量库,完整字段仍以主库为准,接受短时间的不一致。

双写导致两边数据对不上怎么办?

先确定谁是真源:一般分布式数据库是真源,向量库是可重建的派生物。然后跑一个对账任务,按主键比对两边数量与时间戳,把差异丢进重放队列。长期做法是写入走主库、向量由异步任务推,允许滞后但不允许凭空多出来。

迁移到新架构时怎么保证不影响线上?

把检索抽成独立接口层,新旧实现都走同一套方法;先双写并在离线流量上比对召回差异;再按流量比例灰度切读,从批处理任务切起,最后切在线请求。切之前确认好回滚开关怎么拨,出问题能在几分钟内切回旧路径,比追求一次切干净更重要。

向量库和分布式数据库的扩容思路一样吗?

不一样。分布式数据库主要靠加节点重分片,重点在分片键和跨片查询;向量库更吃内存和索引参数,同样数据量调一组参数可能就要加机器,放宽召回质量又能省资源。所以扩容前先用真实查询量出延迟基线,判断到底是数据涨了还是参数没调好。

本文依据各平台公开文档与官方公告整理,只做中文归纳;具体做法、参数与限制以官方文档为准。