
不堆砌概念,只记录真实操作与SQL。本文所有步骤均在腾讯云轻量服务器(4核8G,上海区)上完成,Ubuntu 22.04系统,全文约3800字,阅读需9分钟。
在上一套AI内容流水线中,我使用MySQL存储元数据,用BGE-M3生成向量后单独写到RedisJSON。这套方案存在两个痛点:
PostgreSQL + pgvector 将向量存储为原生数据类型,与关系型字段同库同事务,统一SQL即可完成标量+向量的混合查询。
腾讯云可选方案对比:
方案 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
云数据库PostgreSQL(内置pgvector) | 免运维、自动备份、一键扩容 | 版本滞后(当前最高PG14) | 生产核心业务 |
轻量服务器自建PG16 | 版本新、参数可控、成本低 | 需自行维护备份与监控 | 创业/开发测试 |
我的选择是轻量服务器自建PG16,原因有二:pgvector在PG16上的HNSW索引性能优于PG14约25%;且自建可灵活调整shared_buffers等内核参数。
使用PostgreSQL官方APT源,避开Ubuntu默认仓库的老旧版本:
sudo sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt update
sudo apt install postgresql-16 postgresql-server-dev-16 build-essential git -y安装完成后,初始化数据库并启动:
sudo pg_dropcluster 16 main --stop # 清理默认cluster
sudo pg_createcluster 16 main --start --locale=en_US.UTF-8
sudo systemctl enable postgresqlpgvector从0.6.0开始支持HNSW索引,0.7.0优化了并行构建性能,是生产首选版本:
cd /tmp
git clone --branch v0.7.0 https://github.com/pgvector/pgvector.git
cd pgvector
make
sudo make install安装完成后,在目标数据库中启用扩展:
CREATE EXTENSION vector;
-- 验证版本
SELECT extversion FROM pg_extension WHERE extname = 'vector';
-- 应返回 '0.7.0'编辑/etc/postgresql/16/main/postgresql.conf,针对4核8G机器给出实测稳定值:
# 内存相关(总内存8G,留2G给OS和AI推理服务)
shared_buffers = 2GB # 推荐总内存的25%
effective_cache_size = 6GB # 推荐总内存的75%
maintenance_work_mem = 512MB # 索引构建时可临时增大
work_mem = 16MB # 排序和哈希操作
# 向量检索专用(HNSW索引性能关键)
max_parallel_workers = 4
max_parallel_workers_per_gather = 2
enable_seqscan = off # 强制优先走索引,适用于向量检索场景
# 写入性能(每日200篇文章+向量,写入压力不大)
synchronous_commit = off
wal_buffers = 64MB
checkpoint_timeout = 15min修改后重启生效:
sudo systemctl restart postgresql承接上一篇文章的AI内容流水线,设计文章表:
CREATE TABLE articles (
id BIGSERIAL PRIMARY KEY,
title TEXT NOT NULL,
content_summary TEXT,
source_url VARCHAR(512) UNIQUE,
category VARCHAR(64),
tags TEXT[],
embedding vector(1024), -- BGE-M3维度
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- 创建标量索引(加速过滤)
CREATE INDEX idx_articles_created ON articles(created_at DESC);
CREATE INDEX idx_articles_category ON articles(category) WHERE category IS NOT NULL;
-- 创建向量索引(最关键)
CREATE INDEX idx_articles_embedding_hnsw ON articles
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 200);参数解释:
m=16:每层最大连接数,调高提升召回率但增加内存,16是性价比阈值ef_construction=200:构建时动态列表大小,200可保证99%召回率,构建时间增加约30%但可接受使用Python psycopg2批量写入,注意向量需转为字符串格式:
import psycopg2
import numpy as np
conn = psycopg2.connect("host=localhost dbname=ai_db user=postgres")
cur = conn.cursor()
# 假设embedding为list[float]长度1024
embedding_str = '[' + ','.join(map(str, embedding_list)) + ']'
cur.execute("""
INSERT INTO articles (title, content_summary, source_url, tags, embedding)
VALUES (%s, %s, %s, %s, %s::vector)
ON CONFLICT (source_url) DO UPDATE
SET embedding = EXCLUDED.embedding,
updated_at = NOW()
""", (title, summary, url, tags, embedding_str))最常用的业务场景:查询近3天、属于"AI"分类、与目标向量最相似的5篇文章:
SELECT
id,
title,
content_summary,
tags,
created_at,
1 - (embedding <=> %s::vector) AS similarity
FROM articles
WHERE
created_at >= NOW() - INTERVAL '3 days'
AND category = 'AI'
AND embedding IS NOT NULL
ORDER BY embedding <=> %s::vector
LIMIT 5;其中<=>是余弦距离运算符,值越小越相似。该查询利用HNSW索引先做向量近似检索,再通过标量条件过滤,实测平均耗时22ms(5000条基础数据,HNSW ef_search=40时)。
承接上篇文章的去重逻辑,改为纯SQL实现——查找重复度>0.85且标题含"AI"的群组:
WITH similarity_pairs AS (
SELECT
a1.id AS id1,
a2.id AS id2,
1 - (a1.embedding <=> a2.embedding) AS sim
FROM articles a1
JOIN articles a2 ON a1.id < a2.id
WHERE
a1.created_at >= NOW() - INTERVAL '7 days'
AND a2.created_at >= NOW() - INTERVAL '7 days'
AND a1.title ILIKE '%AI%'
)
SELECT id1, id2, sim
FROM similarity_pairs
WHERE sim > 0.85
ORDER BY sim DESC;该查询在2万条数据下耗时约1.2秒(借助HNSW加速自连接),可放在定时任务中每日运行,识别重复内容。
资源消耗(月度,与上一套合并):
性能数据(压测5000条向量,并发4路):
坑1:HNSW索引构建时内存溢出(OOM Killer)
原因:
maintenance_work_mem设置512MB,但ef_construction=200时单个索引构建峰值内存可达1.2GB。解决方案:临时调低ef_construction=120构建,构建完成后查询时ef_search仍可设为200。后续版本pgvector 0.7.2修复了内存锯齿问题。
坑2:向量维度不匹配导致查询失败
BGE-M3生成的是1024维浮点数,但Python numpy默认float64,传入PostgreSQL vector时被截断。解决方案:在Python端显式转为
float32:embedding.astype(np.float32).tolist()。
坑3:备份恢复后向量索引失效
使用
pg_dump -Fc自定义格式备份,恢复后HNSW索引虽然存在但查询性能骤降。原因是统计信息未更新。执行ANALYZE articles; REINDEX INDEX CONCURRENTLY idx_articles_embedding_hnsw;后恢复正常。
pg_stat_activity中的活跃连接数、HNSW索引命中率通过云监控Agent上报,设置活跃连接>20时告警(避免AI服务同时大量检索拖垮DB)pg_dump -Fc,使用coscli上传至腾讯云COS低频存储,备份成本约5元/月将原本分散在MySQL+RedisJSON的存储统一至PostgreSQL后:
最终架构简图:
采集脚本 → Dify工作流 → Qwen摘要 + BGE向量 → PostgreSQL 16 (pgvector)
↓
混合查询API
↓
前端展示pgvector绝不是“把向量存进数据库”这么简单,真正的价值在于统一SQL语义下的混合检索能力。对于日均处理200-500篇内容的中小规模场景,PostgreSQL 16 + pgvector完全胜任,无需引入Elasticsearch或专用向量数据库,降低技术栈复杂度和运维成本。
给后来者的建议:
idx_articles_embedding_hnsw未被使用,检查enable_seqscan参数和查询中的ORDER BY写法原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。