9.3 9.4 9.5 9.6 10 11 12 13 14 Current(15)
阿里云PostgreSQL 问题报告 纠错本页面

55.5. 索引唯一性检查

PostgreSQL使用唯一索引来强制 SQL 唯一约束,唯一索引实际上是不允许多条记录有相同键值的的索引。 一个支持这个特性的访问方法要设置pg_am.amcanunique为真。(目前,只有 b-tree 支持它。)

因为 MVCC ,必须允许重复的条目物理上存在于索引之中:该条目可能指向某个逻辑行的后面的版本。 实际想强制的行为是,任何 MVCC 快照都不能包含两条相同的索引键字。 这种要求在向一个唯一索引插入新行的时候分解成下面的几种情况:

此外,根据上面的规则报告唯一性违反前,访问方法必须重新检查刚被插入的行是否仍然"活着"。 如果这一行已经因为事务的提交而"死掉了",那么不应当发出任何错误。 (这种情况不可能出现在插入一个由当前事务创建的行的普通场景下。 但是在CREATE UNIQUE INDEX CONCURRENTLY的过程中是可能的。)

我们要求索引访问方法自己进行这些测试,这就意味着它必须检查堆,以便查看那些根据索引内容表明有重复键字的任意行的提交状态。 这样做毫无疑问地很难看并且也不是模块化的,但是这样可以节约重复的工作: 如果我们实施分离的探测,那么,当查找新行的索引项的插入位置时,必须重复对冲突行的索引查找。 并且,没有很显然的方法来避免竞争条件,除非冲突检查是插入新索引项的整体动作的一部分。

如果唯一性约束是可延期的,情况将更加复杂:我们需要能够为新行插入一个新的索引项, 但推迟任何唯一性违反的错误,直到语句结束甚至更晚。 为了避免不必要的重复搜索索引,索引访问方法应该在初始插入时做一个初步的唯一性约束检查。 如果结果明确地显示没有和活着的元组没有冲突,那么事情已经完成了。 否则当需要实施这个约束时,我们需要调度一个再检查。 如果再检查时,被插入的元组和有着相同键的其他元组都还活着,那么必须报告错误。 (为此,"活着"实际上意味着"在该索引项的HOT链上的任何一个元组还活着"。) 为了实现这个,aminsert函数被传入拥有下列某一个值的checkUnique参数:

<
/BODY >