跳到主要内容
版本:下一版

全文搜索推荐索引类型

在全文搜索中,可以使用两类索引来提升搜索性能:GIN 和 GiST。虽然全文搜索本身不强制使用索引,但如果某列经常被用于搜索,通常建议为其创建索引。

可以使用以下语句创建索引:

  • CREATE INDEX <name> ON <table> USING gin(<column>);:基于 GIN(广义倒排索引)的索引。<column> 必须是 tsvector 类型。

  • CREATE INDEX <name> ON <table> USING gist(<column>);:基于 GiST(广义搜索树)的索引。<column> 可以是 tsvectortsquery 类型。

GIN 是全文搜索中最推荐使用的索引类型。作为倒排索引,它为每个词条(lexeme)建立索引项,并记录压缩后的匹配位置列表。在多词搜索中,可以先找出第一个匹配词,再用索引过滤掉不包含其他词的行。GIN 索引仅存储 tsvector 中的词条,不包含权重信息,因此当查询涉及权重标签时,需要回表检查行数据以确认结果。

GiST 索引是有损的,即索引可能返回错误的匹配结果,因此必须检查实际的表数据以剔除这些误匹配(PostgreSQL 会自动执行这一步)。GiST 索引之所以有损,是因为它为每篇文档构建的是固定长度的签名。签名的生成方式是将每个词通过哈希映射到一个 n 位比特串中的某一位,然后将这些位按位 OR 运算合并生成最终签名。如果多个词哈希到同一位,就可能出现误匹配。如果查询中的所有词在索引中都有匹配(无论真假),就必须访问表数据确认匹配是否真实。

GiST 索引支持覆盖索引,可以通过 INCLUDE 子句添加额外的列。被包含的列可以是没有 GiST 操作类的数据类型,这些列会以未压缩形式存储。

由于 GiST 的有损特性,误匹配会导致系统多读取一些实际上不匹配的表记录,增加性能开销。由于随机访问表数据的代价较高,这限制了 GiST 的实际表现。误匹配的可能性受多个因素影响,特别是唯一词条数量,建议使用词典来降低这一数量。

注意,构建 GIN 索引时可以通过提高 maintenance_work_mem 参数来加快构建速度,而 GiST 索引的构建速度对该参数不敏感。

在大数据量场景中,结合表分区与合理使用 GIN 或 GiST 索引,可以实现快速搜索和在线更新。分区可以通过表继承实现,也可以将文档分布在多个服务器上,通过 dblink 汇总搜索结果。这种分布式方式是可行的,因为排序函数只依赖本地信息。