September 19, 2026 in 计算机与网络8 minutes
介绍数据库的基础知识。
关系型数据库(Relational Database)是目前应用最广泛的数据库类型,MySQL、PostgreSQL、Oracle、SQL Server 等均属此类。其核心在于用数学上严谨的“关系”模型来组织数据,并用声明式语言(SQL)操作数据,使用者只需说明“要什么”,无需关心“怎么取”。
1970 年,IBM 研究员 E. F. Codd 发表论文《大型共享数据库的数据关系模型》,提出用集合论与一阶谓词逻辑描述数据,取代当时主流的层次模型和网状模型。这一模型包含三个层面:
之所以称为“关系型”,源于数学概念:表中的每一行都是属性取值的一个 n 元组,整张表则是这些元组构成的集合(即笛卡尔积的子集)。这里的“关系”指代数学上的关系,而非表与表之间的关联。
| 术语 | 含义 |
|---|---|
| 关系(Relation) | 一张表 |
| 元组(Tuple) | 一行记录 |
| 属性(Attribute) | 一列字段 |
| 域(Domain) | 属性的合法取值范围 |
| 模式(Schema) | 表的结构定义(列名、类型、约束),相对稳定 |
| 实例(Instance) | 某一时刻表中的实际数据,随时变化 |
**键(Key)**是关系模型的灵魂:
表与表之间通过外键建立联系,而非像网状模型那样使用物理指针。这种逻辑上的关联正是关系模型实现数据独立性的关键。
这三类约束将数据质量的控制权从应用程序转移到了数据库层,从根本上避免了脏数据的产生。
关系代数提供了一组闭包运算:输入是关系,输出仍是关系,因此可以嵌套组合。基本运算包括:
SQL 是关系代数的工程实现,但两者存在差异:SQL 的表允许重复行(多重集),且支持排序、分组聚合等扩展功能。SQL 属于声明式语言,用户编写 SELECT ... WHERE ... 描述目标结果,具体执行路径由优化器决定。
规范化旨在消除数据冗余及更新异常(插入异常、删除异常、修改异常),其依据是函数依赖:
规范化程度越高,冗余越低,但查询时的连接操作也会增多。因此在实际工程中常需在范式与性能之间权衡,有时会故意进行反规范化(如数据仓库中的星型模型)。
当多步操作需要作为一个整体执行时(如转账),便涉及事务机制:
并发控制通常采用锁机制(共享锁/排他锁、两阶段锁协议)或 MVCC(多版本并发控制);隔离级别从低到高分为读未提交、读已提交、可重复读、串行化,级别越高,并发性能越差。
恢复机制则依赖 WAL(预写式日志):修改数据前先写日志,崩溃后可通过重做(REDO)与撤销(UNDO)保证持久性和原子性。
逻辑层面的“表”在磁盘上需要具体的存储结构:
适合:数据结构清晰、需要强一致性与复杂查询、存在大量关联分析的业务系统(如订单、账务、库存、ERP、CRM)。
不适合:超大规模写入、schema 频繁变动、海量非结构化数据或需要极高横向扩展的场景。这类需求往往更适合 NoSQL(键值、文档、列存、图数据库),这也正是近年来 NewSQL 与分布式数据库试图弥补的方向。
SQL(Structured Query Language,结构化查询语言)是用于管理和操作关系型数据库的标准语言。它并非编程语言,而是一种声明式语言:你只需描述“想要什么数据”,而不必关心“如何取到数据”,具体的执行路径由数据库引擎自行优化。
| 概念 | 说明 |
|---|---|
| 数据库(Database) | 数据的容器,一个实例下可建多个库 |
| 表(Table) | 数据以行(记录)和列(字段)组织,类似二维表格 |
| 字段 / 列(Column) | 定义数据的属性,有名称和数据类型 |
| 行 / 记录(Row) | 一条完整的数据 |
| 主键(Primary Key) | 唯一标识一行数据的列,不可重复、不可为空 |
| 外键(Foreign Key) | 指向另一张表主键的列,用于建立表间关系 |
| DBMS | 数据库管理系统,如 MySQL、PostgreSQL、SQL Server、Oracle、SQLite |
注意:不同 DBMS 在语法细节上存在差异(如分页写法、字符串拼接、日期函数等),下文以标准 SQL 为主,并在关键处标注常见方言区别。
SELECT —— 最常用,占日常工作的八成INSERT / UPDATE / DELETECREATE / ALTER / DROP / TRUNCATEGRANT / REVOKECOMMIT / ROLLBACK / SAVEPOINTINT、BIGINT、DECIMAL(10,2)(金额用这个,别用浮点)、FLOAT、DOUBLECHAR(n)(定长)、VARCHAR(n)(变长)、TEXTDATE、TIME、DATETIME、TIMESTAMP(注意时区问题)BOOLEAN(MySQL 内部用 TINYINT(1) 模拟)JSON、BLOB、枚举类型等选型原则:够用即可。金额用 DECIMAL,手机号用 VARCHAR(因为可能有 +86 或前导 0),性别这种固定值用 TINYINT 或枚举。
SELECT name, age -- 选哪些列
FROM users -- 从哪张表
WHERE age >= 18 -- 过滤条件
AND status = 'active'
ORDER BY age DESC, name ASC -- 排序
LIMIT 10 OFFSET 20; -- 分页:跳过20条,取10条执行顺序(非常重要,与书写顺序不同):
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
这意味着:WHERE 里不能用 SELECT 中定义的别名,因为它还没执行到那一层。
SELECT DISTINCT department FROM employees; -- 去重
SELECT COUNT(*) AS total FROM users; -- 计数(别名用 AS)
SELECT * FROM users LIMIT 5; -- 只看前几行,探索表结构时很实用COUNT(*) 统计行数(含 NULL),COUNT(列名) 统计该列非 NULL 的行数。
WHERE age BETWEEN 18 AND 30 -- 区间(包含两端)
WHERE name IN ('Alice', 'Bob', 'Carol') -- 集合匹配
WHERE email LIKE '%@gmail.com' -- 模糊匹配:%任意字符,_单个字符
WHERE phone IS NULL -- 判断空值,不能用 = NULL
WHERE age IS NOT NULL
WHERE NOT (age < 18) -- 逻辑取反⚠️ 两个高频坑:
NULL 不等于任何值,包括它自己。NULL = NULL 结果是 UNKNOWN,必须用 IS NULL。LIKE '张%' 能走索引,LIKE '%张' 通常走不了(前导通配符)。SELECT
department,
COUNT(*) AS emp_count,
AVG(salary) AS avg_sal,
MAX(salary) AS max_sal,
SUM(salary) AS total_sal
FROM employees
WHERE hire_date >= '2020-01-01'
GROUP BY department
HAVING AVG(salary) > 8000 -- 对分组后的结果再过滤
ORDER BY avg_sal DESC;常用聚合函数:COUNT()、SUM()、AVG()、MAX()、MIN()、GROUP_CONCAT()(MySQL)。
规则:SELECT 中出现的非聚合列,必须出现在 GROUP BY 里,否则结果不确定(MySQL 宽松模式下不报错但数据是错的)。
WHERE vs HAVING:WHERE 在分组前过滤行,HAVING 在分组后过滤组。能用 WHERE 的就别放 HAVING,性能更好。
假设有 users 表和 orders 表:
SELECT u.name, o.order_no, o.amount
FROM users u -- u 是别名,简洁且推荐
JOIN orders o ON u.id = o.user_id;连接类型:
| 类型 | 含义 |
|---|---|
INNER JOIN(内连接) |
只保留两表都能匹配上的行 |
LEFT JOIN(左连接) |
保留左表全部行,右表无匹配则填 NULL |
RIGHT JOIN |
保留右表全部行(少用,写成 LEFT JOIN 更清晰) |
FULL OUTER JOIN |
两表都保留(MySQL 不支持,可用 UNION 模拟) |
CROSS JOIN |
笛卡尔积,慎用 |
-- 找出"从未下过单的用户"——经典左连接判空模式
SELECT u.name
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.id IS NULL;多表连接时,驱动表(左表)尽量小,连接字段要建索引,否则会产生慢查询。
子查询(标量、行、表子查询):
-- 标量子查询:返回单个值
SELECT name FROM users
WHERE salary > (SELECT AVG(salary) FROM users);
-- IN 子查询
SELECT name FROM users
WHERE id IN (SELECT user_id FROM orders WHERE amount > 1000);
-- EXISTS:通常比 IN 效率高,尤其在大数据量时
SELECT name FROM users u
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);集合操作:UNION(去重合并)、UNION ALL(不去重,更快)、INTERSECT(交集)、EXCEPT(差集)。要求两个查询的列数和类型对应一致。
INSERT INTO users (name, age, email)
VALUES ('Alice', 25, 'alice@example.com');
-- 批量插入(性能远高于逐条插入)
INSERT INTO users (name, age) VALUES ('Bob', 30), ('Carol', 28);
UPDATE users
SET age = 26, status = 'active'
WHERE id = 1; -- 务必带 WHERE!
DELETE FROM users WHERE id = 1; -- 务必带 WHERE!⚠️ 铁律:执行 UPDATE / DELETE 前,先把条件换成 SELECT * 跑一遍,确认影响的行数对不对。生产环境误删数据是最常见的事故之一。
TRUNCATE TABLE t 会清空整表且不可回滚(DDL),比 DELETE 快;DROP TABLE t 则是连表结构一起删掉。
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
age INT CHECK (age >= 0 AND age <= 150),
dept_id BIGINT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (dept_id) REFERENCES departments(id) ON DELETE SET NULL
);
ALTER TABLE users ADD COLUMN phone VARCHAR(20); -- 加列
ALTER TABLE users DROP COLUMN phone; -- 删列
ALTER TABLE users MODIFY COLUMN name VARCHAR(100); -- 改类型
DROP TABLE users; -- 删表常用约束:PRIMARY KEY、NOT NULL、UNIQUE、CHECK、DEFAULT、FOREIGN KEY。
外键能保证数据一致性,但高并发场景下常带来锁竞争,因此很多互联网项目选择在应用层维护关联关系(逻辑外键)。
CREATE INDEX idx_email ON users(email); -- 普通索引
CREATE UNIQUE INDEX idx_email ON users(email); -- 唯一索引
CREATE INDEX idx_dept_age ON users(dept_id, age); -- 复合索引
SHOW INDEX FROM users; -- 查看索引(MySQL)核心要点:
(a, b, c) 可用于 a、a+b、a+b+c 的查询,但单独查 b 或 c 用不上。WHERE YEAR(created_at)=2024)、隐式类型转换(字符串字段不加引号)、OR 条件、!=、LIKE '%xx'。视图(虚拟表,封装复杂查询):
CREATE VIEW v_active_users AS
SELECT name, email FROM users WHERE status = 'active';事务(保证一组操作要么全成功、要么全失败):
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT; -- 提交;出错则 ROLLBACK;ACID 四性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。隔离级别从低到高:读未提交 → 读已提交 → 可重复读(MySQL 默认) → 串行化。
其他实用对象:存储过程、函数、触发器、CTE(公用表表达式,WITH ... AS (...) SELECT ...,可读性远优于嵌套子查询,强烈推荐)。
非关系型数据库(NoSQL,Not Only SQL)并非单一技术,而是一批放弃关系模型某些特性,以换取扩展性、灵活性或特定查询性能的数据库的统称。理解它的关键在于搞清楚它们各自放弃了什么,以及为何值得放弃。
关系数据库在 2000 年代末遇到了一组难以同时满足的需求,催生了 NoSQL 的兴起:
ALTER TABLE 在大表上往往是灾难性的操作。背后的理论支撑主要有两个:
核心思路在于:不再追求通用性,而是针对特定访问模式做极致优化。
代表:Redis、DynamoDB、Riak、etcd
原理:数据模型退化为最简形式——一个 key 对应一个 value(value 通常为不透明的二进制大对象或字符串),只支持 get、set、delete。
适用:缓存、会话存储、计数器、排行榜、分布式锁、消息队列。不适用:需要按 value 内容查询或多维筛选的场景。
代表:MongoDB、CouchDB、Firestore
原理:value 升级为半结构化文档(JSON/BSON),数据库能理解文档内部结构,支持对嵌套字段建索引、按字段查询、聚合管道。
适用:内容管理、用户画像、商品目录、快速迭代的业务系统。它是关系数据库最常见的替代或补充方案。
代表:Cassandra、HBase、Bigtable、ScyllaDB
原理:这是最容易误解的一类。它的“列存”与 OLAP 的列存不同,准确说是二维有序键值映射:
row_key → { column_family → { column_qualifier: value, timestamp } }
几个关键点:
consistency level(ONE / QUORUM / ALL / LOCAL_QUORUM)在每次读写时选择一致性与延迟的平衡点,公式 R + W > N 保证强一致。适用:海量写入、时间序列、事件存储、消息历史。不适用:复杂查询、频繁更新删除、需要事务的场景。
代表:Neo4j、JanusGraph、NebulaGraph、TigerGraph
原理:当业务的核心复杂度在于关系本身(而非实体属性)时,关系数据库的 JOIN 会随着跳数指数级退化。图数据库改用指针式物理邻接:每个节点直接持有指向其关系的物理指针,遍历一条边就是一次指针跳转,查询复杂度与图总规模无关,只与 traversed subgraph 大小有关。这就是“index-free adjacency”。
适用:社交网络、推荐系统、知识图谱、风控反欺诈(关系链路识别)、权限与依赖分析。不适用:简单 CRUD、聚合统计。
| 类型 | 代表 | 核心思路 |
|---|---|---|
| 搜索引擎 | Elasticsearch、Solr | 倒排索引:词项 → 文档列表 + 位置/频率,支持全文检索、模糊、相关性打分(TF-IDF/BM25) |
| 时序数据库 | InfluxDB、Prometheus、TDengine | 时间为主键,列式压缩(delta-of-delta、Gorilla 压缩),降采样与连续查询,高压缩比 |
| 向量数据库 | Milvus、Pinecone、pgvector | 近似最近邻(ANN):HNSW 图索引、IVF 量化,牺牲精度换召回速度,服务大模型 RAG |
| NewSQL / 分布式 SQL | TiDB、CockroachDB、Spanner | 用分布式共识(Raft)+ 分布式事务(Percolator / 2PC + 时间戳序)重建 SQL 的强一致与水平扩展,本质是"既要" |
NoSQL 的价值大半体现在分布式能力上,以下几项机制几乎是共通的:
1. 分片(Sharding / Partitioning)
hash(key) mod N 分配(Cassandra、MongoDB 的哈希分片)。写入均匀,但范围查询需 scatter-gather 到所有分片。2. 复制(Replication)
3. 一致性模型(这是个谱系,不是二选一)
强一致 → 顺序一致 → 因果一致 → 会话一致 → 最终一致
工程上常见的手段包括:Quorum 机制(R+W>N)、向量时钟与版本向量(检测并发写冲突)、Merkle Tree(抗熵修复,用于节点间数据校验)、读修复与 hinted handoff。
4. 冲突解决
放弃强一致后,必须回答“两个客户端同时改了同一个 key,留哪个”。常见策略包括 LWW(最后写入胜出,依赖时钟,有时钟漂移风险)、版本向量 + 兄弟节点保留(交由应用层合并,如 Riak)、CRDT(数学上保证收敛的数据结构)。
| 维度 | 关系型 | NoSQL |
|---|---|---|
| 数据模型 | 表 + 行,schema 固定 | 多样,schema 灵活或无 schema |
| 关联 | JOIN(任意方向、多表) | 基本不支持,靠应用层组装或数据冗余 |
| 事务 | ACID,多行多表 | 大多单行/单文档原子,少数支持多文档 |
| 查询语言 | SQL(声明式、统一) | 各异,多为 API 或专有 DSL |
| 扩展 | 纵向为主,分库分表需人工介入 | 横向扩展为原生设计 |
| 一致性 | 强一致 | 可调,多为最终一致 |
| 优化器 | 有(代价估算、执行计划) | 大多没有,查询能力由索引和 key 设计预先决定 |
最后一行尤为重要:在关系数据库中,写好 SQL 即可依赖优化器寻找路径;而在多数 NoSQL 中,必须在建模阶段就预判查询模式,因为事后无法通过加索引来弥补设计缺陷(尤其是 Cassandra 这类,换一种查询往往就得新建一张表)。
**选型原则:先定查询模式,再选数据库。**具体步骤如下:
常见坑:
如今纯粹的“NoSQL vs SQL”之争已基本结束,主流形态演变为多模持久化(polyglot persistence):一个系统里 MySQL 管交易、Redis 管缓存、ES 管搜索、ClickHouse 管分析、Neo4j 管关系,各司其职,由应用层编排。同时,关系数据库也在吸收 NoSQL 的特性(如 JSON 类型、列存引擎、分布式扩展),而 NoSQL 也在补回事务与 SQL(如 MongoDB 的事务、Cassandra 的 CQL)。两者的边界正日益模糊。
向量数据库要回答的核心问题是:给定一个向量,如何在百万到百亿规模的向量集合里,快速找到和它“最相似”的那一批。
这个需求来自 embedding 技术。文本、图片、音频、视频经过神经网络编码后变成固定长度的稠密向量(如 768、1024、4096 维),语义相近的内容在向量空间中距离更近。于是“搜索”被转化为“最近邻查找”。典型场景包括 RAG 知识检索、以图搜图、推荐召回、去重与相似内容识别,以及 Agent 的记忆检索。
关键在于:精确最近邻在大规模下不可行。暴力扫描需要逐个计算距离并排序,复杂度为 O(n·d),十亿级数据单次查询耗时达秒级。因此,向量数据库本质上是近似最近邻(ANN, Approximate Nearest Neighbor)索引引擎——通过牺牲少量精度(如召回率从 100% 降至 95%),换取数百倍甚至千倍的性能提升。
距离度量的选择直接影响结果,且必须与 embedding 模型及训练目标匹配:
| 度量 | 公式 | 适用 |
|---|---|---|
| L2 欧氏距离 | ‖x−y‖² | 通用,SIFT 等图像特征 |
| 内积 IP | x·y | 推荐系统、未经归一化的 embedding |
| 余弦相似度 | x·y/(‖x‖‖y‖) | 文本 embedding 最常用 |
| 汉明距离 | bit 异或计数 | 二值化向量(PQ 残差、感知哈希) |
| 曼哈顿 L1 | Σ|xᵢ−yᵢ| | 较少用 |
一个重要工程技巧:当向量被 L2 归一化后,余弦相似度等价于内积,而最大化内积又等价于最小化 L2 距离。因此大多数引擎内部统一转化为一种运算,再通过归一化预处理切换语义。这也是为什么建索引前是否做 normalize 会显著影响结果。
另外需要注意:距离度量必须在索引构建时确定,构建后无法更改(因为索引结构本身依赖该度量)。更换度量通常需要重建索引。
这是理解向量索引的前提。B+ 树、KD-Tree、R-Tree 这类结构依赖“空间划分”来剪枝,但在高维空间中会出现维度灾难:
因此,现代 ANN 索引基本放弃了严格的空间划分,转向三条路线:量化(压缩)、图(邻接跳转)、哈希(随机投影),以及它们的组合。
思路类似“先分桶再细找”:
center_id → 向量列表 的倒排。代价:只需扫描全量的 nprobe/nlist(如 1%),速度提升百倍。风险:如果 query 落在簇边界附近,真正的近邻可能在相邻簇里被漏掉。增大 nprobe 能提高召回但会降低速度。
IVF 很少单独使用,通常作为“第一级路由”与其他技术叠加,例如 Faiss 经典的 IVF4096,PQ64。
这是降低内存与计算成本的核心手段。假设一个 128 维 float32 向量占 512 字节,十亿条就是 480GB,完全放不下内存。
PQ 的做法:
距离计算时不再还原向量,而是查表累加:预先算出 query 每段与各码字的距离(m×k 的小表),两个向量的距离 ≈ 各段码字间距离之和。这叫 ADC(Asymmetric Distance Computation)。
精度损失来源:每段内的 256 个码字只能近似表达该子空间,残差被丢弃。改进版本包括 OPQ(先做一次旋转使各段方差更均衡)、RQ(残差量化,逐层量化残差)、SQ(标量量化,每维直接均匀离散化为 4bit/8bit,实现简单且在现代硬件上往往优于 PQ)。
理解它需要拆成两部分:
(a)小世界图。构造一张图,节点是向量,边连接“较近”的节点。其特性是:任意两节点间存在一条短路径,且局部连通性良好。搜索时从入口点出发,采用贪心策略走向“离 query 更近的邻居”,迭代至无法更优。这种方式的跳转次数是 O(log n) 级别,且每次跳转都在局部,缓存友好。
(b)分层结构(借鉴跳表)。单层图的问题是容易陷入局部最优。HNSW 给节点分配多个层级(按指数衰减概率抽样,越高层越稀疏):
关键参数:
M:每节点最大出边数(一般 16~64)。越大图越密、召回越高,但内存和构建时间线性增长。efConstruction:建图时的候选池大小,影响图质量(建好后不可改)。efSearch:查询时的候选池大小,这是召回与速度的主要调节旋钮,可在线调整。优点:召回率极高(常 >98%)、无需训练阶段、支持在线插入。缺点:内存占用大(每张图的边都要存指针/ID),十亿级需要百 GB 级内存;删除节点困难(通常只做逻辑标记)。
微软提出的思路:用量化压缩向量放内存作为“导航图”,原始向量放 SSD,通过精心设计的 I/O 预取让磁盘访问次数可控。这使得单机就能支撑亿级甚至十亿级向量,成本远低于纯内存方案。Qdrant 的 mmap 模式、Milvus 的 DiskANN 索引均采用此路线。
实际产品极少只用一种算法,而是多级流水线:
query → 归一化
→ IVF 粗筛(nprobe 个簇,缩小到万级)
→ 图索引精搜(efSearch 控制)
→ PQ/SQ 解码算距离
→ top-k 重排(可选:用原始向量精算一次)
→ 返回
Faiss 的命名就体现了这种组合:IndexIVFHNSWPQ = IVF 路由 + HNSW 簇内搜索 + PQ 压缩。理解这种拼接方式,比死记单个算法更有用。
很多人以为向量数据库就是 FAISS 包一层 HTTP,差别其实体现在以下方面:
1. 元数据过滤(filtering)。真实查询几乎都带条件:“找相似图片,且属于用户 A,时间在最近 30 天,标签不含已读”。这带来难题:ANN 的跳转顺序与过滤条件无关,可能扫了几万个点才凑够 k 个满足条件的。
两种解法:
成熟做法是自适应选择(根据过滤选择性估计决定),并配合位图索引、倒排标量索引、Bloom filter。Qdrant 的 payload 索引、Milvus 的 ScalarIndex 均属此类。这是选型时最容易踩坑的地方——很多引擎的过滤性能远不如宣传。
2. 混合检索与重排。单纯向量检索对关键词精确匹配、数字、专有名词表现不佳。工业界普遍采用 BM25(稀疏/关键词)+ 向量(稠密)双路召回,再用 RRF(倒数排名融合)或加权打分合并,最后交给 Cross-Encoder 重排。这也是 RAG 提升召回率的标准配置。
顺便提一句:稀疏向量检索(如 SPLADE、BM25 的向量化表达)正在回归,ColBERT 这类“多向量”方案也模糊了稀疏与稠密的界限。
3. 增删改与实时性。HNSW 不擅长删除。常见做法是 tombstone 标记 + 定期 vacuum/重构,或者采用 LSM 式分段:新数据写入 mutable segment(内存或小图),满后冻结为 immutable segment 并建索引,查询时 merge 多段结果。Milvus 的 growing segment / sealed segment 就是这套机制。
4. 分布式。包括一致性哈希或范围分片、副本复制、Raft 主从、查询 scatter-gather 与各分片 top-k 归并。这里有个细节:各分片返回 top-k 后再全局归并,得到的并非全局精确 top-k,但在 ANN 语境下误差可接受。
5. 持久化与容错。日志追加、checkpoint、对象存储下沉冷数据、多租户隔离。云原生托管服务(Pinecone、Weaviate Cloud、Milvus Zilliz)的价值主要在此,而非算法本身。
建议使用标准数据集(SIFT1M、GIST1M、Deep1B)做基准测试,避免被厂商单点优化数据误导。
| 类型 | 代表 | 特点 |
|---|---|---|
| 专用引擎 | Milvus、Qdrant、Weaviate、Vespa、Zilliz、Pinecone、LanceDB | 功能全、支持过滤/混合/分布式 |
| 库 | FAISS(Meta)、ScaNN(Google)、NGT、RAFT(NVIDIA) | 性能基座,需自建服务层 |
| 数据库插件 | pgvector(PostgreSQL)、Elasticsearch/OpenSearch kNN、ClickHouse、Redis Stack、MongoDB Atlas Vector Search | 运维统一,适合中小规模 |
| 文件格式 | Lance、HDF5、Parquet+embedding | 离线分析、湖仓一体 |
一个务实的建议:数据量在千万级以下、团队已有 PostgreSQL 时,pgvector 通常是首选。它支持 HNSW 与 IVFFlat,能和事务、权限、JOIN 共存,运维成本极低。只有当规模、QPS 或过滤复杂度超出其能力时,才值得引入专用引擎。
向量数据库并没有取代关系型或非关系型数据库,而是成为多模持久化中的又一专才。典型的 RAG 架构大致如下:
PostgreSQL / MySQL —— 交易与结构化事实(权威源)
Redis —— 缓存、会话、限流
Elasticsearch —— 关键词检索、日志
Vector DB —— 语义召回
ClickHouse —— 行为分析与埋点
Neo4j —— 实体关系与权限链路
其中关键决策在于:embedding 应该存在哪。越来越多的系统选择“主库自带向量能力”(如 pgvector、MySQL HeatWave、SQL Server 向量),以避免数据同步带来的复杂性。反过来,向量数据库也在补回 SQL、事务与 ACID(如 Milvus 的 Hybrid Search、Weaviate 的聚合)。两者的边界正在模糊,正如当年 NoSQL 与 SQL 的演进轨迹。
未来的变量主要有三个:GPU 原生检索(让暴力扫描重新具备竞争力)、端到端可微检索(索引本身参与训练)、以及多模态统一空间(图文音视频共用一套索引)。
如果需要进一步探讨,可以深入了解以下方向之一: