# 62.4.索引锁定注意事项
索引访问方法必须通过多个进程处理索引的并发更新。PostgreSQL系统的核心访问共享锁
在索引扫描期间在索引上,以及罗威洛克
更新索引时(包括普通索引)真空
)。由于这些锁类型不冲突,access方法负责处理它可能需要的任何细粒度锁。一访问独占
只有在索引创建、销毁或删除期间,才会对整个索引进行锁定重新索引
(共享更新独占
取而代之的是同时
).
构建支持并发更新的索引类型通常需要对所需行为进行广泛而微妙的分析。对于b-树和散列索引类型,您可以阅读src/backend/access/nbtree/README
和src/backend/access/hash/README
.
除了索引本身的内部一致性要求外,并发更新还会产生有关父表(表)之间一致性的问题堆)还有索引。因为PostgreSQL将堆的访问和更新与索引的访问和更新分开,所以有些窗口中的索引可能与堆不一致。我们使用以下规则处理此问题:
在创建索引项之前,会创建一个新的堆项。(因此,并发索引扫描可能看不到堆条目。这没关系,因为索引读取器无论如何都不会对未提交的行感兴趣。但是请参阅。)第62.5节.)
当要删除堆条目时(通过
真空
),必须首先删除其所有索引项。索引扫描必须在索引页上保留一个pin码,以保存上一次返回的项目
amgettuple
和安布尔克德莱特
无法从被其他后端固定的页面中删除条目。这条规则的必要性解释如下。如果没有第三条规则,索引读取器可能会在索引项被删除之前看到它
真空
,然后在真空
。如果读卡器到达该项目编号时该项目编号仍未使用,则不会产生严重问题,因为空项目槽将被heap_fetch()
.但如果第三个后端已经将项目槽重新用于其他用途,该怎么办?当使用符合MVCC的快照时,没有问题,因为插槽的新占用者肯定太新,无法通过快照测试。但是,使用不符合MVCC的快照(例如快照
),则可以接受并返回实际上与扫描键不匹配的行。我们可以通过要求在所有情况下针对堆行重新检查扫描键来抵御这种情况,但这太昂贵了。相反,我们使用索引页上的pin作为代理,以指示读取器可能仍在从索引项“飞行”到匹配的堆项。制作安布尔克德莱特
在这样一个销上的挡块确保真空
在读取器处理完堆条目之前,无法删除它。这种解决方案在运行时成本很低,并且只在实际存在冲突的少数情况下增加了阻塞开销。这个解决方案要求索引扫描是“同步的”:我们必须在扫描相应的索引项后立即获取每个堆元组。这是昂贵的,原因有很多。在“异步”扫描中,我们从索引中收集许多TID,并且只在稍后某个时间访问堆元组,这需要更少的索引锁定开销,并且可以允许更高效的堆访问模式。根据上述分析,我们必须对不符合MVCC的快照使用同步方法,但对于使用MVCC快照的查询,异步扫描是可行的。
在一个
amgetbitmap
索引扫描时,访问方法不会在任何返回的元组上保留索引pin。因此,只有在符合MVCC的快照中使用此类扫描才是安全的。当
安普雷德洛克
如果未设置标志,则在可序列化事务中使用该索引访问方法的任何扫描都将在完整索引上获取非阻塞谓词锁。这将通过并发可序列化事务向该索引插入任何元组,从而产生读写冲突。如果在一组并发可序列化事务中检测到某些模式的读写冲突,则可能会取消其中一个事务以保护数据完整性。设置该标志时,它表示索引访问方法实现了更细粒度的谓词锁定,这将倾向于减少此类事务取消的频率。