1. 开头:为什么RAG应用选数据库,比选大模型还头疼
做RAG(检索增强生成)应用,很多人一上来就盯着Embedding模型怎么选、向量维度设多少、Prompt模板怎么写。但真正把系统推到生产环境时,最先暴露问题的反而是数据层——存文档的库、存向量的库、存会话状态的库,到底要选几个?每个库各承担什么职责?数据同步怎么做?这些问题不提前想清楚,后续的检索质量、写入性能、运维成本都会连环踩坑。
我在多个RAG项目中用过DuckDB、Milvus和SurrealDB,这三款数据库在社区里经常被放在一起比较,但深入了解后会发现,它们其实是三条不同的技术路线。DuckDB是嵌入式分析型OLAP,Milvus是专为向量检索设计的分布式数据库,SurrealDB则是多模型数据库,试图在一个引擎里同时搞定文档、关系和向量。它们的交集点在于都能处理向量数据,但设计目标、使用场景、性能特征和工作原理差异非常大。这篇文章就从RAG应用的实际需求出发,对这三者做一次深度对比,把选型背后的逻辑讲透。
2. RAG应用的数据层到底在存什么
很多人在选型时直接跳到“向量数据库对比”这一步,但实际上RAG应用的数据层是一个混合存储场景。只有先拆清楚数据需求,才能判断什么类型的数据库真正适合。
2.1 语料源数据与文本块
RAG首先需要一个知识库,这部分数据通常是原始文档和经过切分后的文本块。文本块从几百字符到上千字符不等,带有文档ID、章节序号、标题、标签、权限等信息。这部分数据的特征是:写入后很少修改,但量会持续增长,并且需要支持按文档、分类、标签等条件做精确查询,供调试、审计和局部更新使用。
对于这类数据,关系型模型或文档模型非常合适,需要支持基础的过滤条件组合查询,例如“找到某个批次导入的所有文档分块”“删除某个用户上传的全部文本块”等操作。如果就存几万条文本块,任意一款数据库都能应付;但如果到了百万级,就必须考虑查询效率了。
2.2 向量索引与距离计算
这是向量数据库的主场。文本块经过Embedding后变成高维向量,常见的是768维或1024维浮点数组。检索时需要通过相似度计算找到最相关的向量,本质上是大规模高维空间下的最近邻搜索。
这一层最核心的指标是召回率、查询延迟和索引构建耗时。不同的库在这三项指标上的取舍差异巨大。DuckDB走的是暴力精准扫描路线,Milvus采用的是HNSW、IVF等近似最近邻算法,SurrealDB也在较新版本中加入了向量索引支持。只看单条查询延迟的话,近似算法会远快于暴力扫描,但召回率会打折;而暴力扫描在数据量不大、查询并发不高时,延迟其实也可接受,关键是你要知道自己能容忍多快的查询。
2.3 会话状态、用户数据与系统元数据
RAG应用不只是“查文档”,它还需要维护对话历史、收藏记录、用户反馈、用量统计等状态数据。这部分数据的特征是:读写频繁、结构各异、单条数据量小、与用户ID强关联。
这类场景里,关系型数据库和文档数据库都做得很好,但向量数据库普遍不擅长。这也是为什么很多RAG项目最终会做成“组合架构”,而不是把全部数据塞进一个库——向量库专注做相似度检索,关系库或文档库负责用户数据和会话管理。
3. 三个参赛选手的能力画像
3.1 DuckDB:被低估的嵌入式英雄
DuckDB在RAG选型讨论中亮相,很多人会觉得意外。毕竟它的定位是嵌入式OLAP数据库,主打的是分析型工作负载,比如跑聚合、做联表、统计指标。但它有一个杀手级特性:原生支持向量搜索所需的距离函数,可以在SQL里直接完成向量相似度计算。
DuckDB还支持加载社区扩展,其中就包含向量相似度计算的函数库,可以直接写SQL查询。对于百万级以下的数据量,DuckDB的暴力扫描性能足够好,而且它没有独立服务端进程,直接嵌入到Python应用中,这在原型阶段优势太明显了。数据集是几万条文档块时,我实测过召回率100%,单条查询延迟也在几十毫秒以内。
但DuckDB的短板也很明显。它不是为高并发而生的,设计目标是单机处理分析查询,不适合作为面向大量客户端并发写入和查询的服务端数据库;写入方式偏向批量,不适合高频小规模更新。如果RAG应用要直接暴露给终端用户,DuckDB无法作为独立服务支撑在线业务。
3.2 Milvus:更专业的向量搜索引擎
Milvus的设计思路就是“把向量检索做到极致”。它采用分布式架构,内置多种索引类型,支持混合查询——就是同时过滤结构化属性和向量相似度,还提供了完整的SDK、监控体系和水平扩展能力。在生产级RAG服务中,Milvus通常被用作召回引擎。
Milvus的数据模型围绕“集合”和“字段”组织,每个向量是一个实体,除了向量字段外可以附带动态字段或标量字段。构建索引时会有明确的构建时间和内存占用,查询时可以指定过滤表达式来缩小范围。它是真正的“为向量服务设计的数据库”。
代价是运维复杂度明显更高。跑一个单机版还好,一旦上集群,就涉及协调节点、数据节点、查询节点和对象存储的配置管理。数据量不大时,Milvus的分布式优势完全发挥不出来,反而白白增加了部署成本和学习成本。
3.3 SurrealDB:多模型数据库的多面手
SurrealDB是这三者中最“年轻”的一个。它把关系表、文档结构和图关系整合在一个引擎里,也支持向量类型和索引。设计理念是:一个数据库就够了,场景切换不需要换引擎。
在实际体验中,SurrealDB的SurrealQL语法和传统SQL差异很大,需要花时间适应。它的REST API、实时通知(Live Queries)、权限控制体系非常完善,这在生产环境中很实用。向量索引引入后,可以直接在记录上存向量字段,在同一套查询里完成文本属性过滤和相似度排序,避免了多库拼装的复杂逻辑。
不过要客观说,SurrealDB的向量检索能力在成熟度上还赶不上Milvus。索引类型相对单一,大规模向量场景下的调优空间有限。它更适合中小规模、业务逻辑复杂的应用,一个库管所有状态和检索,省去了多系统的同步成本。
4. 选型评测维度与实测思路
选定数据库不能只看技术热度,要回到三个核心维度:性能表现、功能边界、运维成本。以下是我在对比三款产品时使用的评测框架。
4.1 性能指标怎么测才有效
评测向量数据库时,最忌直接用随机生成的高维向量来跑基准测试,因为真实文本向量的分布特征和你随意生成的向量分布差异很大。我自己踩过这个坑,早期某个项目用随机向量测出来延迟很低,换成了真实文本的嵌入向量后,查询延迟出现了数倍波动。所以评测时固定使用同一套真实文本数据集,并统一Embedding模型,才谈得上对比的公平性。
针对DuckDB、Milvus、SurrealDB,我重点测了四个指标:
- 批量导入耗时:写入1万条、10万条、50万条文本块,观察导入总耗时和资源占用;
- 索引构建时间:Milvus构建HNSW索引、SurrealDB构建向量索引的时间差异;
- P95单条查询延迟:在固定并发下打压力度,观察延迟分布;
- 混合过滤+向量检索延迟:在带标签过滤条件和无过滤两种情况下分别测试。
结果比较有意思。10万条以内,DuckDB依靠暴力扫描,查询延迟稳定在20到80毫秒之间波动,和构建了索引的Milvus差距不算大;到了50万条以上,Milvus的HNSW优势就体现出来了,延迟在10毫秒以内,而DuckDB的暴力扫描性能随着数据量增长明显退化。SurrealDB在查询延迟上比DuckDB略高,功能上更灵活,但索引参数调优不像Milvus那么精细。
4.2 功能边界对比
列一个表会更直观:
| 维度 | DuckDB | Milvus | SurrealDB |
|---|---|---|---|
| 部署形态 | 嵌入式,无独立服务 | 独立服务,可集群 | 独立服务,可嵌入 |
| 数据模型 | 关系型(表结构) | 集合+字段 | 多模型(表+文档+图) |
| 向量索引类型 | 无独立索引,靠暴力扫描 | HNSW、IVF等 | 自研向量索引,选项较少 |
| 混合查询能力 | SQL天然支持,但无索引加速 | 支持标量过滤+向量检索 | 支持记录属性+向量相似度 |
| 高并发支持 | 弱,设计面向分析场景 | 强,面向在线服务 | 中等,适合中小规模在线场景 |
| 运维复杂度 | 极低,pip install即可 | 中等偏高 | 中等 |
这张表透露了一个关键信息:这三款产品并没有落在完全同一的赛道里。DuckDB和SurrealDB在中小规模场景下是直接竞争对手,Milvus更偏向大规模在线检索场景。选型时先确认自己的数据规模和并发量级,再谈哪个好。
5. 典型RAG场景下的方案组合与取舍
5.1 轻量级原型阶段:DuckDB是最佳搭档
个人做项目原型、内部知识库Demo或数据处理脚本时,我强烈推荐DuckDB。原因非常直接:安装一条pip命令就能完成,无需启动服务,无需担心网络端口和权限配置,所有数据落在本地文件里,备份就是把文件拷贝一份。原型阶段迭代快,文档重切、Embedding重跑、数据清理是常规操作,DuckDB用SQL语句就能完成复杂的数据变换,比在向量数据库里折腾省事太多。
我做过一个文档问答原型,数据量2万条文本块,DuckDB查询延迟保持在80毫秒内,加上大模型推理时间,整体响应在可接受范围。后面分享给几个同事做内测时,DuckDB暴露出并发短板——多人同时查询时延迟明显上升。
这里的关键心得是:DuckDB解决的是“单机分析+原型验证”的问题,如果项目有清晰的上线预期,那么从一开始就要预留迁移路径,代码中将对数据库的操作封装到独立的仓储层,避免SQL语句散落各处。后期无论换Milvus还是SurrealDB,都能平滑迁移。
5.2 生产级在线检索:Milvus的成熟优势
当RAG应用要面向外部用户提供在线问答服务,数据量达到百万级、查询并发几十甚至上百时,Milvus是更稳妥的选择。它的成熟度体现在工程细节上:索引参数多样,可以根据数据分布调整M、efConstruction、efSearch等参数;支持多副本和水平扩展;有Prometheus监控指标;SDK覆盖Python、Java、Go等主流语言。
Milvus的混合查询能力在实际RAG场景中价值很大。比如一家企业有不同部门的文档,用户可以指定只看某一部门的资料,这时查询会附加过滤条件。Milvus会借助标量索引先做过滤再做向量检索,既保证准确性又不会让延迟劣化得太严重。
但Milvus不适合当全能存储存在。会话记录、用户反馈、用量统计这类数据放进去,既浪费存储空间,又会增加集合管理的复杂度。生产架构中我通常把它和一台简洁的PostgreSQL搭配使用——Milvus管向量召回,PostgreSQL管业务状态,两者通过应用代码协调。
5.3 多租户业务逻辑复杂:SurrealDB的用武之地
SurrealDB更适合业务逻辑复杂、数据关联密集的中小型应用。假设你在做一个面向多个团队的知识库平台,需要为每个团队隔离数据、记录团队成员关系、保存文档元数据和向量数据,SurrealDB的单库搞定能力就非常有吸引力了。
我试用SurrealDB时最大的感受是:它的权限体系和RLive Query对应用开发太友好了。权限规则可以精细到每一条记录,前端可以直接订阅实时更新,客户端通过WebSocket拿数据,省掉了自己写同步层的步骤。这意味着后端代码量能大幅减少。
需要注意的问题是,SurrealDB的向量检索能力有待更多项目验证。我在测试中发现,数据量超过10万条后,索引参数对查询质量影响明显,可调参数少,社区经验也不像Milvus那样丰富。所以如果核心场景是超大规模召回,我建议慎重选择SurrealDB;如果业务属性重、检索量有限,它的综合效率反而较高。
5.4 三种组合架构的实战建议
根据项目规模和应用形态,我总结出三套组合架构,可以直接作为选型参考:
第一种,轻量内部工具。DuckDB单库存文本块和向量层,元数据用SQL查询,大模型调用外部API。适合查询量低、纯内部使用、没有用户体系的场景。优点是开发和部署成本极低,DuckDB的数据文件可以直接离线分享,冷备份也很省心。
第二种,标准在线RAG服务。Milvus做向量召回,PostgreSQL或MySQL存用户和会话数据,两者配合。适合对外提供产品化服务,对查询延迟和数据一致性有明确要求。数据管道中用DuckDB做预处理和批量分析,可以充分利用其数据处理速度。
第三种,多租户应用平台。SurrealDB作为主数据库,既管业务实体和关系,也存向量数据,用权限体系隔离租户数据。适合功能复杂、数据关联多、团队规模有限的项目。
6. 实操中容易踩的坑
6.1 向量维度与距离算法一致性
这是最隐蔽的坑。Embedding时你用的是OpenAI的三千维接口,那存储和检索时的距离函数就必须匹配。向量数据库中相似度计算通常有内积、余弦相似度、欧氏距离三种,选错距离函数会导致检索结果与实验阶段不一致。DuckDB中自己要写清楚距离逻辑,Milvus中建Collection时就要指定metric type,SurrealDB的向量函数同样要显式声明。任何一步不一致,结果都会莫名其妙地偏差。
6.2 Milvus Collection设计与动态字段
Milvus的数据模型是先定义schema后写入数据,字段一旦建好就很难调整。如果你要把文档标题、来源、权限等属性作为过滤条件字段,在一开始就要设计好schema。一个常见优化手段是用动态字段(Dynamic Field)存储额外元数据,避免为每个新属性重建集合。但注意动态字段不能直接参与过滤,那会造成查询性能降低。实测下来,为高频过滤字段单独建标量索引,查询体验提升非常明显。
6.3 DuckDB高并发时当作服务使用
DuckDB的文档明确说它不适合高并发服务场景。但实际项目中总有团队图省事,直接用FastAPI包一层,把DuckDB当在线服务数据库来跑。小流量下问题不大,流量一旦上来,锁竞争和内存占用会直线拉升。我在一个项目里被这种用法坑过。解决方案是强制增加缓存层、降低查询频率,或者干脆迁移到独立数据库服务。
6.4 生产环境监控和可观测性
RAG应用的数据库层监控常常被忽视。Milvus有Dashboard可以看到查询延迟和索引状态,DuckDB把状态暴露在进程内部需要手动采集,SurrealDB提供系统表但文档不够详细。上线前务必把CPU、内存、磁盘、查询延迟、错误率等指标接入监控系统。生产环境上因为索引构建导致CPU飙高进而拖垮整个服务的案例,我见得太多了。
7. 我现在的选择方式
项目还在原型阶段时,我的默认选择始终是DuckDB加Python包,快速验证检索效果和整体链路。确定业务规模后,我会做一个快速评估:给未来半年的数据量乘以查询并发量估值,如果数据量在百万以下、并发低,SurrealDB整套方案能极大简化架构;如果数据量大或并发要求高,就用Milvus承担向量检索,让更传统的数据库负责业务状态。
选型没有绝对的“最好”,关键是你对数据库特性的认知是否匹配业务需求。把DuckDB当分析工具、Milvus当检索引擎、SurrealDB当业务数据底座,三者各归其位,RAG应用的数据层会清爽很多。希望这篇文章能帮你避开我踩过的坑。