主题
PGVector 向量数据库教程大纲
当关系型数据库遇上向量搜索——PostgreSQL + pgvector,用你最熟悉的 SQL 做语义检索
📖 教程概述
为什么要在 PostgreSQL 上做向量搜索?答案很简单:你已经有 PostgreSQL 了。绝大多数后端系统的关系型数据库就是 PostgreSQL——用户表、订单表、商品表都在里面。当你需要给系统加上语义搜索能力时,与其引入一个全新的向量数据库(Chroma、Milvus、Qdrant),不如直接在现有的 PostgreSQL 上装一个 pgvector 扩展——零额外运维、零数据迁移、SQL 原生查询、事务一致性全保留。
pgvector 是 PostgreSQL 的向量相似度搜索扩展,它把向量(embedding)作为一等公民引入了 SQL 世界。你可以在同一张表里同时存储结构化字段(用户名、价格、日期)和向量字段(文本的 embedding),然后用一条 SQL 同时做结构化过滤和语义搜索——这是独立的向量数据库很难做到的。
本教程分为两大部分:前两章带你快速掌握 PostgreSQL 的核心操作(如果你已经熟悉 PostgreSQL 可以跳过),后五章深入 pgvector 的方方面面——从安装配置到向量索引、从 CRUD 到高级查询、从 RAG 实战到生产调优。我们不只讲 SQL 语法,更要理解 pgvector 在 RAG 架构中的独特优势、它与独立向量数据库的取舍、以及如何用"SQL 思维"重新理解向量搜索。
🗺️ 章节规划
第1章:PostgreSQL 基础入门
1.1 PostgreSQL 是什么?为什么 RAG 工程师需要它
- 关系型数据库的核心价值:结构化数据存储、SQL 查询、ACID 事务、丰富的数据类型
- PostgreSQL 在 AI 应用中的角色:不只是"存用户数据的数据库",更是 RAG 系统的结构化数据底座
- PostgreSQL vs MySQL vs SQLite:为什么 pgvector 只支持 PostgreSQL(扩展机制、类型系统、索引架构的差异)
- RAG 场景下 PostgreSQL 的独特优势:结构化数据 + 向量数据在同一张表中,一条 SQL 同时做 WHERE 过滤和向量搜索
1.2 安装与连接
- 安装方式:Docker(推荐开发)、Homebrew(macOS)、apt/yum(Linux)、云托管(RDS/Aurora)
- Docker 一键启动:
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=xxx pgvector/pgvector:pg16 - 连接方式:psql 命令行 / pgAdmin GUI / Python(psycopg2 / asyncpg) / Node.js(pg)
- 基本连接参数:host、port、database、user、password
- 连接池的概念:为什么生产环境不用短连接
1.3 SQL 基础:增删改查
- CREATE TABLE:数据类型(INTEGER, VARCHAR, TEXT, TIMESTAMP, JSONB, BOOLEAN)、约束(PRIMARY KEY, NOT NULL, UNIQUE)
- INSERT:单条插入、批量插入、COPY 命令高效导入
- SELECT:基本查询、WHERE 条件、ORDER BY 排序、LIMIT/OFFSET 分页
- UPDATE:更新字段、条件更新、RETURNING 子句
- DELETE:条件删除、TRUNCATE 清空表
- Python 操作 PostgreSQL:psycopg2 的基本用法(连接、游标、参数化查询、事务控制)
第2章:PostgreSQL 进阶必备
2.1 索引与查询优化基础
- 为什么需要索引:全表扫描 vs 索引扫描的性能差异
- B-tree 索引:PostgreSQL 的默认索引类型,适合等值查询和范围查询
- 索引类型全景:B-tree / Hash / GIN / GiST / BRIN / SP-GiST,各自的适用场景
- EXPLAIN ANALYZE:读懂查询计划,找到性能瓶颈
- 索引设计原则:选择性高的字段优先、联合索引的列顺序、避免过度索引
2.2 JSONB 与半结构化数据
- JSONB vs JSON:二进制存储、支持索引、查询性能对比
- JSONB 查询操作符:
->/->>/?/@>/?|等 - GIN 索引加速 JSONB 查询:
CREATE INDEX idx_meta ON docs USING GIN (metadata) - JSONB 在 RAG 中的用途:存储文档的灵活 metadata(来源、标签、分类),无需预定义 schema
2.3 事务与并发控制
- ACID 事务:BEGIN / COMMIT / ROLLBACK 的基本用法
- 隔离级别:READ COMMITTED(默认)、REPEATABLE READ、SERIALIZABLE
- MVCC 机制:多版本并发控制如何实现读写不互斥
- 行锁与表锁:SELECT FOR UPDATE、 advisory locks
- 为什么事务对 RAG 重要:文档入库时保证结构化数据和向量数据的原子性
第3章:pgvector 入门——向量扩展初体验
3.1 pgvector 是什么?它解决了什么问题
- pgvector 的定位:PostgreSQL 扩展,不是独立的向量数据库
- pgvector vs 独立向量数据库:
- pgvector 优势:SQL 原生、事务一致性、结构化+向量混合查询、零额外运维
- pgvector 劣势:超大规模性能不如 Milvus、向量算法不如 FAISS 丰富
- pgvector 的核心能力:向量存储(vector 类型)、距离计算(L2/Cosine/IP)、近似索引(IVFFlat/HNSW)
- 版本与兼容性:pgvector 0.7.x、PostgreSQL 12~16 支持、Docker 镜像 pgvector/pgvector
3.2 安装 pgvector 与 Hello World
- 安装方式:Docker(最简)/ CREATE EXTENSION(已有 PG 实例)/ 编译安装
- Docker 一键启动:
docker run pgvector/pgvector:pg16 - 创建扩展:
CREATE EXTENSION vector; - 第一个完整示例:
- 建表(id, content, embedding vector(3))
- 插入向量数据
- 用
<->操作符做 L2 距离搜索 - 用
<=>操作符做 Cosine 距离搜索 - 理解返回结果的距离含义
- Python 集成:psycopg2 + pgvector 库的
register_vector()用法
3.3 vector 数据类型详解
- vector(N):固定维度的向量类型,N 为维度(如 vector(384)、vector(1536))
- 维度约束:同一列的所有向量维度必须一致,维度不匹配会报错
- 向量字面量语法:
'[0.1, 0.2, 0.3]'::vector(3) - vector 类型的操作符:
<->:L2 距离(欧氏距离)<=>:余弦距离<#>:内积距离(负内积)+/-:向量加减*:标量乘法
- vector 类型的函数:
vector_dims(embedding):获取维度vector_norm(embedding):获取 L2 范数l2_distance()/cosine_distance()/inner_product():显式距离函数
第4章:pgvector 的 CRUD 与混合查询
4.1 向量数据的增删改查
- INSERT:插入单条/批量向量数据,pgvector 的
register_vector()自动处理 Python list → PG vector 的类型转换 - SELECT:查询向量字段、计算距离、按相似度排序
- UPDATE:更新向量字段(如 embedding 升级后重新编码)
- DELETE:删除向量数据、级联删除
- 批量操作的性能优化:COPY 命令、UNNEST 批量插入、事务批处理
4.2 结构化 + 向量的混合查询(pgvector 的杀手锏)
- 为什么混合查询是 pgvector 的核心优势:独立向量数据库需要两次查询(先向量搜索再结构化过滤),pgvector 一条 SQL 搞定
- WHERE + ORDER BY 向量距离:
SELECT * FROM docs WHERE category = 'tech' ORDER BY embedding <=> '[0.1,...]' LIMIT 5 - 多条件组合:时间范围 + 分类过滤 + 向量搜索
- JSONB metadata + 向量搜索:
WHERE metadata @> '{"category": "faq"}' ORDER BY embedding <=> query_vec - 性能对比:pgvector 混合查询 vs Chroma where 过滤 vs Milvus 标量过滤
4.3 Python 完整 CRUD 封装
- PGVectorManager 类:封装连接管理、CRUD 操作、批量操作
- 参数化查询:防止 SQL 注入的最佳实践
- 连接池配置:psycopg2.pool / asyncpg 连接池
- 异步操作:asyncpg + pgvector 的高性能异步方案
- ORM 集成:SQLAlchemy + pgvector 的使用方式
第5章:向量索引与性能优化
5.1 为什么需要向量索引
- 暴力搜索的瓶颈:O(N×d) 的距离计算,10万条 768 维向量的全表扫描需要数百毫秒
- 近似最近邻(ANN)的权衡:牺牲少量精度换取数量级的速度提升
- pgvector 支持的两种索引:IVFFlat(倒排文件)和 HNSW(分层导航小世界图)
5.2 IVFFlat 索引
- IVFFlat 原理:将向量空间划分为 K 个区域(聚类中心),搜索时只扫描查询向量附近的几个区域
- 创建索引:
CREATE INDEX ON docs USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100); - lists 参数选择:√N(数据量的平方根)是经验起点,lists 过大/过小的影响
- ** probes 参数**:搜索时扫描的区域数量,
SET ivfflat.probes = 10; - IVFFlat 的局限:需要先有数据再建索引(聚类中心依赖数据分布)、索引构建慢、召回率受 probes 影响
5.3 HNSW 索引
- HNSW 原理:多层图结构,从顶层向下导航,O(log N) 搜索复杂度
- 创建索引:
CREATE INDEX ON docs USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64); - m 参数:每层最大连接数,影响索引大小和召回率(默认 16,推荐 16~64)
- ef_construction 参数:建索引时的搜索宽度,影响索引质量和构建速度(默认 64,推荐 64~200)
- ef_search 参数:查询时的搜索宽度,
SET hnsw.ef_search = 100;(默认 40,推荐 40~200) - HNSW vs IVFFlat 对比:
维度 IVFFlat HNSW 构建速度 快 慢 查询速度 快(probes 适中时) 更快 召回率 依赖 probes 更稳定 内存占用 小 大(2~3x 数据量) 增量更新 需重建索引 支持增量 推荐场景 数据量大且稳定 数据量中等且频繁更新
5.4 索引选型与调优实战
- 何时建索引:数据量 < 10K 不需要索引(暴力搜索足够快)
- 索引类型选择决策树:数据量 / 更新频率 / 召回率要求 / 内存预算
- 距离操作符与索引的对应关系:
vector_l2_ops→ L2 距离(<->)vector_cosine_ops→ 余弦距离(<=>)vector_ip_ops→ 内积距离(<#>)- ⚠️ 索引创建时指定的 ops 必须与查询时使用的操作符一致!
- EXPLAIN ANALYZE 诊断:确认索引是否被使用、扫描行数、实际耗时
- 性能基准:不同数据量/维度/索引类型的 QPS 和 Recall@K 对比
第6章:pgvector 在 RAG 系统中的实战
6.1 RAG 架构中 pgvector 的角色
- pgvector vs Chroma 在 RAG 中的定位差异:
- Chroma:纯向量数据库,适合快速原型
- pgvector:关系型数据库 + 向量能力,适合需要结构化数据和事务一致性的生产系统
- pgvector 的独特优势:
- 结构化数据 + 向量数据在同一张表 → 无需数据同步
- SQL JOIN 能力 → 文档表 + 用户表 + 向量表自由关联
- 事务保证 → 文档入库和向量索引更新的原子性
- 成熟的运维工具 → pg_dump、pg_stat_statements、pg_stat_activity
- RAG 全链路中 pgvector 覆盖的环节:文档存储 + 向量索引 + 混合查询 + 来源溯源
6.2 端到端 RAG Demo:文档问答系统
- 项目结构:数据加载 → 切分 → embedding → 入库 pgvector → 检索 → 生成
- 表设计:sql
CREATE TABLE documents ( id SERIAL PRIMARY KEY, source TEXT NOT NULL, category TEXT, content TEXT NOT NULL, embedding vector(384), metadata JSONB, created_at TIMESTAMP DEFAULT NOW() ); - Python 完整实现:
- 文档加载与切分(递归字符级切分)
- Embedding 编码(SentenceTransformers)
- 批量入库(COPY / UNNEST 高效插入)
- 混合查询(WHERE + ORDER BY embedding <=> query_vec)
- Prompt 组装与 LLM 调用
- 来源溯源:利用 SQL JOIN 关联文档表和用户表,在回答中引用来源
6.3 对话记忆与用户画像
- 对话历史表设计:session_id / role / content / embedding / created_at
- 长期记忆表设计:user_id / preference_key / preference_value / embedding
- 混合检索:同时搜索文档库和记忆库,用 UNION 或 JOIN 合并结果
- TTL 清理:利用 PostgreSQL 的定时任务(pg_cron)自动清理过期记忆
第7章:生产部署与进阶主题
7.1 生产部署方案
- Docker Compose 部署:PostgreSQL + pgvector + 应用服务
- 云托管方案:AWS RDS / Azure Database / 阿里云 RDS PostgreSQL(需确认 pgvector 扩展支持)
- 连接池配置:pgbouncer(生产标配)、连接数规划
- 备份与恢复:pg_dump / pg_restore / WAL 归档 / 时间点恢复(PITR)
- 高可用方案:流复制(Streaming Replication)/ 逻辑复制 / Patroni 自动故障转移
7.2 性能调优与监控
- PostgreSQL 核心参数调优:
shared_buffers:共享缓冲区大小(建议物理内存的 25%)work_mem:排序和哈希操作的内存(影响向量索引构建)effective_cache_size:操作系统缓存估计(影响查询计划选择)
- pgvector 专用参数:
ivfflat.probes/hnsw.ef_search:搜索精度与速度的权衡
- 监控工具:
pg_stat_statements:慢查询分析pg_stat_activity:连接和锁监控pg_stat_user_indexes:索引使用率- Prometheus + postgres_exporter + Grafana 可视化
- 常见性能问题与排查:
- 索引未被使用 → 检查操作符是否匹配、数据量是否太小
- 查询越来越慢 → 检查表膨胀、索引膨胀、是否需要 VACUUM
- 内存不足 → 调整 shared_buffers、work_mem
7.3 pgvector 的局限性与替代方案
- 已知局限:
- 单机架构,不支持原生分布式(最大规模约 1 亿向量,取决于内存)
- HNSW 索引全内存驻留,数据量大时内存消耗高
- 向量维度上限 2000(pgvector 0.7.x)
- 不支持量化索引(PQ/SQ),无法做向量压缩
- 增量数据量大时 IVFFlat 索引需要重建
- 何时该用 pgvector:
- 已有 PostgreSQL 基础设施,不想引入新组件
- 需要结构化数据和向量数据的强一致性
- 数据量 < 1000 万向量
- 需要复杂的 SQL 查询能力(JOIN、子查询、窗口函数)
- 何时该换:
- 数据量 > 1 亿向量 → Milvus
- 需要分布式 → Milvus / Qdrant
- 需要向量压缩(量化) → FAISS / Milvus
- 需要多模态内置支持 → Weaviate
- pgvector 与其他方案共存:小规模用 pgvector,大规模用 pgvector + Milvus 混合架构
🎯 学习路径建议
PostgreSQL 新手(2-3天):
第1-2章 → 掌握 PostgreSQL 的基本操作和核心概念
→ 能用 Python 连接 PG、执行 CRUD、理解索引和事务
RAG 开发者(2-3天):
第3-4章 → 掌握 pgvector 的安装、vector 类型、混合查询
→ 能用 pgvector 搭建完整的文档检索 pipeline
生产工程师(3-5天):
第5-7章 → 掌握向量索引调优、部署方案、监控运维
→ 能让 pgvector 在生产环境中稳定高效运行
深度研究者:
全部章节 → 理解 pgvector 的设计权衡
结合 IVFFlat/HNSW 算法原理、PostgreSQL 索引架构、MVCC 机制深入理解📚 与 Chroma 教程的对照阅读
如果你已经学过本系列的 Chroma 教程,以下是两个教程的核心对照:
| 概念 | Chroma | pgvector |
|---|---|---|
| 数据模型 | Document (id/text/embedding/metadata) | Table Row (id/content/embedding/metadata columns) |
| 集合 | Collection | Table |
| 距离度量 | 创建时指定(hnsw:space) | 查询时选择操作符(<->/<=>/<#>) |
| 过滤 | where (Python dict) | WHERE (SQL) |
| 索引 | 自动 HNSW | 手动创建 IVFFlat/HNSW |
| 事务 | 无 | 完整 ACID |
| 部署 | 嵌入式 / Docker | Docker / 云托管 RDS |
| 适合规模 | < 10M 向量 | < 100M 向量(取决于内存) |
| 核心优势 | 零配置、Python 原生 | SQL 原生、事务一致性、混合查询 |
本大纲遵循以下写作原则:每节以白板式通俗介绍开场 → 深入原理与面试级知识点 → 配合代码示例("比如下面的程序...")→ 覆盖常见用法与误区 → 结尾总结要点衔接下一节。