Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17 / 18

63.5. 索引唯一性检查 #

PostgreSQL 使用唯一索引来强制执行 SQL 唯一性约束;所谓唯一索引,就是不允许存在多个具有相同键值条目的索引。支持这一特性的访问方法会把 amcanunique 设为真。(目前只有 B-树支持这一点。)在强制唯一性时,不会考虑 INCLUDE 子句中列出的列。

由于 MVCC 的存在,索引中在物理上总是必须允许存在重复条目:这些条目可能指向同一个逻辑行的连续版本。我们真正想强制的行为是,任何 MVCC 快照都不能同时包含两行拥有相同索引键的记录。在向唯一索引插入一行新数据时,必须检查以下几种情况:

此外,在按照上述规则报告唯一性违背之前,访问方法必须立即重新检查正在插入那一行的存活性。如果它已经是提交后死亡的状态,就不应报告违背。(这种情况不会出现在插入由当前事务刚创建的行这一普通场景中,但在 CREATE UNIQUE INDEX CONCURRENTLY 期间却可能发生。)

我们要求索引访问方法自行应用这些测试,这意味着它必须深入堆中检查那些根据索引内容显示为具有重复键的行的提交状态。毫无疑问,这样做既丑陋又不够模块化,但它避免了重复工作:如果我们单独再做一次探测,那么在寻找新行索引条目插入位置时,查找冲突行的索引搜索实际上就会被重复执行。更何况,除非把冲突检查作为插入新索引条目动作的一个组成部分,否则也没有明显的方法可以避免竞争条件。

如果唯一约束是可延迟的,情况会更复杂:我们需要能够为新行插入一个索引条目,但把任何唯一性违背错误延迟到语句结束时甚至更晚才报告。为了避免对索引进行不必要的重复搜索,索引访问方法应在初始插入期间执行一次初步唯一性检查。如果这表明确实不存在冲突的存活元组,那么事情就结束了。否则,我们会安排在真正强制约束时再做一次重检。若在重检时,插入的元组与另外某个具有相同键值的元组都仍然存活,就必须报告错误。(注意,就此用途而言,存活实际上是指索引条目 HOT 链中的任一元组是存活的。)为实现这一点,传给 aminsert 函数的 checkUnique 参数会取以下值之一: