pg_trgm 的 PostgreSQL GIN 索引比 GIST 慢?
PostgreSQL GIN index slower than GIST for pg_trgm?
尽管所有文档都这么说,但我发现 GIN 索引在 pg_trgm 相关搜索中比 GIST 索引慢得多。这是在 2500 万行的 table 上,文本字段相对较短(平均长度为 21 个字符)。大多数文本行都是“123 Main st, City”形式的地址。
GIST 索引大约需要 4 秒,搜索类似
select suggestion from search_suggestions where suggestion % 'seattle';
但是GIN需要90秒,当运行 EXPLAIN ANALYZE
时出现以下结果:
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 上。
一些突出的问题:
首先,考虑升级到 当前版本的 Postgres。在撰写本文时,它是 pg 9.6 或 pg 10(目前是测试版)。自 Pg 9.4 以来,对 GIN 索引、附加模块 pg_trgm 和大数据进行了多项改进。
接下来,您需要更多 RAM,尤其是更高的 work_mem
设置。我可以从 EXPLAIN
输出中的这一行看出:
Heap Blocks: exact=7625 lossy=223807
"lossy" 在 位图堆扫描的详细信息中 (带有您的特定数字)表示work_mem
。 Postgres 仅收集位图索引扫描中的块地址而不是行指针,因为使用低 work_mem
设置(无法在 RAM 中保存确切地址)预计会更快。在下面的Bitmap Heap Scan中必须过滤更多不符合条件的行。此相关答案有详细信息:
但别把work_mem
定得太高不顾全大局:
可能还有其他问题,例如索引或 table 膨胀或更多配置瓶颈。但是,如果您只修复这两项,查询应该 快很多。
此外,您真的需要检索示例中的所有 40k 行吗?您可能想在查询中添加一个小 LIMIT
并使其成为 "nearest-neighbor" 搜索 - 在这种情况下,GiST 索引毕竟是更好的选择,因为that 使用 GiST 索引应该会更快。示例:
尽管所有文档都这么说,但我发现 GIN 索引在 pg_trgm 相关搜索中比 GIST 索引慢得多。这是在 2500 万行的 table 上,文本字段相对较短(平均长度为 21 个字符)。大多数文本行都是“123 Main st, City”形式的地址。
GIST 索引大约需要 4 秒,搜索类似
select suggestion from search_suggestions where suggestion % 'seattle';
但是GIN需要90秒,当运行 EXPLAIN ANALYZE
时出现以下结果:
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 上。
一些突出的问题:
首先,考虑升级到 当前版本的 Postgres。在撰写本文时,它是 pg 9.6 或 pg 10(目前是测试版)。自 Pg 9.4 以来,对 GIN 索引、附加模块 pg_trgm 和大数据进行了多项改进。
接下来,您需要更多 RAM,尤其是更高的 work_mem
设置。我可以从 EXPLAIN
输出中的这一行看出:
Heap Blocks: exact=7625 lossy=223807
"lossy" 在 位图堆扫描的详细信息中 (带有您的特定数字)表示work_mem
。 Postgres 仅收集位图索引扫描中的块地址而不是行指针,因为使用低 work_mem
设置(无法在 RAM 中保存确切地址)预计会更快。在下面的Bitmap Heap Scan中必须过滤更多不符合条件的行。此相关答案有详细信息:
但别把work_mem
定得太高不顾全大局:
可能还有其他问题,例如索引或 table 膨胀或更多配置瓶颈。但是,如果您只修复这两项,查询应该 快很多。
此外,您真的需要检索示例中的所有 40k 行吗?您可能想在查询中添加一个小 LIMIT
并使其成为 "nearest-neighbor" 搜索 - 在这种情况下,GiST 索引毕竟是更好的选择,因为that 使用 GiST 索引应该会更快。示例: