如何借助PGVector的HNSW索引提升批量插入性能?
批量插入DocumentChunk到PostgreSQL(PGVector+Peewee)的高效方案
一、临时禁用HNSW索引(立竿见影的优化)
HNSW索引会在每条插入时更新,批量插入前先禁用索引,插入完成后重建,能大幅提升速度:
# 替换成你的HNSW索引名称,通常是"documentchunk_embedding_idx"之类的 DocumentChunk.raw("ALTER INDEX idx_documentchunk_embedding DISABLE").execute() # 执行批量插入操作... # 重建索引 DocumentChunk.raw("ALTER INDEX idx_documentchunk_embedding REBUILD").execute()
二、用Peewee内置的copy_from实现文本格式批量插入
Peewee的copy_from封装了PostgreSQL的COPY命令,比逐条插入快很多,处理起来也简单:
- 把DocumentChunk列表转换成字段元组列表,PGVector向量直接转成字符串格式(如
[0.1, 0.2, ...]) - 调用
copy_from完成插入:
# 转换chunk列表为元组列表 chunk_records = [ (chunk.id, chunk.text, str(chunk.embedding)) for chunk in document_chunk_list ] # 原子操作中执行批量插入 with db.atomic(): db.copy_from( chunk_records, DocumentChunk, fields=['id', 'text', 'embedding'], sep='|', # 选一个文本中不会出现的分隔符,避免冲突 null='' )
三、二进制格式COPY(极致性能)
如果需要更高性能,用PostgreSQL的二进制COPY格式,结合psycopg2的原生能力和PGVector的适配器:
from psycopg2.extensions import register_vector # 注册PGVector的psycopg2适配器,让向量能正确转二进制 register_vector(db.connection.cursor()) def generate_binary_records(chunks): for chunk in chunks: # 直接返回字段元组,psycopg2会自动处理二进制转换 yield (chunk.id, chunk.text, chunk.embedding) # 用psycopg2原生copy_from执行二进制插入 with db.connection.cursor() as cur: cur.copy_from( generate_binary_records(document_chunk_list), DocumentChunk._meta.table_name, columns=('id', 'text', 'embedding'), binary=True ) db.connection.commit()
注意事项
- 二进制COPY的性能优势在超大规模数据(百万级以上)才会凸显,中小规模用文本COPY足够
- 确保分隔符不会和文本内容冲突,若文本里有
|,可以换用\x01这类不可见字符
内容的提问来源于stack exchange,提问作者Federico
相关产品推荐
相关产品推荐

