本文汇总了向量数据库使用过程中的常见问题。
存储
单个表可存储多少向量?
默认情况下,非分区表的最大限制为32 TB,而分区表可以拥有数千个该大小的分区。
是否支持复制?
支持。PGVector使用WAL日志,支持复制和时间点恢复。
如果索引超过2,000维怎么办?
能否在同一列中存储不同维度向量?
支持。可使用vector
类型代替vector(3)
。
CREATE TABLE embeddings (model_id bigint, item_id bigint, embedding vector, PRIMARY KEY (model_id, item_id));
但是,此时只能通过表达式索引或部分索引为相同维度的行创建索引。
CREATE INDEX ON embeddings USING hnsw ((embedding::vector(3)) vector_l2_ops) WHERE (model_id = 123);
创建索引成功后,使用以下方式查询:
SELECT * FROM embeddings WHERE model_id = 123 ORDER BY embedding::vector(3) <-> '[3,1,2]' LIMIT 5;
是否支持存储更高精度的向量?
支持。您可以使用double precision[]
或numeric[]
类型存储更高精度的向量。
CREATE TABLE items_highpre (id bigserial PRIMARY KEY, embedding double precision[]);
-- 对于Postgres数组,使用 {} 而不是 []
INSERT INTO items_highpre (embedding) VALUES ('{1,2,3}'), ('{4,5,6}');
此外,您还可以选择为表添加检查约束,确保数据可以转换为vector
类型,并具有预期的维度。
ALTER TABLE items_highpre ADD CHECK (vector_dims(embedding::vector) = 3);
通过表达式索引创建HNSW索引:
CREATE INDEX ON items_highpre USING hnsw ((embedding::vector(3)) vector_l2_ops);
创建索引成功后,使用以下方式查询:
SELECT * FROM items_highpre ORDER BY embedding::vector(3) <-> '[3,1,2]' LIMIT 5;
是否需要将索引完全放入内存?
不需要。但是和其他索引类型一样,放入内存可获得更好的性能表现。您可通过以下语句查看索引大小:
SELECT pg_size_pretty(pg_relation_size('index_name'));
查询处理
为什么查询没有使用索引?
查询语句需要同时包含ORDER BY
和LIMIT
子句,且ORDER BY
必须是距离运算符(而非表达式)的结果,并按升序排列。
-- 使用索引
ORDER BY embedding <=> '[3,1,2]' LIMIT 5;
-- 不使用索引
ORDER BY 1 - (embedding <=> '[3,1,2]') DESC LIMIT 5;
您也可以使用以下方式使查询计划器使用索引:
BEGIN;
SET LOCAL enable_seqscan = off;
SELECT ...
COMMIT;
此外,对于较小的表,表扫描的速度可能会更快。
为什么查询没有使用并行扫描?
查询规划器在成本估算中不考虑外联存储,该机制可降低串行扫描成本。您可以通过以下方式降低查询中并行扫描的成本:
BEGIN;
SET LOCAL min_parallel_table_scan_size = 1;
SET LOCAL parallel_setup_cost = 1;
SELECT ...
COMMIT;
或者将向量存储为内联形式:
ALTER TABLE items ALTER COLUMN embedding SET STORAGE PLAIN;
为什么添加HNSW索引后查询结果减少?
查询结果受限于动态候选列表的大小hnsw.ef_search
,其默认值为40。如查询中的死元组或过滤条件,结果可能会更少。可启用迭代索引扫描帮助解决此问题。
需要注意的是,NULL
向量不会被索引,对于余弦距离,零向量也同样不会被索引。
为什么添加IVFFlat索引后查询结果减少?
索引可能是在列表数量较多而使用的数据较少的情况下创建的。请在表中数据量增加后再重新创建索引,或考虑先删除现有索引。
此外,其查询结果可能受到探针数量ivfflat.probes
限制。可启用迭代索引扫描帮助解决此问题。
需要注意的是,NULL
向量不会被索引,对于余弦距离,零向量也同样不会被索引。