受支持版本: 16 / 15 / 14

65.4. 实现 #

在内部,一个 GIN 索引包含一个基于键构建的 B-树索引,其中每个键都是一个或多个被索引项中的某个元素 (例如数组成员),而叶子页中的每个元组要么包含一个指向堆指针 B-树的指针(posting tree), 要么在列表足够小、能够连同键值一起放入单个索引元组时,直接包含一个简单的堆指针列表(posting list)。 Figure 65.1 展示了 GIN 索引的这些组成部分。

PostgreSQL 9.1 开始,索引中可以包含 null 键值。 此外,对于那些自身为 null,或按照 extractValue 的定义不包含任何键的被索引项, 索引中也会包含占位符 null 值。这样一来,应该找到空项的搜索就能够找到它们。

多列 GIN 索引的实现方式,是在组合值(列号,键值)之上构建一个单独的 B-树。 不同列的键值可以具有不同类型。

Figure 65.1. GIN 内部结构


65.4.1. GIN 快速更新技术 #

由于倒排索引的内在性质,更新 GIN 索引往往比较慢:插入或更新一个堆元组, 可能会导致向索引中执行多次插入(从被索引项中提取出的每个键都要插入一次)。 GIN 可以通过把新元组插入一个临时的、未排序的待处理列表, 来推迟其中的大部分工作。当表被清理或自动分析时,或者调用 gin_clean_pending_list 函数时,又或者待处理列表增长到大于 gin_pending_list_limit 时,这些项就会被移入主要的 GIN 数据结构中,所用的是与初始索引创建时相同的批量插入技术。 即便把额外的清理开销计算在内,这也会大幅提高 GIN 索引的更新速度。 此外,这部分开销工作还可以由后台进程完成,而不是在前台查询处理过程中完成。

这种方法的主要缺点是,搜索除了要查找常规索引之外,还必须扫描待处理列表, 因此大型待处理列表会显著拖慢搜索。另一个缺点是,虽然大多数更新都很快, 但一旦某次更新使待处理列表变得过大,就会立刻触发一次清理周期, 因此该次更新会比其他更新慢得多。恰当地使用自动清理可以将这两个问题都尽量减轻。

如果一致的响应时间比更新速度更重要,可以通过关闭 GIN 索引的 fastupdate 存储参数来禁用待处理列表机制。详见 CREATE INDEX

65.4.2. 部分匹配算法 #

GIN 可以支持部分匹配查询。在这种查询中, 查询无法确定一个或多个键的精确匹配,但可能的匹配会落在一个相对狭窄的键值范围内 (该范围位于由 compare 支持方法确定的键排序顺序中)。 extractQuery 方法不是返回一个要精确匹配的键值, 而是返回待搜索范围的下界键值,并将 pmatch 标志设为 true。 随后使用 comparePartial 方法扫描该键范围。 对于匹配的索引键,comparePartial 必须返回零; 对于虽然不匹配但仍处在待搜索范围内的索引键,返回小于零; 如果索引键已经超出了可能匹配的范围,则返回大于零。

提交更正

如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。