sync_threshold 用来定义,累计多少条向量才触发,从 WAL 队列刷入 HNSW 内存索引、并持久化 HNSW 索引文件到磁盘这个动作。
参数的默认值为 1000,和 max_neighbors/ef_construction 不一样,这个参数在集合创建之后可以动态修改,不需要重建集合。
Chroma 的写入链路如下:
client.add()
→ 写入 SQLite 的 embeddings_queue(队列表,不是 SQLite WAL!)
→ SQLite 事务提交成功 → add() 返回 OK
↓ 后台索引线程持续轮询消费队列
按 hnsw.batch_size 分批取出队列里待索引向量
→ 逐条执行 HNSW 插入逻辑(ef_construction 建图,加入内存 HNSW)
→ 新增累计达到 sync_threshold 条已经入内存 HNSW 的向量时
→ 将完整内存 HNSW 索引序列化 dump 到磁盘文件如何正确调整 sync_threshold 配置?
调小:dump 更频繁;队列积压少,查询时需要暴力扫描的未索引向量更少,查询更稳;代价是频繁全量序列化,写入侧周期性 IO/CPU 开销更高。
调大:减少重量级 dump 次数,大批量导入速度更好;但导入期间容易堆积大量还没进 HNSW 的队列数据,查询要合并【HNSW 检索 + 线性暴力扫描队列】,查询延迟升高、召回不稳定。
下面通过一个场景来介绍 sync_threshold 的用法:
假如我们需要批量导入大量的数据,可以先调大 sync_threshold,导完再调回来,代码如下:
# 灌数据前:攒着一起刷
col.modify(configuration={
"hnsw": {
"sync_threshold": 100000,
"batch_size": 1000
}
})
# ... 灌 100 万条 ...
# 灌完:恢复正常,让它赶紧刷
col.modify(configuration={
"hnsw": {
"sync_threshold": 1000,
"batch_size": 100
}
})注意,改完参数只是改阈值,不会强制立刻 dump。 全部灌完之后,如果想确保索引落盘,最好额外执行 persist() 持久化:
# 强制持久化 HNSW
col.persist()不过说实话,单机版 Chroma 的写入瓶颈通常在 embedding 计算上,而不是索引。如果你是自己算好向量再灌,sync_threshold 的影响没那么明显。