PostgreSQL GIN 索引比 pg_trgm 的 GIST 慢?

Posted

技术标签:

【中文标题】PostgreSQL GIN 索引比 pg_trgm 的 GIST 慢?【英文标题】:PostgreSQL GIN index slower than GIST for pg_trgm? 【发布时间】:2017-03-24 20:14:34 【问题描述】:

尽管所有文档都这么说,我发现 GIN 索引比 pg_trgm 相关搜索的 GIST 索引慢得多。这是在一个包含 2500 万行的表中,文本字段相对较短(平均长度为 21 个字符)。大多数文本行是“123 Main st, City”形式的地址。

GIST 索引搜索大约需要 4 秒

select suggestion from search_suggestions where suggestion % 'seattle';

但使用EXPLAIN ANALYZE 运行时,GIN 需要 90 秒,结果如下:

Bitmap Heap Scan on search_suggestions  (cost=330.09..73514.15 rows=25043 width=22) (actual time=671.606..86318.553 rows=40482 loops=1)
  Recheck Cond: ((suggestion)::text % 'seattle'::text)
  Rows Removed by Index Recheck: 23214341
  Heap Blocks: exact=7625 lossy=223807
  ->  Bitmap Index Scan on tri_suggestions_idx  (cost=0.00..323.83 rows=25043 width=0) (actual time=669.841..669.841 rows=1358175 loops=1)
        Index Cond: ((suggestion)::text % 'seattle'::text)
Planning time: 1.420 ms
Execution time: 86327.246 ms

请注意,索引选择了超过一百万行,尽管实际上只有 40k 行匹配。任何想法为什么这表现如此糟糕?这是在 PostgreSQL 9.4 上。

【问题讨论】:

缺少有关性能问题的一些信息。表定义、表和索引的总大小。 See instructions here. 【参考方案1】:

有些问题很突出:

首先,考虑升级到当前版本的 Postgres。在撰写本文时,这是 pg 9.6 或 pg 10(当前为测试版)。自 Pg 9.4 以来,对 GIN 索引、附加模块 pg_trgm 和大数据进行了多项改进。

接下来,您需要更多的 RAM,尤其是更高的 work_mem 设置。我可以从EXPLAIN 输出中的这一行看出:

Heap Blocks: exact=7625 lossy=223807

“有损”Bitmap Heap Scan 的详细信息中(带有您的特定数字)表示 work_mem 的严重短缺。 Postgres 仅在位图索引扫描中收集块地址而不是行指针,因为使用较低的work_mem 设置(不能在 RAM 中保存确切地址)预计会更快。更多不符合条件的行必须以这种方式在以下位图堆扫描中进行过滤。这个相关的答案有详细信息:

“Recheck Cond:” line in query plans with a bitmap index scan

但是不要把work_mem设置得太高不考虑整体情况:

Optimize simple query using ORDER BY date and text

可能还有其他问题,例如索引或表膨胀或更多配置瓶颈。但是如果你只修复这两个项目,查询应该已经快很多了。

另外,您真的需要检索示例中的所有 40k 行吗?您可能希望在查询中添加一个小的 LIMIT 并使其成为“最近邻”搜索 - 在这种情况下,GiST 索引毕竟是更好的选择,因为 /em> 应该使用 GiST 索引更快。示例:

Best index for similarity function

【讨论】:

非常感谢!机器有足够的内存,所以我会尝试增加 work_mem 设置。最终查询将使用限制,为简单起见,我将其从示例中删除 - 添加它不会更改查询计划(除了明显添加限制)。

以上是关于PostgreSQL GIN 索引比 pg_trgm 的 GIST 慢?的主要内容,如果未能解决你的问题,请参考以下文章

用于比较 JSONB 值的 PostgreSQL 索引

PostgreSQL 未对 JSONB 上的 GIN 索引使用索引扫描

postgresqL 的Btree 与gin索引

PostgreSql jsonb 列上的 GIN 索引未在查询中使用

如何在 postgresql 中使用带有数组列的 GIN 索引?

PostgreSQL - 来自许多表和OR条件的字段的gin索引