TiDB 内核解剖室SECTION 04

把向量存进关系表,一次 Top-K 检索 —— 全表逐点扫,还是沿 HNSW 图跳?两条路都走给你看

1024 TiDB AIGC 黑客松 · 参赛作品 v0.2
检索路径 · 暴力扫描(全表逐点)
400 个向量点 · 固定种子(LCG #20261024)· 三维真实距离 · 可复算

同一个查询点(空心圆),两种找法:暴力扫描逐点比距离,一个不漏;HNSW 沿近邻图从入口点逐跳逼近,候选池收窄后只在最后一段做近邻比较。这一版里没有"画出来的路径"—— 距离、跳数、访问点数、召回率都是页面当场算的;三维点阵与近邻图都由固定种子当场生成,每次打开完全一致,可对照复算;图的构造(每点连几个近邻、层 1 采样比例)为教学选定 —— 见页尾边界声明。

两条检索路径 · 点一下分别走一遍
Top-K
距离函数
数据规模
分布
探索预算

探索预算 = 一次检索最多展开多少个候选(候选池容量上限;本站演示命名 —— 真实索引的内部参数由 TiFlash 管理,官方未公开);距离、访问点数、召回率均为当场计算。点住画布拖动查询点,数字实时重算;拖动空白处可旋转视角(双击复位)。

暴力扫描:N 个点,一个不漏。每个点都与查询点算一次距离,排序取最相近的 K 个 —— 结果精确,但计算量与数据量成正比:数据翻倍,计算就翻倍。这就是引入向量索引之前的原始做法。
HNSW:先跳远、再收窄。层 1(稀疏层)从入口点贪心跳远:每一步只走「更近的那个邻居」,结构上的一步可以横跨很远的空间;落到局部最优后,在层 0 用一个小候选池边收窄边比较。它不保证扫过全部数据,所以结果是近似值;官方口径:搜索召回率通常可保持在 90% 以上。换来的是距离计算次数从全表量级降到路径量级 —— 少算多少、漏没漏,右侧当场统计。
暴力扫描 · 精确 Top-5
HNSW · 近似 Top-5

行号 #1…#K 与画布上的名次标号一一对应,每行附真实距离值;HNSW 列中落在精确集之外的行标「近似」(琥珀标)—— 召回率 = 命中数 ÷ K,当场计算、不查表;换个分布或规模,召回率会跟着变。

①前置依赖 · 为什么它旁边总站着 TiFlash?

向量索引必须提前部署 TiFlash 节点。建表时定义向量索引,TiDB 会自动创建 TiFlash 副本;没有走到这一步的表,需要显式执行 ALTER TABLE ... SET TIFLASH REPLICA 1。索引的构建与检索都在列存侧完成 —— 这是本页与前几台演示台最大的不同。

②算法与距离函数 · 选项少得有点意外

算法只有一种:目前仅支持 HNSW(Hierarchical Navigable Small World)。距离函数只有两个:余弦距离 VEC_COSINE_DISTANCE() 与 L2 距离 VEC_L2_DISTANCE() —— 使用时必须指定,且需与索引一致。选错距离函数不是"慢一点",而是直接回不到索引上。

③预过滤陷阱 · 带 WHERE 反而不走索引

WHERE 在 KNN 之前执行,所以包含预过滤的查询无法利用向量索引。正确姿势:先在子查询里做 KNN,再在外层过滤 —— 但注意,外层过滤掉部分结果后,最终返回条数可能少于 LIMIT 指定值。这个坑首页就点了名,现在你知道它长什么样了。

④确认命中 · 别猜,去看执行计划

EXPLAIN 的 operator info 中出现 annIndex: 才表示走了向量索引。没指定 Top K、距离函数不匹配、或用了 DESC 排序,都会退回全表 —— 此时 SHOW WARNINGS 会告诉你原因。

反例台 ① · 预过滤陷阱(同一份数据 · 两种写法 · 后果当场对照)

同一个过滤条件、同一个 Top-K,WHERE 放在 KNN 前还是后,拿到的是两批完全不同的点。左边是最常见的直觉写法(WHERE 前置)—— 官方口径说它用不上向量索引;右边是官方推荐的姿势(子查询先 KNN、外层再过滤)—— 代价是过滤后条数可能少于 LIMIT。两种写法各自返回什么,下面当场算、并排画。

姿势 1 · WHERE 前置(直觉写法)
SELECT id FROM t
WHERE tag = 'A'
ORDER BY VEC_L2_DISTANCE(embedding, ?)
LIMIT 5;

正在算…

官方口径:包含预过滤的查询无法利用向量索引(WHERE 在 KNN 之前执行)—— 上面的数字就是它的语义后果。

姿势 2 · 先 KNN 再过滤(官方推荐)
SELECT * FROM (
  SELECT id, tag FROM t
  ORDER BY VEC_L2_DISTANCE(embedding, ?)
  LIMIT 5
) WHERE tag = 'A';

正在算…

官方口径:过滤会减少条数,但不改变「全库最近」的定义 —— 看下面的数字。

过滤标签
每个点固定分到 A / B / C / D 四类之一(固定种子推导,可复算)

正在算…

反例台 ② · 红线检查器(四条任缺一条,EXPLAIN 里就没有 annIndex:)

点右列的「破坏」按钮,把某一条前提弄坏 —— 判定当场重算。四条全部满足,查询才走得到向量索引上;坏掉的条数与原因写在下面的判定区里,每条都挂着出处。

①距离函数与索引一致(须与索引一致)
②查询里指定了 Top K
③没有用 DESC 排序
④没有 WHERE 预过滤
正在判定…
建表 · 官方文档原文(含向量索引)
CREATE TABLE foo (id INT PRIMARY KEY, embedding VECTOR(5), VECTOR INDEX idx_embedding ((VEC_COSINE_DISTANCE(embedding))));
CREATE VECTOR INDEX idx_embedding ON foo ((VEC_COSINE_DISTANCE(embedding))) USING HNSW;

逐字说明:上面两行是官方文档的原文写法 —— 建表时内联定义,或事后单独建索引。VECTOR(5) 里的 5 是固定维度:向量数据类型为 TiDB 特有(MySQL 不支持),VECTOR 表示任意维度、VECTOR(D) 表示固定维度 D;而索引只能建在定长向量列上 —— 点开这条卡,能看到向量索引的整份限制清单。

索引不是秒建的 · 怎么知道建完了

构建进度可以查出来:SELECT * FROM INFORMATION_SCHEMA.TIFLASH_INDEXES,当 ROWS_STABLE_NOT_INDEXED 为 0 时构建完成。官方给出的参考量级:对 500 MiB、768 维的向量数据集建索引,可能需要长达 20 分钟。另有一处容易忽略:Delta 层始终不会被索引 —— 需要时用 ALTER TABLE <T> COMPACT; 强制合并。

本节口径与边界声明(技术解读准确性依据)
  • 版本与阶段:TiDB Self-Managed 使用向量搜索需要 v8.4.0 或更高版本(推荐 v8.5.0 或更高),当前处于公测阶段,可能在不事先通知的情况下变更 —— 版本与行为请以官方最新文档为准。
  • 官方未列明角:HNSW 的 M / efConstruction / efSearch 参数 —— 官方文档未列明,也未提供调整入口,因此本页不出现这些参数名;TiFlash 副本的默认数量 —— 官方口径是"部署后默认不会同步任何数据,需按表构建副本",未给出"默认 N 副本",本页同样不写。
  • 本页的边界声明:① 点阵与查询点为固定种子的程序数据(非真机数据);检索为教学级实现:每点连多少个近邻、层 1 如何采样、探索预算取值,均为本站为演示选定,不对应官方实现的内部参数;② 距离值、距离计算次数、召回率均为页面当场计算的真实结果,但三维、低维、小规模的绝对数值不代表任何真实产品性能;③ 本页不承诺任何性能或延迟数值 —— 官方对 ANN 的表述是"准确性仅有轻微下降",召回率的参考口径见取证卡。

口径来源(已核验 · 2026-09-16 · TiDB 官方文档 stable 线 / release-8.5)
· 来源:向量搜索概述、向量数据类型、向量搜索索引(docs.pingcap.com/zh/ai)。

以上带虚线的条目均可点击,查看官方原文、适用版本与文档链接 —— 琥珀色虚线表示「官方未列明,因此本作品一个字都不写」。

系列导航:01 Multi-Raft 日志复制 · 02 Region 分裂与 PD 调度 · 03 分布式事务 2PC · 05 Raft 选举与故障转移 · 06 HTAP 与 TiFlash · 07 在线 DDL

当前路径
暴力扫描 · 全表逐点
计算 → 70 个点,全部比较

每个点都算一次距离,排序取前 5 —— 结果精确,计算量与数据量成正比。

本次查询 · 当场实测
—
距离计算次数
—
算量节省
—
Top-K 召回

跑一次看看 —— 数字是这一秒算出来的。

批量基准 · 30 个查询点(固定种子)
全表扫描
—
HNSW
—

打开即算 —— 30 个固定查询点的平均距离计算次数与平均召回率。

一次 Top-K 查询的旅程
  1. SQL 给出目标向量与距离函数
    距离函数须与索引一致,且查询里要指定 Top K
  2. 优化器判断能不能用索引
    距离函数匹配、指定了 Top K、没有 DESC —— 缺一样就退回全表
  3. 在 TiFlash 上沿图导航
    从入口点逐跳收窄,落到一小撮候选近邻
  4. 候选集比较,返回 Top-K
    结果是近似值:官方口径召回率通常 90% 以上
红线与前提 · 点开看原文

最低版本:v8.4.0+(推荐 v8.5.0+)· 公测阶段

索引算法:仅 HNSW

距离函数:仅余弦 / L2,须与索引一致

前置依赖:必须先部署 TiFlash