60.5. 索引唯一性检查

PostgreSQL 使用* unique index *强制执行 SQL 唯一性约束,这是不允许使用相同键的多个条目的索引。支持此功能的访问方法将amcanunique设置为 true。 (目前,只有 b 树支持它.)

由于存在 MVCC,始终必须允许索引中的重复条目物理存在:这些条目可能引用单个逻辑行的连续版本。我们实际上要强制执行的行为是,任何 MVCC 快照都不能包含具有相等索引键的两行。这分为以下几种情况,在将新行插入唯一索引时必须检查以下情况:

此外,在根据上述规则报告唯一性违规之前,访问方法必须重新检查要插入的行的活动性。如果它被判死刑,则不应报告任何违规行为。 (这种情况在插入由当前事务刚创建的行的普通情况下不会发生.但是,可能在CREATE UNIQUE INDEX CONCURRENTLY期间发生.)

我们需要索引访问方法本身来应用这些测试,这意味着它必须到达堆中才能检查根据索引内容显示为具有重复键的任何行的提交状态。无疑这是丑陋且非模块化的,但它节省了多余的工作:如果我们进行了单独的探测,则在寻找插入新行的索引条目的位置时,实质上将重复对冲突行的索引查找。而且,除非冲突检查是插入新索引条目的组成部分,否则没有明显的方法可以避免出现争用情况。

如果唯一性约束是可延迟的,则将存在额外的复杂性:我们需要能够为新行插入索引条目,但是将任何违反唯一性的错误推迟到语句结束时或更晚。为避免不必要的重复搜索索引,索引访问方法应在初始插入期间进行初步的唯一性检查。如果这表明绝对没有冲突的活动 Tuples,那么我们就完成了。否则,我们计划在应该执行约束时进行一次重新检查。如果在重新检查时插入的 Tuples 和其他具有相同键的 Tuples 都处于活动状态,则必须报告错误。 (请注意,为此,“活动”实际上表示“索引条目的 HOT 链中的任何 Tuples 都是活动的”.)要实现这一点,将为aminsert函数传递一个具有以下值之一的checkUnique参数:

访问方法必须标识任何可能违反唯一约束的行,但是报告误报并不是错误。这样就可以完成检查而无需 await 其他事务完成。此处报告的冲突不会被视为错误,稍后会再次检查,到那时它们可能不再是冲突。

建议在UNIQUE_CHECK_EXISTING调用中,访问方法进一步验证目标行是否确实在索引中具有现有条目,如果没有,则报告错误。这是个好主意,因为传递给aminsert的索引 Tuples 值将被重新计算。如果索引定义涉及的功能并不是 true 不变的,那么我们可能正在检查索引的错误区域。检查是否在重新检查中找到了目标行,从而验证我们是否在扫描与原始插入中使用的相同的 Tuples 值。

上一章 首页 下一章