本文档提供了一些建议,可帮助您优化 Spanner 中向量搜索的性能。
了解 Spanner 基础知识
如需进行有效的 Spanner 向量搜索性能测试,请了解 Spanner 基础知识。例如,由于缓存,立即重新执行同一查询可能会更快。如需测试主要使用热数据的应用的性能,请先执行预热读取。
请参阅以下指南:
Spanner 会根据 数据库拆分并行处理查询。使用持续的生产查询负载进行测试可以实现 基于负载的拆分, 从而通过提高并行度来提高查询性能。如需提高未来负载的并行度,请考虑 预先拆分数据库,尤其是 对于 KNN。
向量搜索最佳实践
本文档介绍了以下向量搜索最佳实践:
为嵌入列添加注解
使用
vector_length为嵌入列添加注解。
此注解可针对
K 最近邻 (KNN) 搜索进行性能优化,并且是
近似最近邻 (ANN)
搜索的前提条件。
使用 top-k 查询
如需查找最近邻,请使用带有 LIMIT 的 ORDER BY 子句。top-k 查询针对向量搜索进行了高度优化。避免在 WHERE 子句中按距离阈值进行过滤。
例如,不建议使用以下查询:
SELECT d.DocId
FROM Documents AS d
WHERE COSINE_DISTANCE(d.DocEmbedding, @vector) < 1;
请改用以下查询:
SELECT d.DocId
FROM Documents AS d
ORDER BY COSINE_DISTANCE(d.DocEmbedding, @vector)
LIMIT 10;
使用 top-k 查询不仅更简单(因为它消除了距离阈值调整),而且还可针对向量搜索进行专门的性能优化。
为 LIMIT 子句使用 SQL 字面量
如果 top-k 限制是固定的,请使用 SQL 字面量而不是参数。例如,使用 LIMIT 10 而不是 LIMIT @limit。这会为
Spanner 查询优化器
提供更多信息,以便选择最佳
查询执行计划。
使用面向批处理的扫描
向量搜索查询是扫描密集型查询。对于 KNN 查询,请考虑使用
带有
scan_method=batch查询提示的面向批处理的扫描。
这是 ANN 查询的默认扫描方法。
对小型数据集使用 KNN
如果 KNN 足以满足您的延迟预算,请不要创建向量索引。KNN 更准确,避免了索引创建和维护费用,并且在任何过滤后的输入行数较少时,其性能可能优于 ANN。
使用二级索引加快过滤后的 KNN 的速度
如需提高过滤后的 KNN 查询的性能,请在过滤列上创建 二级索引。 例如,请看以下查询:
SELECT d.DocId
FROM Documents AS d
WHERE Category = 'toy'
ORDER BY COSINE_DISTANCE(d.DocEmbedding, @vector)
LIMIT 10;
如果每个类别的文档数量少于几万个,并且您的应用可以接受 100 毫秒的查询延迟,请在 Category 列上创建二级索引。将 DocEmbedding 列存储在索引中:
CREATE INDEX ON Documents(Category) STORING (DocEmbedding);
此索引创建有助于加快过滤后的查询的速度。
对大型数据集使用 ANN
如果在评估过滤条件后行数较多,请创建向量索引并使用 ANN 搜索。有几种技术可以加快使用 ANN 进行过滤的速度:
存储过滤列:如需在遍历向量 搜索时启用过滤,请将过滤列存储在向量索引中。这样可以在执行过程中尽早移除不符合条件的行。
CREATE VECTOR INDEX ON Documents(DocEmbedding) STORING(Category);键过滤列:如需加快对移除许多结果的高度选择性列 的过滤速度,请将这些列组织为向量索引中的 其他键列。对于这些额外的键,指定完全相等(使用
=运算符)的查询速度最快。对任何这些额外的键使用IN子句都无法实现相同级别的加速。CREATE VECTOR INDEX ON Documents(DocEmbedding, Category);避免存储大型列或将其用作键:这样做可能会稀释嵌入的数据块,从而降低读取效率。作为替代方案,请考虑在索引中使用哈希列,并在 top-k 后将原始大型列用作后过滤条件。
创建过滤后的(部分)向量索引:如果您仅查询数据集的子集,并且过滤条件定义了该子集(例如
Category = "Tech"),请创建过滤后的或部分向量索引。