PostgreSQL(六)—— Hash Indexes

181 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第23天,点击查看活动详情

引言

因为业务上有要存 JSON 数据的需求,项目上使用的数据库是 PostgreSQL,所以用了四篇文章将 PgSQL 关于 JSON 存储的相关说明整理了一下分别为:CharacterJSON TypesJSON Functions and Operatorsjsonpath

存储了数据自然是要考虑对存储的数据添加索引,而我关联的 JSON 数据的索引是之前写文章的介绍过的 Uber/H3 空间索引。我对应在 PgSQL 中的索引类型想要采用哈希索引,所以本篇先对 PgSQL 的哈希索引做一些学习介绍。

Hash Indexes

Hash Index 特点

PostgreSQL hash index 的特点:

  • PostgreSQL hash index 是在磁盘上持久化的,是完全可恢复的
  • 任何数据类型包括没有明确定义的线性排序的都可以被设置为哈希索引
  • 哈希索引仅存储索引数据的哈希值,因此对要索引的数据列的大小没有限制
  • 哈希索引仅支持单列索引,不允许唯一性检查
  • 哈希索引仅支持 = 运算符,因此指定范围运算的 WHERE 子句将无法利用哈希索引
  • 每个哈希索引元组仅存储 4 字节哈希值,而不存储实际的列值。因此,在索引较长的数据项(如 UUID、URL 等)时,哈希索引可能比 B 树小得多。缺少列值也会使所有哈希索引扫描都有损。哈希索引可以参与位图索引扫描和向后扫描

使用场景

哈希索引最适合对较大表使用相等扫描的 SELECT 和 UPDATE 密集型操作。在 B 树索引中,搜索必须在树中下降,直到找到叶子节点的数据页。在包含数百万行的表中,这种下降会增加对数据的访问时间。哈希索引中的叶页面等效项称为存储桶页面。相比之下,哈希索引允许直接访问存储桶页面,从而潜在地减少较大表中的索引访问时间。

为了能达到哈希索引快速查询,给数据列设置哈希索引应该注意:

  • 哈希索引列最适合选择唯一、几乎唯一的数据,这会是索引列的哈希值均匀分布。如果哈希值均匀分布,则直接访问存储桶页面效果很好。当插入意味着存储桶页面已满时,其他溢出页面将链接到该特定存储桶页面,从而在本地扩展与该哈希值匹配的索引元组的存储。在查询期间扫描哈希桶时,我们需要扫描所有溢出页面。因此,对于某些数据,就所需的块访问次数而言,不平衡的哈希索引实际上可能比 B 树更差。
  • 哈希索引可能不适合行数快速增长的表。哈希索引可能会随着索引行数的增长而扩展存储桶页数。选择哈希键到存储桶编号的映射,以便可以增量扩展索引。当要将新存储桶添加到索引时,只需要“拆分”一个现有存储桶,并根据更新的键到存储桶编号映射将其某些元组传输到新存储桶。当索引扩展发生在访问密集的区域时,可能会增加用户插入的执行时间。