【问题标题】:PostgreSql phraseto_tsquery is very slowPostgreSql 短语to_tsquery 很慢
【发布时间】:2019-06-05 18:27:23
【问题描述】:

我使用的是 PostgreSql 9.6

我有一个包含大约 1600 万条记录的数据库表。我有一个 jsonb 列 - logentry - 有一个名为“消息”的字段。它有一个这样创建的 GIN 索引:

CREATE INDEX inettklog_ix_ts_message
    ON public.inettklog USING gin
    (to_tsvector('english'::regconfig, logentry ->> 'message'::text))
    TABLESPACE pg_default;

我想搜索“应用程序名称”。

带有 WHERE 子句的查询

 to_tsvector('english', logentry->>'message') @@ plainto_tsquery('application name') 

在 113 毫秒内执行并返回 7349 行

解释分析:

 WindowAgg  (cost=1812.98..2240.22 rows=95 width=12) (actual time=84.037..84.986 rows=7315 loops=1)
   ->  Bitmap Heap Scan on inettklog  (cost=1812.98..2239.03 rows=95 width=4) (actual time=17.943..81.708 rows=7315 loops=1)
         Recheck Cond: (to_tsvector('english'::regconfig, (logentry ->> 'message'::text)) @@ plainto_tsquery('application name'::text))
         Heap Blocks: exact=7574
         ->  Bitmap Index Scan on inettklog_ix_ts_message  (cost=0.00..1812.96 rows=95 width=0) (actual time=8.542..8.542 rows=8009 loops=1)
               Index Cond: (to_tsvector('english'::regconfig, (logentry ->> 'message'::text)) @@ plainto_tsquery('application name'::text))
 Planning time: 0.387 ms
 Execution time: 85.243 ms

但我不想要“应用程序”和“名称”,我想要“应用程序名称”

但是一个带有 WHERE 子句的查询

 to_tsvector('english', logentry->>'message') @@ phraseto_tsquery('application name') 

运行时间超过 2 分钟!

解释分析:

 WindowAgg  (cost=852.98..1280.22 rows=95 width=12) (actual time=145065.204..145066.127 rows=7314 loops=1)
   ->  Bitmap Heap Scan on inettklog  (cost=852.98..1279.03 rows=95 width=4) (actual time=55.180..145030.148 rows=7314 loops=1)
         Recheck Cond: (to_tsvector('english'::regconfig, (logentry ->> 'message'::text)) @@ phraseto_tsquery('application name'::text))
         Heap Blocks: exact=7573
         ->  Bitmap Index Scan on inettklog_ix_ts_message  (cost=0.00..852.96 rows=95 width=0) (actual time=8.196..8.196 rows=8008 loops=1)
               Index Cond: (to_tsvector('english'::regconfig, (logentry ->> 'message'::text)) @@ phraseto_tsquery('application name'::text))
 Planning time: 25.926 ms
 Execution time: 145067.052 ms

当然,“”运算符的工作原理是首先定位包含“application”和“name”的行,然后过滤结果以找到“name”跟在“application”之后的那些行。

如果是这样,为什么要运行 2 分钟???

【问题讨论】:

  • 能否包含解释分析的输出?
  • @Jeremy 我已将解释分析添加到原始帖子中。计算机今天似乎运行得更快 - 似乎在大约 2.5 分钟而不是 5 分钟内运行

标签: postgresql performance


【解决方案1】:

不幸的是,GIN 索引不支持词位的排序。您的第一个查询要快得多,因为它能够使用您构建的索引处理所有内容。使用短语版本,重新检查必须实际转到您的表并创建 ts_vectors 以查找订单。

您可以使用 RUM 索引:https://github.com/postgrespro/rum,其中包含订购信息。

This 文章在这些方面做了很大的扩展。

【讨论】:

  • RUM 在 9.6 中不存在。
  • 即便如此,也只有 7000 行需要重新创建它们的 tsvector。这不可能超过几秒钟
  • 如果使用 BUFFERS 选项查看 explain 的输出,看看它实际从磁盘读取了多少,这会很有趣。至于 RUM,它是一个扩展,适用于 9.6。
猜你喜欢
  • 2019-08-25
  • 1970-01-01
  • 2013-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-10
  • 2016-01-10
相关资源
最近更新 更多