Neon pgvector 性能测试指南:从 100 万条 OpenAI 1536 维向量数据集到 HNSW/IVFFlat 基准

发布时间:2026/9/13 18:25:50
Neon pgvector 性能测试指南:从 100 万条 OpenAI 1536 维向量数据集到 HNSW/IVFFlat 基准 Neon pgvector 性能测试指南从 100 万条 OpenAI 1536 维向量数据集到 HNSW/IVFFlat 基准【免费下载链接】neonNeon: Serverless Postgres. We separated storage and compute to offer autoscaling, code-like database branching, and scale to zero.项目地址: https://gitcode.com/GitHub_Trending/ne/neon导读本指南完整讲解 Neon 仓库中 pgvector 性能测试的搭建与运行方法从 Hugging Face 上的dbpedia-entities-openai3-text-embedding-3-large-1536-1M数据集出发依次完成 Parquet 下载、loaddata.py批量导入、HNSW / IVFFlat / halfvec 三种索引构建再到使用 pgbench 并发跑余弦相似度 Top-K 查询的全流程。读完本文你将掌握一套可复现的、基于 100 万条 1536 维真实文本向量的向量数据库基准测试方案并了解 Neon 如何通过test_runner框架把该负载接入日常性能回归。1. 数据集来源与规格pgvector 性能测试使用的数据集并非虚构数据而是直接复用公开的 Hugging Face 数据集Qdrant/dbpedia-entities-openai3-text-embedding-3-large-1536-1M说明见 test_runner/performance/pgvector/README.md。该数据集的核心规格如下项目值样本总数1,000,0001M向量维度1536向量类型float64序列类型字段_idstring、titlestring、textstring、text-embedding-3-large-1536-embeddingfloat64 序列数据切分单个train切分num_examples 1000000下载大小9,551,862,565 字节约 8.9 GiB解压后大小12,679,725,776 字节约 11.8 GiB许可MIT任务类别feature-extraction特征提取语言en英语数据内容方面title与text来自 BeIR/dbpedia-entity 数据集的前 100 万条记录embedding 由 OpenAItext-embedding-3-large模型生成数据集创建于 2024 年 2 月。选择该数据集的原因很直接它是真实文本语义向量维度 1536 恰是text-embedding-3-large的标准输出能让 pgvector 的vector(1536)列、HNSW/IVFFlat 索引和 pgbench 负载都运行在接近生产规模的量级上。2. 下载 Parquet 数据文件数据集以 Parquet 格式发布仓库建议使用git-lfs克隆整个数据集仓库brew install git-lfs git-lfs clone https://huggingface.co/datasets/Qdrant/dbpedia-entities-openai3-text-embedding-3-large-1536-1M下载完成后本地会得到按data/train-*分片组织的多个.parquet文件这正是下一步loaddata.py逐个读取的数据源。整个下载体量约 9 GB请预留足够磁盘空间。3. 将 100 万条向量导入 PostgreSQL仓库提供了现成的导入脚本 test_runner/performance/pgvector/loaddata.py使用方式python loaddata.py CONNSTR DATADIR其中CONNSTR是 libpq 连接串DATADIR是上一步下载的 Parquet 文件所在目录。脚本依赖numpy、pandas、psycopg2以及pgvector.psycopg2用于注册向量类型。3.1 建表逻辑脚本首先连接 PostgreSQL 并执行 DDL对应 loaddata.pyCREATE EXTENSION IF NOT EXISTS vector; DROP TABLE IF EXISTS documents; CREATE TABLE documents ( _id TEXT PRIMARY KEY, title TEXT, text TEXT, embeddings vector(1536) -- text-embedding-3-large-1536-embedding (OpenAI) );关键点必须先执行CREATE EXTENSION IF NOT EXISTS vector;确保 pgvector 扩展可用embeddings vector(1536)严格锁定维度为 1536与数据集一致通过psycopg2.extras.execute_values做批量插入batch insert而不是逐行 INSERT这是 100 万行级别导入能保持可接受耗时的重要原因每个 Parquet 文件读取后conn.commit()一次避免事务过大。3.2 与 Neon 环境的对接在 Neon 上pgvector 是默认可用的扩展直接建表即可在自建 PostgreSQL 上需确认vector扩展已安装。脚本按字典序sorted遍历目录下所有*.parquet文件因此分片命名需保证顺序稳定保证可重复执行。该表documents是所有后续索引构建脚本HNSW/IVFFlat/halfvec的公共数据源导入完成后即进入索引构建阶段。4. 索引构建基准HNSW 与 IVFFlat导入 100 万条向量后仓库分别提供了两类索引的构建脚本均使用psql的\timing统计耗时并预先调大了并行构建参数。4.1 HNSW 索引构建HNSW_build.sql\set ECHO queries \timing DROP TABLE IF EXISTS hnsw_test_table; CREATE TABLE hnsw_test_table AS TABLE documents WITH NO DATA; INSERT INTO hnsw_test_table SELECT * FROM documents; CREATE INDEX ON hnsw_test_table (_id); -- needed later for random tuple queries SET max_parallel_maintenance_workers 7; SET maintenance_work_mem 8GB; CREATE INDEX ON hnsw_test_table USING hnsw (embeddings vector_cosine_ops); CREATE INDEX ON hnsw_test_table USING hnsw (embeddings vector_ip_ops); CREATE INDEX ON hnsw_test_table USING hnsw (embeddings vector_l1_ops); CREATE INDEX ON hnsw_test_table USING hnsw ((binary_quantize(embeddings)::bit(1536)) bit_hamming_ops); CREATE INDEX ON hnsw_test_table USING hnsw ((binary_quantize(embeddings)::bit(1536)) bit_jaccard_ops);该脚本一次构建了 5 个 HNSW 索引覆盖 pgvector 支持的多种距离度量vector_cosine_ops余弦距离vector_ip_ops内积#vector_l1_opsL1 曼哈顿距离binary_quantize(embeddings)::bit(1536)bit_hamming_ops先二值量化再算汉明距离同样二值量化后的bit_jaccard_opsJaccard 距离。binary_quantize把 1536 维 float 向量压成 1536 bit对应 bit 类型内存占用只有原来的 1/32是 pgvector 降低存储与加速距离计算的常用手段。脚本还给出了一个运维小技巧HNSW_build.sql在另一个 psql 会话中可通过以下查询实时观察 HNSW 构建各阶段进度SELECT phase, round(100.0 * blocks_done / nullif(blocks_total, 0), 1) AS % FROM pg_stat_progress_create_index;pg_stat_progress_create_index会按phase如1: initializing、2: loading tuples回报进度便于估算 100 万行索引构建的剩余时间。4.2 IVFFlat 索引构建IVFFLAT_build.sqlDROP TABLE IF EXISTS ivfflat_test_table; CREATE TABLE ivfflat_test_table AS TABLE documents WITH NO DATA; INSERT INTO ivfflat_test_table SELECT * FROM documents; CREATE INDEX ON ivfflat_test_table (_id); SET max_parallel_maintenance_workers 7; SET maintenance_work_mem 8GB; -- the formula for lists is # rows / 1000 or sqrt(# rows) if # rows 1 million -- we have 1 million embeddings of vector size 1536 ... so we use 1000 lists CREATE INDEX ON ivfflat_test_table USING ivfflat (embeddings vector_l2_ops) WITH (lists 1000); CREATE INDEX ON ivfflat_test_table USING ivfflat (embeddings vector_ip_ops) WITH (lists 1000); CREATE INDEX ON ivfflat_test_table USING ivfflat (embeddings vector_cosine_ops) WITH (lists 1000); CREATE INDEX ON ivfflat_test_table USING ivfflat (embeddings::halfvec(1536) halfvec_l2_ops) WITH (lists 1000); CREATE INDEX ON ivfflat_test_table USING ivfflat ((binary_quantize(embeddings)::bit(1536)) bit_hamming_ops) WITH (lists 1000);IVFFlat倒排文件 平坦扫描的关键超参是lists聚类数。脚本注释明确给出了选值经验公式IVFFLAT_build.sql行数 ≤ 100 万lists 行数 / 1000行数 100 万lists sqrt(行数)。由于本测试恰好是 100 万行取lists 1000。lists越大查询时扫描的候选桶越少、召回率越低反之召回率越高但查询越慢属于精度与延迟的权衡旋钮。另外注意该脚本还包含一个embeddings::halfvec(1536)的 IVFFlat 索引直接对比了同度量下半精度与全精度的差异详见第 6 节。4.3 索引清单核对两个构建脚本末尾都附带了一段 catalog 查询用来核对每个表上实际建立的索引、访问方法am.amname与操作符类opc.opcnameSELECT idx.relname AS index_name, tbl.relname AS table_name, am.amname AS access_method, a.attname AS column_name, opc.opcname AS operator_class FROM pg_index i JOIN pg_class idx ON idx.oid i.indexrelid JOIN pg_class tbl ON tbl.oid i.indrelid JOIN pg_am am ON am.oid idx.relam JOIN pg_attribute a ON a.attrelid tbl.oid AND a.attnum ANY(i.indkey) JOIN pg_opclass opc ON opc.oid i.indclass[0] WHERE tbl.relname hnsw_test_table AND a.attname embeddings;脚本最后还会执行\dt展示表与索引的物理大小用于评估不同索引方案对存储的影响例如二值量化 bit 索引显著小于 float 向量索引。5. pgbench 查询负载模拟真实 Top-K 语义检索索引构建完成后仓库提供两份 pgbench 自定义脚本模拟线上“给定一个查询向量返回最相似的 30 条记录”场景。5.1 HNSW 查询脚本pgbench_custom_script_pgvector_hsnw_queries.sqlwith x (x) as ( select embeddings as x from hnsw_test_table TABLESAMPLE SYSTEM (1) LIMIT 1 ) SELECT title, embeddings (select x from x) as distance FROM hnsw_test_table ORDER BY 2 LIMIT 30;设计要点用TABLESAMPLE SYSTEM (1)从表中随机抽取一行作为“查询向量”避免把固定向量写死使每轮负载的查询点都不同、更贴近真实检索分布embeddings ...使用余弦距离运算符ORDER BY 2按距离升序排列LIMIT 30取最近邻 Top-30这个查询会命中hnsw_test_table上的vector_cosine_opsHNSW 索引走 ANN近似最近邻路径返回结果。5.2 halfvec 查询脚本pgbench_custom_script_pgvector_halfvec_queries.sql脚本内容与 HNSW 版几乎一致只是把表换成halfvec_test_tablewith x (x) as ( select embeddings as x from halfvec_test_table TABLESAMPLE SYSTEM (1) LIMIT 1 ) SELECT title, embeddings (select x from x) as distance FROM halfvec_test_table ORDER BY 2 LIMIT 30;其文件头注释给出了在 Neon 上通过连接池pooled connection运行 pgbench 的完整命令模板pgbench_custom_script_pgvector_halfvec_queries.sqlpgbench -T 300 -c 100 -j20 -f pgbench_halfvec_queries.sql \ -postgresql://neondb_owner:secretep-floral-thunder-w1gzhaxi-pooler.eu-west-1.aws.neon.build/neondb?sslmoderequire参数含义-T 300总运行 300 秒、-c 100并发客户端 100、-j20线程数 20、--protocolprepared使用扩展查询协议的预编译语句以减少解析开销。5.3 halfvec 建表与索引halfvec_build.sqlDROP TABLE IF EXISTS halfvec_test_table; CREATE TABLE halfvec_test_table ( _id text NOT NULL, title text, text text, embeddings halfvec(1536), PRIMARY KEY (_id) ); INSERT INTO halfvec_test_table (_id, title, text, embeddings) SELECT _id, title, text, embeddings::halfvec FROM documents; CREATE INDEX documents_half_precision_hnsw_idx ON halfvec_test_table USING hnsw (embeddings halfvec_cosine_ops) WITH (m 64, ef_construction 128);这里演示了 pgvector 的halfvec半精度向量用法通过embeddings::halfvec把全精度vector(1536)直接转换出半精度列存储减半HNSW 建索引用halfvec_cosine_ops并显式指定m 64每节点最大连接数与ef_construction 128构建期候选集大小两个 HNSW 超参——ef_construction越大索引质量越高但构建越慢m越大图连通性越好但内存占用越大。该测试用于衡量“半精度 HNSW”相对“全精度 HNSW”在吞吐与召回上的折中是 pgvector 在存储敏感场景下的常见调优方向。6. 自动化运行Neon 性能测试框架上述 SQL 脚本并非只能手工执行仓库还把它们封装进了 pytest 性能测试框架便于纳入 CI 与日常回归。6.1 测试入口test_runner/performance/test_perf_pgvector_queries.py 定义了两个测试pytest.mark.parametrize(duration, get_durations_matrix()) pytest.mark.remote_cluster def test_pgbench_remote_pgvector_hnsw(remote_compare: PgCompare, duration: int): run_test_pgbench(remote_compare, 1, duration, PgBenchLoadType.PGVECTOR_HNSW) pytest.mark.parametrize(duration, get_durations_matrix()) pytest.mark.remote_cluster def test_pgbench_remote_pgvector_halfvec(remote_compare: PgCompare, duration: int): run_test_pgbench(remote_compare, 1, duration, PgBenchLoadType.PGVECTOR_HALFVEC)两个测试都标记为remote_cluster不拉起本地 Neon 环境而是要求外部提供已装好 pgvector、已载入 100 万向量并建好索引的 PostgreSQL/Neon 集群连接串get_durations_matrix()读取环境变量TEST_PG_BENCH_DURATIONS_MATRIX默认45支持h/m后缀决定每次 pgbench 的运行时长矩阵。6.2 pgbench 负载的底层实现test_runner/performance/test_perf_pgbench.py 中定义了负载枚举L20-L25class PgBenchLoadType(enum.Enum): ... PGVECTOR_HNSW pgvector-hnsw PGVECTOR_HALFVEC pgvector-halfvec对应的实际 pgbench 调用L141-L179与手工命令等价run_pgbench( env, pgvector-hnsw, [ pgbench, -f, test_runner/performance/pgvector/pgbench_custom_script_pgvector_hsnw_queries.sql, -c100, -j20, f-T{duration}, -P2, --protocolprepared, --progress-timestamp, connstr, ], passwordpassword, )即100 并发、20 线程、--protocolprepared、每 2 秒打印一次进度时间戳-P2 --progress-timestamp跑满duration秒。run_test_pgbench会记录各时段的 TPS/延迟并汇总report_size()等指标。6.3 性能测试的整体运行方式性能测试运行在同一套 pytest 集成测试基础设施之上详见 test_runner/performance/README.mdBUILD_TYPErelease CARGO_BUILD_FLAGS--featurestesting make -s -j8 ./scripts/pysync DEFAULT_PG_VERSION17 NEON_BIN./target/release poetry run pytest test_runner/performance常用 pytest 参数包括-x首个错误即停、-s显示输出、-k按名字筛选测试、--timeout0关闭默认 300 秒超时、--preserve-database-files跳过清理、--out-dir输出 JSON 指标可用 test_runner/performance/out_dir_to_csv.py 转 CSV。需要注意的客观限制README 中明确说明多数性能测试跑在本地Postgres、safekeeper、pageserver 共享 CPU/I/O且无网络开销结果不能直接代表生产环境remote_cluster测试跑在共享的 staging/captest 环境会受其他集群活动干扰每个测试只跑一次未经 min/max/avg/median 聚合跨 run 对比存在噪声。因此pgvector 的 HNSW/halfvec 基准更适合用于“同环境下的相对比较与回归监控”而非绝对性能数值的对外宣传。7. 完整实验流程小结把整条链路串起来一次完整的 pgvector 性能实验包含 5 步下载数据git-lfs clone数据集仓库得到约 9 GB 的 Parquet 分片导入数据python loaddata.py CONNSTR DATADIR生成documents表含 100 万条vector(1536)构建索引依次执行 HNSW_build.sql、IVFFLAT_build.sql、halfvec_build.sql并用\timing、pg_stat_progress_create_index、\dt记录构建耗时、进度与空间占用压测查询用 pgbench 分别加载 HNSW 与 halfvec 查询脚本按-c100 -j20 -T300 --protocolprepared跑 5 分钟并记录 TPS/延迟对比分析横向对比 HNSW 与 IVFFlat、全精度vector与halfvec、二值量化 bit 索引在不同距离度量下的吞吐与召回差异为生产选型提供数据支撑。这套方法论的价值在于数据集真实、规模达到百万级、索引与查询脚本可直接复用无论用于 Neon Serverless Postgres 的向量场景容量规划还是用于自建 PostgreSQL 的 pgvector 参数调优都具有直接的参考意义。【免费下载链接】neonNeon: Serverless Postgres. We separated storage and compute to offer autoscaling, code-like database branching, and scale to zero.项目地址: https://gitcode.com/GitHub_Trending/ne/neon创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考