PostgreSQL 的索引并不直接指向页面中的项,而是指向的是页面中的项指针。
PostgreSQL 的索引只会增加,不会删除,因此索引页面不需要版本化。 在这种情况下,索引存有所有版本的元组。和扫描整表一样通过元组自身的元数据来判断元组的有效性。
索引在 页剪枝 时不会更新。
优化:
B-Tree
PostgreSQL 中最常见的一种索引引擎就是 B-tree,其内部以 B+ tree 为基础,但有一些改动。
B+ tree 中的一个节点在 PostgreSQL 中固定为一个 page,并根据 key 的大小确定 B+ tree 的 K 值。
当插入操作即将使节点一分为二时,会先尝试索引剪枝,重用当前节点内的空间。
首先,PostgreSQL 会删除节点内被标记为 dead 的元组。在页剪枝中,如果项指针指向一个在任何快照中均不再可见或根本不存在的元组,便会在项指针上设置这样的标记。
如果没有元组已知是 dead 的状态,PostgreSQL 会检查对同一个表行的不同版本的索引条目是否已经消失在数据库视界之外。这些元组通常由 UPDATE 产生,虽然尚未标记为 dead 但因为事务完成可能已经可以剪枝。
如果索引剪枝之后仍然没有足够的空间插入新索引,PostgreSQL 会根据 B+ tree 的规则分裂当前节点。
PostgreSQL 不会删除 B+ tree 中的节点。即使在插入已满节点或 VACUUM FULL 执行的索引剪枝将节点元素数量减少至 以下,PostgreSQL 也不会按照 B+ tree 的规则尝试合并节点。
因此在某些场景下,索引中可能会有较多的空洞导致体积膨胀甚至树不再平衡。 HOT更新能够减少元组更新插入的新索引以减缓索引膨胀,但最坏情况仍然可能发生。
如果统计数据指示索引确实发生了这种现象,可以考虑重建索引。