在内部,GIN 索引包含一个在键上构建的 B 树索引,其中每个键都是一个或多个索引项的元素(例如,数组的成员),并且叶页中的每个元组都包含指向堆指针的 B 树的指针(“发布树”),或当列表足够小以与键值一起放入单个索引元组时,堆指针的简单列表(“发布列表”)。图 70.1说明了 GIN 索引的这些组件。
从 PostgreSQL 9.1 开始,可以在索引中包含空键值。此外,对于根据 extractValue
为空或不包含任何键的索引项,占位符空值包含在索引中。这允许搜索找到空项。
多列 GIN 索引通过在复合值(列号、键值)上构建单个 B 树来实现。不同列的键值可以是不同的类型。
图 70.1。GIN 内部
更新 GIN 索引往往很慢,因为倒排索引的本质:插入或更新一行堆会导致许多插入索引(每个从索引项中提取的键一个)。GIN 能够通过将新元组插入到待处理条目的临时未排序列表中来推迟大部分工作。当对表进行真空或自动分析时,或者当调用 gin_clean_pending_list
函数时,或者如果待处理列表变大到大于 gin_pending_list_limit,则使用与初始索引创建期间使用的相同批量插入技术将条目移动到主 GIN 数据结构。这极大地提高了 GIN 索引更新速度,即使计算了额外的真空开销。此外,开销工作可以由后台进程完成,而不是在前台查询处理中完成。
此方法的主要缺点在于,除了搜索常规索引之外,搜索还必须扫描待处理条目列表,因此,大量的待处理条目将显著减慢搜索速度。另一个缺点是,虽然大多数更新都很快,但导致待处理列表变得““太大””的更新将立即执行清理周期,因此比其他更新慢得多。正确使用自动清理可以最大程度地减少这两个问题。
如果一致的响应时间比更新速度更重要,则可以通过关闭 GIN 索引的 fastupdate
存储参数来禁用待处理条目的使用。有关详细信息,请参见 CREATE INDEX。
GIN 可以支持““部分匹配””查询,其中查询不会确定一个或多个键的确切匹配,但可能的匹配项落在一个相当窄的键值范围内(在由 compare
支持方法确定的键排序顺序中)。extractQuery
方法不会返回要完全匹配的键值,而是返回作为要搜索的范围的下限的键值,并将 pmatch
标志设置为 true。然后使用 comparePartial
方法扫描键范围。comparePartial
必须对匹配的索引键返回零,对仍处于要搜索的范围内的不匹配返回小于零,或如果索引键超过可能匹配的范围,则返回大于零。