SevenTnewS

数据库工程

阿里巴巴 Panda Index 赋予 InnoDB 唯一键前所未有的版本历史

Panda Index 将聚簇索引的版本管理下沉到唯一键记录,新增事务列和一条独立的 undo 链。结果是:一个记录锁取代多个间隙锁,仅索引读取不再触碰聚簇索引。目前仍缺少独立的基准测试。

Emmanuel Fabrice Omgbwa Yasse AI 辅助

2026-08-06 · 阅读需 4 分钟

阿里巴巴 Panda Index 赋予 InnoDB 唯一键前所未有的版本历史

唯一键是在线数据库中无声的瓶颈。订单号、手机号和交易流水号都依赖唯一键(UK)索引来保证不重复,而在高并发下,这种约束开始付出代价。在 InnoDB(MySQL 和阿里巴巴 MySQL 兼容版 PolarDB-X 的底层引擎)中,问题出在结构上:二级索引不携带版本信息,因此引擎不得不借助间隙锁和回表来弥补。

阿里巴巴 PolarDB-X 团队发布了一个修复方案。Panda Index 是该引擎数据节点上的新一代 UK 索引,通过事务列和每条记录上独立的 undo 链,为唯一键赋予原生多版本能力。ApsaraDB 团队的技术文章描述了一条更简单的插入路径和真正的仅索引扫描。

InnoDB 唯一键瓶颈

PolarDB-X 是运行在集中式与分布式统一架构之上的分布式数据库,完全兼容 MySQL,每个数据节点拥有一个处理 OLTP 的行存储。InnoDB 聚簇索引以标准方式管理历史:每条记录携带 TRX_ID 和指向 undo 链的 ROLL_PTR,更新就地完成,B+ 树只保留最新版本。二级索引则完全没有这些。UK 记录不携带 TRX_ID、ROLL_PTR,也没有任何版本信息。

因此,唯一键更新采用先标记删除再插入(delete-mark-then-insert)的方式:引擎先将旧记录标记为已删除,再插入新记录。在 purge 线程运行之前,索引上会同时存在多条键值相同的物理记录。这会从两个方面破坏唯一性约束。

第一个问题是加锁。插入冲突检测无法判断共享同一键的多条记录中哪一条是有效的,因此会扫描全部记录,并对整个区间加间隙锁。逻辑上并不冲突的事务最终会互相等待,有时甚至死锁。ApsaraDB 工程师指出,这一问题在交易系统、余额扣减和秒杀场景中尤为严重。

第二个问题是可见性。由于 UK 记录没有版本信息,MVCC 读无法独立判断可见性, , 即使索引覆盖了查询所需的全部列。它必须回到聚簇索引并遍历 undo 链,隐式锁检测和 purge 也是如此。写入密集的工作负载还会带来第三项代价:purge 落后于删除操作,残留的删除标记记录会扩大下一次冲突检查的扫描范围。

Panda Index 内部:四个系统列和一条独立 undo 链

Panda Index 将聚簇索引的版本管理下沉到 UK 索引。每条记录新增四个系统列:TRX_ID,最近一次修改的事务 ID;ROLL_PTR,指向独立 undo 记录的指针;SCN,来自 Lizard 事务系统的提交序列号;以及 UBA,undo 块地址。这些列的语义与聚簇索引记录一致,因此引擎可以复用 Lizard 现有的可见性框架 Vision。

ROLL_PTR 指向一条仅由 UK 索引持有的 undo 链。更新就地完成:不再有先标记删除再插入,每个唯一键只有一条物理记录,历史版本存放在独立的 undo 表空间中,可通过 ROLL_PTR 访问,无需回表。前向 DML、回滚和 purge 各自遵循专门的逻辑,这使 UK 索引的版本生命周期与聚簇索引脱钩。

一个记录锁,取代一排间隙锁

就地更新带来了一个有用的副作用:每个唯一键最多只有一条物理记录。插入冲突检测简化为一次检查。如果记录不存在,插入立即成功;如果存在,引擎在它上面放置一个记录锁,并检查它是否被标记为删除。不再有间隙锁,锁的占用也小得多。

这篇文章包含一个具体的例子。一个事务删除了 c1 = 1 的行,并插入一条相同值的新行;随后第二个事务插入 c1 = 2,这并不冲突。在标准 InnoDB 行为下,第二个插入会超时,索引上持有四个锁,其中三个是间隙锁。在 Panda Index 下,它立即成功,只持有一个 X,REC_NOT_GAP 记录锁。

标准 InnoDB UK 索引Panda Index
每个唯一键的物理记录数删除标记版本不断堆积,直到 purge 执行只有一条,就地更新
插入冲突检查扫描共享该键的所有记录,并加间隙锁锁定整个区间一个记录锁,无间隙锁
可见性检查回表到聚簇索引并遍历 undo 链本地完成,通过 TRX_ID、SCN 和 UBA
c1 = 2 示例的结果插入超时,持有四个锁插入成功,新键只持有一个锁

可见性也得到了同样的简化:一致性读在索引 B+ 树内部完成,覆盖索引查询获得真正的仅索引扫描,隐式锁检测不再触达聚簇索引。

高并发的收益,以及仍然缺失的部分

这一改变让 UK 版本管理与聚簇索引保持一致,而后者正是 InnoDB 已经处理得很好的部分。阿里巴巴发布了邻近数据库索引工作的结果:PolarDB-X 的二级前缀压缩将索引空间削减了 30% 到 70%,在 I/O 压力下 sysbench 吞吐量最高提升 47%;另外,PolarDB 向量索引工程的报告显示,构建和查询速度提升 1.5 到 2 倍,I/O 争用下降 90%。

Panda Index 本身还没有公布任何数据。这篇文章没有包含基准测试,锁表证据也只覆盖了一个手工构造的场景。四个额外的系统列和第二条 undo 链本身会带来存储和 purge 开销,在 UK 密集写入下这些开销能否保持平稳,只有实测才能回答。诚实的总结是:机制看起来是对的,而证据基础来自阿里巴巴自己。

每天早晨用 3 分钟掌握科技要闻

每个工作日一封邮件,只讲真正重要的 AI 与科技动态。