事情本身不复杂,线索都在日志里。pgvector 0.7 在 200 万行 1536 维的表上建 HNSW 索引,maintenance_work_mem 还是默认的 64MB,跑了 3 小时没建完,磁盘 IO 一直满。
第一反应是「建索引期间表还在持续写入」,验证下来不成立。
把日志和配置对完,能解释这个现象的基本就这几处。maintenance_work_mem 太小,建图过程反复落盘。还有一种是没有开并行建索引。
另外,维度高、m 和 ef_construction 取值偏大。
上来先看建索引的进度
SELECT phase, blocks_done, blocks_total FROM pg_stat_progress_create_index;
调大维护内存和并行度后重建
SET maintenance_work_mem='4GB'; SET max_parallel_maintenance_workers=4;
接着把 m 从 32 降到 16 再建一次
CREATE INDEX CONCURRENTLY idx_emb ON docs USING hnsw (embedding vector_cosine_ops) WITH (m=16, ef_construction=128);
建完做一次 analyze 让统计信息跟上
ANALYZE docs;
那几天正好在做别的变更,先把时间线对齐才敢动手。
恢复的判定其实很直接。重建耗时从 3 小时降到 38 分钟,索引大小减少 30%,召回率在测试集上只掉了 0.4 个百分点。
容易忽略的是,HNSW 建索引是内存密集型操作,内存给不够就会退化成磁盘随机写,先把维护内存拉起来再谈参数。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。
