PostgreSQL 16 装 pgvector 0.8,表 chunks 有 200 万行 1536 维向量,执行 CREATE INDEX 用 hnsw 跑了三十多分钟,日志里抛 ERROR: out of memory,DETAIL 指向 maintenance_work_mem,机器 32GB 内存当时只用了 9GB。

一开始怀疑是「同一实例上还有别的索引在并发重建,内存被分走」,查了一圈,方向不对。

把日志和配置对完,能解释这个现象的基本就这几处。maintenance_work_mem 默认 64MB,HNSW 建图需要的临时内存远超这个值。少数情况下是并行建索引时每个 worker 各自申请一份内存,峰值是单份乘以 worker 数。

还有一种情况,维度高导致每条向量的图结构开销变大,估算时按行数算少了一半。

动手时先看当前内存参数和并行度

psql -d kb -c "SHOW maintenance_work_mem; SHOW max_parallel_maintenance_workers;"

然后在会话内提到 4GB 并临时关掉并行建索引

psql -d kb -c "SET maintenance_work_mem='4GB'; SET max_parallel_maintenance_workers=0; CREATE INDEX idx_chunk_hnsw ON chunks USING hnsw (embedding vector_cosine_ops) WITH (m=16, ef_construction=64);"

建完补一次统计信息让计划器选对索引

psql -d kb -c "VACUUM ANALYZE chunks;"

等前面都确认过,再确认索引体积与执行计划

psql -d kb -c "SELECT pg_size_pretty(pg_relation_size('idx_chunk_hnsw')); EXPLAIN SELECT id FROM chunks ORDER BY embedding <=> '[0.1,0.2]' LIMIT 5;"

恢复的判定其实很直接。索引创建语句正常结束,pg_indexes 里能查到 idx_chunk_hnsw,EXPLAIN 输出走 Index Scan 而不是 Seq Scan。

这条参数只影响维护类操作,改完别写进全局配置就完事,生产上按内存的十分之一给,同时留意并行 worker 会把峰值放大。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。

作者 9823189