↑↓ 选择 ↵ 打开 ⌫ 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3
历史版本PostgreSQL 8.3 已于 2013 年 2 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本。

12.9. GiST 和 GIN 索引类型 #

有两种索引可以用来加速全文搜索。 请注意,索引对于全文搜索并非强制要求,但在定期搜索某一列的情况下,通常是可取的。

CREATE INDEX name ON table USING gist(column);

创建基于 GiST(广义搜索树)的索引。 column可以是tsvector类型或tsquery类型。

CREATE INDEX name ON table USING gin(column);

创建基于 GIN(广义倒排索引)的索引。 column必须是tsvector类型。

这两种索引类型之间存在显著的性能差异,因此了解该使用哪一种很重要。

一个 GiST 索引是有损的,这表示索引可能产生假匹配,并且有必要检查真实的表行来消除这种假匹配。PostgreSQL会自动做这一步;例如,在下面的查询计划中,Filter:行就表明索引输出将被重新检查:

EXPLAIN SELECT * FROM apod WHERE textsearch @@ to_tsquery('supernovae');
                               QUERY PLAN
-------------------------------------------------------------------------
 Index Scan using textsearch_gidx on apod  (cost=0.00..12.29 rows=2 width=1469)
   Index Cond: (textsearch @@ '''supernova'''::tsquery)
   Filter: (textsearch @@ '''supernova'''::tsquery)

GiST 索引之所以是有损的,是因为每一个文档在索引中被表示为一个定长的签名。该签名通过将每个词 hash 到一个 n 位串中的一位,再将所有这些位进行 OR 运算来生成,结果是一个 n 位的文档签名。当两个词 hash 到同一个位位置时就会产生假匹配。如果查询中所有词都有匹配(真或假),则必须检索表行查看匹配是否正确。

有损性导致的性能下降归因于不必要的表记录(即被证实为假匹配的记录)获取。因为表记录的随机访问是较慢的,这限制了 GiST 索引的实用性。假匹配的可能性取决于几个因素,特别是不同词的数量,因此推荐使用词典来缩减这个数量。

GIN 索引不是有损的,但其性能以对数方式依赖于不同词的数量。

实际上,GIN 索引只存储tsvector值的词(词位),而不存储它们的权重标签。因此,对于一个不指定权重的查询,GIN 索引可以被认为是非有损的,而对于指定权重的查询则是有损的。这样,在使用涉及权重的查询时就需要进行表行重新检查。遗憾的是,在PostgreSQL当前的设计中,是否需要重新检查是一个特定操作符的静态属性,而不能根据传给该操作符的值来即时启用或禁用。为了在不给不需要重新检查的查询强加重新检查开销的前提下处理这种局面,采用了如下做法:

  • 标准文本匹配操作符@@对 GIN 索引被标记为非有损。

  • 另外提供了一个匹配操作符@@@,它对 GIN 索引被标记为有损。除此之外,该操作符的行为与@@完全一样。

  • 当用@@操作符发起 GIN 索引搜索时,如果查询指定了任何权重,索引支持代码将抛出一个错误。这可以避免因未重新检查权重而给出错误答案。

简而言之,对于涉及权重限制的查询,你必须使用@@@而不是@@来执行 GIN 索引搜索。对于没有权重限制的查询,两个操作符都可以工作,但@@会更快。这种别扭之处也许会在PostgreSQL的将来版本中得到解决。

在选择使用哪种索引类型(GiST 还是 GIN)时,请考虑这些性能差异:

  • GIN 索引的查找大约比 GiST 快三倍

  • GIN 索引的构建大约比 GiST 慢三倍

  • GIN 索引的更新比 GiST 索引慢大约 10 倍

  • GIN 索引比 GiST 索引大两到三倍

根据经验法则,GIN 索引最适合静态数据,因为查找更快。 对于动态数据,GiST 索引的更新更快。具体来说,当不同词(词位)的数量 在 100,000 以下时,GiST 索引对动态数据非常好而且快; 而 GIN 索引能更好地处理 100,000 以上的词位,但更新较慢。

注意GIN索引的构建时间常常可以通过增加maintenance_work_mem来缩短,而GiST索引的构建时间则对该参数不敏感。

对大集合分区并正确使用 GiST 和 GIN 索引可以实现带在线更新的极快搜索。分区可以在数据库层面上使用表继承和constraint_exclusion来完成,或者通过将文档分布在服务器上,并使用contrib/dblink模块收集搜索结果来完成。后一种做法之所以可行,是因为排名函数只使用本地信息。

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。