# 69.1.概述

PostgreSQL包含一个永久性磁盘哈希索引的实现,该索引可以完全崩溃恢复。任何数据类型都可以通过哈希索引进行索引,包括没有明确定义的线性排序的数据类型。散列索引只存储被索引数据的散列值,因此对被索引数据列的大小没有限制。

哈希索引只支持单列索引,不允许唯一性检查。

哈希索引只支持=运算符,因此指定范围操作的WHERE子句将无法利用哈希索引。

每个哈希索引元组只存储4字节的哈希值,而不是实际的列值。因此,当索引较长的数据项(如UUID、URL等)时,哈希索引可能比B树小得多。缺少列值也会使所有哈希索引扫描有损。哈希索引可以参与位图索引扫描和反向扫描。

哈希索引最适合在较大的表上使用相等扫描的选择和更新繁重工作负载。在B-树索引中,搜索必须向下遍历树,直到找到叶页。在有数百万行的表中,这种下降会增加对数据的访问时间。散列索引中相当于叶页的页称为bucket页。相比之下,散列索引允许直接访问bucket页,从而可能减少较大表中的索引访问时间。这种“逻辑I/O”的减少在大于共享的索引/数据上变得更加明显_缓冲区/内存。

散列索引被设计用来处理散列值的不均匀分布。如果散列值均匀分布,那么直接访问bucket页面的工作效果很好。当insert意味着bucket页变满时,额外的溢出页链接到特定的bucket页,本地扩展与该散列值匹配的索引元组的存储。在查询期间扫描哈希桶时,我们需要扫描所有溢出页。因此,就某些数据所需的块访问数量而言,不平衡哈希索引实际上可能比B树更糟糕。

由于存在溢出情况,我们可以说散列索引最适合于唯一、几乎唯一的数据或每个散列桶的行数较少的数据。避免问题的一种可能方法是使用部分索引条件从索引中排除高度非唯一的值,但这在许多情况下可能不适用。

与B-树一样,散列索引执行简单的索引元组删除。这是一个延迟维护操作,用于删除已知可以安全删除的索引元组(其项标识符为LP的索引元组)_死位已设置)。如果insert发现页面上没有可用空间,我们会尝试删除死索引元组,以避免创建新的溢出页面。如果此时页面被固定,则无法删除。真空期间也会删除失效的索引指针。

如果可以的话,VACUUM还将尝试将索引元组压缩到尽可能少的溢出页面上,从而最小化溢出链。如果溢出页变为空,溢出页可以循环使用,以便在其他存储桶中重复使用,尽管我们永远不会将它们返回到操作系统。目前,除了用REINDEX重新构建散列索引外,没有缩减散列索引的规定。也没有减少桶数的规定。

散列索引可能会随着索引行数的增加而扩大存储桶页面的数量。选择哈希键到桶号的映射,以便可以增量扩展索引。当一个新的bucket被添加到索引中时,正好需要“拆分”一个现有bucket,其中的一些元组根据更新的key-to-bucket-number映射被转移到新bucket。

扩展发生在前台,这可能会增加用户插入的执行时间。因此,哈希索引可能不适用于行数快速增加的表。