Sizing Lakebase Search: lessons from a real app and 4 million passages
TL;DR · AI 摘要
Lakebase Search通过PostgreSQL扩展实现混合搜索,优化缓存和索引策略可显著降低延迟并控制成本。
核心要点
- 本地文件缓存匹配向量索引可使95-98%页面保留在内存,延迟降至毫秒级
- 候选池从1000缩减至200仍保留90.5%的top-10结果,读取量减少至1/3
- 推荐生产环境使用$31-40/月的0.5 CU基线配置避免冷启动
结构提纲
按章节快速跳转。
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- Lakebase Search优化实践
- 架构特性
- PostgreSQL扩展实现混合搜索
- 向量索引(IVF+RaBitQ)
- 优化策略
- 本地缓存配置优化
- 候选池规模控制
- 成本模型
- 按需计费模式
- 推荐基线配置
金句 / Highlights
值得收藏与分享的关键句。
RaBitQ量化技术将每个向量压缩至约1bit/维度,显著降低存储需求
候选池规模缩减至1/5时仍保留90.5%的top-10结果,验证搜索效率
生产环境推荐$31-40/月的0.5 CU基线配置,避免冷启动带来的性能下降
Lakebase Search 的规模评估:来自实际应用和 400 万段落的经验 | Databricks 博客
跳至主要内容
Lakebase
2026 年 10 月 15 日
Lakebase Search 的规模评估:来自实际应用和 400 万段落的经验
作者:Philipp Tiefenbacher
摘要
- Lakebase Search 作为 Postgres 扩展,在应用数据库内部运行向量和 BM25 关键字搜索,开发者无需维护独立的搜索系统或第二条事务路径即可实现混合搜索。
- 基准测试表明,将本地文件缓存大小调整到与向量索引大致匹配时,可使 95~98% 的页面保留在内存中,向量预热延迟降至个位数毫秒,同时将候选池从 1000 缩小到 200 时,在页面读取量减少三分之一的情况下仍可保留 90.5% 的前 10 名结果。
- Lakebase Postgres 仅在运行时计费,14 分钟的负载测试处理 109k 请求仅消耗了 Lakebase Postgres 计算资源 0.02 美元,因此建议生产环境以每月 31~40 美元的 0.5 CU 基线持续运行,以避免冷启动。
Slide Hub 是 Databricks 的内部应用。现场工程师使用它从约 700 个内部演示文稿(包括活动演讲、产品方案和架构方案)中查找和复用幻灯片。搜索栏可通过语义和关键词查找单个幻灯片,Model Context Protocol(MCP)服务器为 AI 代理提供相同的搜索功能。该应用将幻灯片、投票、搜索遥测数据和变更历史存储在 Lakebase Postgres 中。我们使用 Slide Hub 作为基准来评估 Lakebase Postgres。这是一个具有真实使用场景和真实用户的实际应用,因此其数据展示了数据库在实际工作负载下的表现。
本文面向在 Databricks 上构建应用的开发人员和架构师,他们希望在应用自身的 Lakebase Postgres 数据库中实现搜索功能。假设读者了解 SQL 和 PostgreSQL 的基础知识。如果您计划在 Lakebase Postgres 上实现搜索栏或代理工具,以下数据可帮助您在投产前选择合适的计算规模。
本文将展示 Slide Hub 如何在 Lakebase Postgres 内部运行搜索,其性能瓶颈、成本以及 Lakebase Search 在处理 100 万至 400 万条公共语料库数据时的表现。
一个数据库同时支持应用和搜索
Lakebase Search 于 9 月正式发布。它是一组 Postgres 扩展,因此可与应用表并行运行。应用无需将数据复制到独立的搜索系统中,开发者也无需维护第二条事务路径。
两个 CREATE EXTENSION 命令即可启用组件。lakebase_vector 存储嵌入向量(代表文本含义的数字向量),并支持 lakebase_ann 索引进行近似最近邻(ANN)搜索。lakebase_text 支持 lakebase_bm25 索引进行 BM25 搜索(一种按查询词匹配程度对文本进行排序的标准方法)。lakebase_tokenizer 是可选组件。ANN 索引使用 IVF 分区(将相似向量分组,使查询只需读取少量组)和 RaBitQ 量化(将每个向量压缩到每维约 1 位)。BM25 使用 <@> 运算符对文本进行评分。
Slide Hub 的 23k 幻灯片行与投票、遥测数据、变更历史、预览和两个索引存储在同一个无服务器 Lakebase Postgres 实例中。应用通过单个连接和统一的权限模型读取数据和索引。
搜索查询
Slide Hub 执行混合搜索。它结合了向量搜索(用于查找与查询语义相似的幻灯片)和 BM25 关键词搜索(用于查找包含查询词的幻灯片)。每种方法分别返回其最佳匹配的简短列表,即候选结果。一条 SQL 语句承载了完整的排序策略。它对每个候选列表进行排序,融合两种排序结果,应用应用层过滤条件,并合并投票结果。搜索和应用逻辑共享一个数据库连接、一组权限配置以及一个事务提交。
Slide Hub 从每种方法中获取 200 个候选结果。它通过倒数排名融合(RRF)在 k=60 的参数下融合两个列表:每个列表中幻灯片的得分计算为 1/(60 + 其排名位置),两个得分相加。相似度阈值 0.70 会过滤掉与查询距离过远、对当前嵌入模型无用的向量匹配结果。当查询匹配幻灯片标题时,标题层级会增加权重。备注内容的权重为 0.5。作用域过滤器将结果限制在用户有权限查看的资产范围内。
负载下应用的性能限制
一个搜索请求使用两个独立的计算单元,任一单元都可能成为性能瓶颈。
Lakebase Postgres 计算单元运行数据库。Lakebase Postgres 以计算单元(CU)为单位进行规模配置。1 CU 为数据库分配约 2 GB 内存,并分配相应的 CPU 和本地 SSD 资源。计算单元可在 0.5 CU 至 64 CU 的最小/最大规模之间自动扩展,最大规模不得超过最小规模的 16 CU。固定规模计算单元最高可达 112 CU,且最多 32 CU 的计算单元可扩展至零规模。Postgres 将表和索引存储在 8 KB 的页面中。Lakebase Postgres 在计算单元上通过本地文件缓存(LFC)存储最近读取的页面。缓存容量随 CU 规模增长,最多可使用计算单元内存的 75%。未命中缓存的页面需要从存储设备读取,耗时更长。
Databricks Apps 计算单元运行 Slide Hub Web 服务器。其规模按应用配置固定。中型应用最多提供 2 vCPU 和 6 GB 内存,大型应用最多提供 4 vCPU 和 12 GB 内存。Slide Hub 运行一个应用实例。其中每个 Python 工作进程维护 8 个数据库连接池,因此 2 个工作进程最多打开 16 个连接,4 个工作进程最多打开 32 个连接。
每个请求中,应用会嵌入查询文本,向 Lakebase Postgres 发送一条 SQL 语句并返回结果。为确定性能瓶颈,测试通过逐步调整单侧参数进行验证:固定 Lakebase Postgres 的 CU 规模并调整应用配置,或保持应用配置不变调整 CU 规模。负载生成器模拟发送搜索请求的用户,并逐步增加用户数量。下表显示了不同 Lakebase Postgres 规模和应用规模下,500 用户时的请求吞吐量和中位数延迟(p50)。
- 1 CU,中型应用(2 个工作进程):196 请求/秒,p50 1.8 秒
- 0.5-1 CU,大型应用(4 个工作进程):193 请求/秒,p50 1.6 秒
- 2 CU,中型应用(2 个工作进程):201 请求/秒,p50 1.8 秒
- 4 CU,中型应用(2 个工作进程):219 请求/秒,p50 1.6 秒
- 8 CU,中型应用(2 个工作进程):336 请求/秒,p50 1.0 秒
- 16 CU,中型应用(2 个工作进程):349 请求/秒,p50 1.0 秒
- 16 CU,大型应用(4 个工作进程):至少 662 请求/秒,p50 343 毫秒
在 CU 规模不超过 4 时,Lakebase 是性能瓶颈。大型应用即使将工作进程和连接数翻倍,在 1 CU 规模下也未带来性能提升。1 CU 规模下,搜索语句平均耗时 146 毫秒,从存储设备读取了 14.9M 页面,文件缓存为 1.5 GB。当扩展到 8 CU 时,平均耗时降至 34 毫秒,缓存容量达到 12 GB,吞吐量提升约 50%。
从8个CU开始,应用程序成为瓶颈。使用相同MEDIUM应用的16个CU仅增加4%,其数据库连接大多处于空闲状态。使用4个工作者的LARGE应用在16个CU下可达到至少662 req/s,此时负载生成器成为瓶颈。首先优化查询,然后扩展Lakebase Postgres直到应用程序工作者成为瓶颈,最后再扩展应用程序。
关键结论:扩展前先找到瓶颈。低于8个CU时,增加Lakebase Postgres的CU。从8个CU开始,为应用程序添加更多工作者。
连接池仍然必要。在50个用户的情况下,没有连接池时应用程序达到45 req/s和2.4秒p95,使用连接池时达到85 req/s和0.7秒p95。在负载下,嵌入缓存没有可测量的差异。
候选池和冷启动
候选池限制决定了查询访问的页面数量。在冷缓存情况下,这个数量决定了延迟。Slide Hub默认每个方法设置1,000个候选。文档模式使用40个候选。候选池限制实验仅修改candidate_limit参数,对20个公共查询在三种状态下进行测量。冷启动是计算扩展到零且缓存为空时的第一个查询。首次访问是计算唤醒后查询的首次运行。重复是缓存中已有页面的相同查询再次运行。页面访问次数统计查询从任何来源读取的页面数量。Top-10重叠率是前10个结果与1,000个候选结果匹配的比例。
- 40个候选:冷启动127毫秒,首次访问13毫秒,重复5.0毫秒。访问5,655个页面。Top-10重叠率74.5%。
- 100个候选:冷启动240毫秒,首次访问16毫秒,重复7.9毫秒。访问7,355个页面。Top-10重叠率89%。
- 200个候选:冷启动387毫秒,首次访问24毫秒,重复11.7毫秒。访问10,401个页面。Top-10重叠率90.5%。
- 1,000个候选:冷启动740毫秒,首次访问109毫秒,重复35.3毫秒。访问28,972个页面。Top-10重叠率100%(基准)。
在200个候选情况下,Top-10的90.5%保持不变,匹配数量达到1,000个候选时的81%。用户很少翻页超过200个结果,因此Slide Hub现在默认使用200个候选。从与应用程序位于同一云区域的作业端到端测量,200个候选的冷启动搜索耗时2.9秒,重复搜索仅需40毫秒。冷启动时间包含两个部分:连接等待约1秒直到端点唤醒,然后每个查询从存储中读取页面直到缓存预热。新连接上的首次查询还需约75毫秒的规划时间。
关键结论:保持候选池规模较小。200个候选可保留90.5%的Top-10结果,读取约1,000个候选的三分之一页面,并将冷启动延迟减半。
扩展:1M至4M条MIRACL英文数据
扩展测试使用MIRACL英文语料库,该语料库由维基百科构建。完整语料库包含32,893,221个段落。我们使用gte-large-en-v1.5模型(1024维开源模型,与Slide Hub嵌入尺寸相同)进行嵌入。该模型在单个A10G GPU上以每秒379个段落的速度进行自托管。整个语料库处理耗时2.95 GPU小时,成本为48.87美元(与模型服务端点相同工作量相比)。GPU向量与端点向量完全匹配(余弦均值1.0000,最小值0.9978)。
我们构建了三个子集:1M、2M和4M段落。lakebase_ann索引随语料库扩展:1M时5.8GB,2M时11.5GB,4M时23.0GB。二进制COPY在8个CU下用19分钟加载所有4M行。
Lakebase Postgres 每个 CU 持有约 1.6 GB 的文件缓存。扩展引发了一个问题:当索引大于缓存时会发生什么?每个测试单元对应一个语料库规模和一个 CU 规模,因此缓存是索引的一个已知比例。我们将这个比例称为缓存比例:缓存大小除以向量索引大小。比例为 1.0 表示索引刚好能容纳。命中率是指查询读取的页面中不来自存储的比例。
我们对每个单元运行了三种查询组合。均匀组合每次发送新标题且从不重复,这是缓存最糟糕的情况。偏斜组合从包含 20,000 个标题的池中抽取,遵循 Zipf 分布,这是搜索流量的常见模型。冷启动组合在唤醒后立即运行查询,此时缓存为空。在均匀和偏斜测试之前,会先运行预热阶段,直到命中率不再变化。我们称预热后的结果为“预热状态”。
命中率遵循缓存比例
命中率与缓存比例的关系。2M 和 4M 曲线重叠,因此比例是横轴。
命中率取决于缓存比例。语料库规模不会改变这一关系:2M 和 4M 的数据点落在同一条曲线上。在 0.07 的比例下,偏斜组合的命中率为 45%;在 0.57 时达到 86%;在 1.14(索引刚好容纳)时达到 97%。均匀组合的命中率略低几个点,因为它不重复使用任何内容。
这给出了一个规模规则。测量索引大小,选择目标缓存比例对应的 CU 规模,然后从曲线上读取命中率。该比例适用于所有语料库规模,因此 2M 的测试可以预测 4M 的行为。
要点:应根据向量索引大小而非行数来确定缓存规模。与索引大小相当的缓存可使 95% 至 98% 的页面无需存储访问即可命中。
延迟遵循命中率
预热状态下向量和混合搜索的延迟与缓存比例的关系。
预热向量搜索的 p50 延迟从比例 0.07 的 187 毫秒降至比例 2.3 的 4 毫秒。混合搜索在比例接近 1 之前保持在 800 毫秒左右,随后降至 33 毫秒。混合查询的关键词部分读取最多页面,因此从完整缓存中获益最大。
要点:当缓存包含索引的三分之一以下时,向量搜索耗时 160 至 230 毫秒;当整个索引容纳在缓存中时,耗时降至 11 至 23 毫秒。
延迟与存储缺失的关系。一次缺失约增加 0.3 毫秒。
一次缺失是指一个不在本地文件缓存中的 8 KB Postgres 页面。在向量索引中,一个页面包含一个或两个嵌入向量。从存储读取一个页面需要固定时间。所有测量查询中,向量搜索每缺失一页会增加约 252 微秒的执行时间,混合搜索则增加 316 微秒。缺失 2000 页的查询大约增加 0.5 秒。完整缓存几乎消除了所有缺失。这就是缓存比例决定延迟的原因:它决定了每个查询从存储读取的页面数量。
要点:每个存储页面增加约 0.3 毫秒。将查询的存储缺失数乘以 0.3 毫秒,即可估算缓存为您节省的时间。
从缓存读取时,延迟几乎不随语料库规模增长
从缓存和存储读取时的延迟与索引规模的关系。
保持缓存比例接近 1.0 并改变语料库规模。预热向量延迟在 1M 到 4M 之间保持在 11 至 23 毫秒之间。预热混合搜索延迟保持在 276 毫秒左右。从存储读取的冷查询随语料库规模增长:冷向量查询从 1M 的 44 毫秒增至 4M 的 133 毫秒,冷混合查询在 4M 时达到 911 毫秒。
这是“你不需要将整个索引加载到内存中”的诚实表达:你确实不需要,因为架构保持计算内存平坦。RaBitQ 每个维度存储约 1 位,比 float32 小 32 倍,IVF 每个查询仅读取少量分区。索引由存储支持,因此计算资源可以很小或扩展到零。未命中缓存的查询需要承担未命中的代价,缓存命中率控制着这种情况发生的频率。
要点:随着语料库扩展增加计算资源,缓存命中时的延迟保持稳定。只有未命中缓存的查询在语料库增长时会变慢。
吞吐量随计算资源扩展
每秒混合查询总数与开放连接数的关系,400万段落。
吞吐量测试直接将混合查询发送到 Lakebase Postgres,不经过应用层,因此仅衡量数据库性能。测试同时向 Lakebase Postgres 打开 1、4、16 或 64 个连接。每个连接发送查询、等待响应后继续发送下一个查询。图表显示所有连接的总查询数每秒。当曲线变平后,增加连接数无法提升查询量。此时 Lakebase Postgres 达到性能极限,每个查询等待时间反而增加。负载生成器自身的 CPU 使用率接近零,因此所有性能数据均由 Lakebase Postgres 决定。
在 400万语料库中,偏斜混合模式在 2 CU 时达到约 4 查询/秒,8 CU 时达到 15 查询/秒,16 CU 时达到 65 查询/秒。64 个连接时,单个查询的中位等待时间在 2 CU 时为 14.5 秒,8 CU 时为 5.2 秒,16 CU 时为 343 毫秒。均匀混合模式在 16 CU 时达到 30 查询/秒的峰值,因为其从不复用页面。吞吐量由计算资源规模和缓存命中率共同决定。
将这些数据解读为负载下缓存未命中的代价。真实应用中的大多数查询会重复或聚类,因此稳态容量由缓存命中率决定,而非均匀混合模式。
要点:增加 CU 可使吞吐量翻倍,同时提升 CPU 使用率和缓存容量。从 8 CU 升级到 16 CU 使偏斜吞吐量从 15 查询/秒提升至 65 查询/秒。
与精确搜索的召回率对比
lakebase_ann 索引是近似索引。Recall@10 表示在对所有向量进行精确搜索时,索引返回的真正前 10 个最近段落所占比例。索引将向量划分为分区(IVF),lakebase_ann.probes 设置查询读取的分区数量。默认探针数下,Recall@10 随语料库规模变化不大:100万时为 0.74,200万时为 0.75,400万时为 0.75。更多探针数会以延迟换取召回率。
在 400万语料库中,默认索引和高质量索引构建下 Recall@10 与探针数的关系。
默认索引在 400万语料库中,109 个默认探针数实现 0.74 召回率耗时 3 毫秒,2000 个探针数实现 0.95 召回率耗时 49 毫秒。使用 build_mode = 'quality' 构建的索引在每个探针数下召回率更高:默认探针数 3 毫秒实现 0.80,2000 探针数约 49 毫秒实现 0.97。其构建耗时 52 分钟(16 CU)。将 lakebase_ann.epsilon 提升至测试中允许的最高值 4,召回率提升不足 0.3。[9] 召回率取决于数据和嵌入模型,因此需在自身数据上进行测量,并根据应用需求选择探针数。Lakebase Search 支持单个索引超过 10 亿向量。[1]
Takeaway: 使用 build_mode = 'quality' 构建向量索引。在默认探针数下,约3毫秒内将召回率@10从0.74提升至0.80,500探针时13毫秒达到0.91,而默认构建方式需要1000探针和20毫秒。成本体现在构建时间:在16 CU下处理400万段落耗时52分钟。仅在需要更高召回率时才应增加探针数。
成本
Lakebase 的计费方式遵循使用情况。暂停的计算单元不产生费用,存储单独计费。Lakebase 的成本约为 Slide Hub 30天账单的1%。Slide Hub 是内部应用,用户可接受搜索5分钟空闲后出现较慢的首次响应,因此其生产数据库在无人搜索时可扩展至零。
规模评估成本低廉。自托管嵌入整个语料库耗时2.95 GPU小时,而模型服务端点费用为48.87美元。一次区域内负载测试运行14分钟,按列表价格计费仅0.13美元:应用0.11美元,Lakebase Postgres 0.02美元。该服务在0.5至1 CU之间自动扩展,使用0.21 CU小时。在1000用户以内,该测试处理了109,602次请求且无错误。计算单元在0.5至16 CU之间运行,各次运行之间会暂停。在我们工作区的计费表中,1 CU小时等于0.213 DBU:按Premium列表价格约为0.085美元,按Enterprise列表价格在AWS US East约为0.11美元。
Takeaway: Lakebase Postgres 仅在运行时计费计算资源。14分钟负载测试使用了Lakebase Postgres 0.02美元的计算资源,这一成本约为Slide Hub 30天账单的1%。生产环境中应将最小计算单元设为0.5 CU而非扩展至零。按列表价格每月成本约31至40美元,搜索不再需要等待约1秒唤醒计算资源或从空缓存开始。[11] 让开发和测试分支扩展至零。
关于数据的说明
MIRACL 英文语料库是开源的。语料库采用Apache-2.0协议,其段落来自维基百科,遵循CC BY-SA协议。嵌入模型gte-large-en-v1.5采用Apache-2.0协议。本文仅报告聚合指标。任何1024维模型均可运行相同测试:替换嵌入步骤,保留表格、索引和搜索部分。
结论
将Lakebase Postgres想象成一位坐在大型书架前的读者。
- 书架代表存储,书桌代表缓存。桌上的书页读取速度快,书架上的书页需要走动,每次约0.3毫秒。
- 将书桌大小调整为常用书籍的规模。当缓存大小与向量索引相当时,几乎所有书页都在桌面上,向量搜索仅需数毫秒。
- 更多计算单元意味着更大的书桌和更多助手。这使每次搜索更快,并让Lakebase Postgres同时处理更多搜索请求。
- 减少书籍数量。选择200个候选项而非1000个,可携带约三分之一的书页,仍能保留前10名中的9个结果。
- 有序排列书架,再决定搜索数量。以quality模式构建的索引在默认探针数下3毫秒内可返回真实最近的10个段落中的8个,在2000探针下约50毫秒可返回100个中的97个。
- 应用程序有自己的书桌。一旦Lakebase Postgres变得快速,应用程序的工作者将成为瓶颈。此时应为应用程序增加更多工作者。此时增加Lakebase Postgres的计算单元已无帮助。
- 桌面上不需要放满所有书籍。Lakebase Postgres会从存储中读取其余部分。虽然速度较慢,但依然有效,缓存比例会告诉你这种情况发生的频率。
- 仅在有人阅读时才为桌面付费。当无人搜索时,Lakebase Postgres 可挂起并仅对存储收费;在 Slide Hub 中,这一费用约为 30 天账单的 1%。在生产环境中,保持一个小型桌面开放:0.5 CU 的成本约为每月 31 至 40 美元,可避免冷启动问题。
Databricks 提供三种搜索方式,每种都适用于不同场景。选择与你的数据相邻的那一种。
- Lakebase Search 在应用的 Postgres 数据库内部运行。当搜索必须与应用自身的表并行运行且需实时查看每次写入时,请使用它。
- AI 搜索(原 Vector 搜索)是 Unity Catalog 中 Lakehouse 表的托管搜索服务。它能与 Delta 或 Iceberg 表保持索引同步,并可为你生成嵌入向量。适用于 Lakehouse 数据的 RAG、代理和推荐场景。
- 全文搜索索引(Beta)可加速对托管 Delta 和 Iceberg 表的 SQL 查询。search 和 isearch 函数利用索引跳过不可能包含匹配项的文件,从而减少日志和关键词查询的数据读取量。它们过滤行但不为搜索栏对结果进行排序。
Slide Hub 将所有内容运行在同一个 Lakebase Postgres 数据库中:应用数据、向量索引和关键词索引。从 Lakebase Search 文档开始,然后使用自己的数据运行相同测试。
订阅最新文章
订阅我们的博客,将最新文章发送到你的邮箱。
注册
查看所有博客
slice-start id="_gatsby-scripts-1"
slice-end id="_gatsby-scripts-1"