云服务器上Postgres全文搜索的进一步优化

Posted

技术标签:

【中文标题】云服务器上Postgres全文搜索的进一步优化【英文标题】:Futher optimization of Postgres Full-text search on a Cloud Server 【发布时间】:2013-05-15 16:48:00 【问题描述】:

我在云服务器上运行 Postgres 9.1(我知道这远非理想,我们希望在今年的某个时候进行迁移)。该服务器经常对超过 300 万条记录的表执行全文查询。这是一个典型查询的示例。

SELECT id 
FROM Table 
WHERE datepublished BETWEEN $$2012-05-01 00:00:00$$ AND $$2013-05-15 23:59:59$$ 
  AND hide = false 
  AND ( tsvall @@ to_tsquery('query')) 
ORDER BY datepublished DESC

datepublished、hide 和 tsvall 列都已编入索引,tsvall 使用 GIN 编入索引。 postgres 配置设置 shared_buffers、effective_cache_size、work_mem 也进行了调整。

对于一个典型的查询(使用的查询文本是“august”),使用上面示例中的参数返回 986 行需要 5 秒。我真的很想加快速度。非常感谢您的帮助,我可以根据要求提供额外的信息。

--编辑:解释分析结果

 Sort  (cost=15352.87..15355.18 rows=927 width=16) (actual time=17705.293..17706.266 rows=849 loops=1)
   Sort Key: datepublished
   Sort Method:  quicksort  Memory: 64kB
   ->  Bitmap Heap Scan on post  (cost=1049.44..15307.18 rows=927 width=16) (actual time=63.520..17702.219 rows=849 loops=1)
         Recheck Cond: (tsvall @@ to_tsquery('trialing'::text))
         Filter: ((at IS NULL) AND (NOT hide) AND (datepublished >= '2012-05-04 00:00:00'::timestamp without time zone) AND (datepublished <= '2013-06-04 23:59:59'::timestamp without time zone))
         ->  Bitmap Index Scan on index_tsvall  (cost=0.00..1049.20 rows=3758 width=0) (actual time=62.537..62.537 rows=4814 loops=1)
               Index Cond: (tsvall @@ to_tsquery('trialing'::text))
 Total runtime: 17707.280 ms

这里是 cmets http://explain.depesz.com/s/QDAb中要求的链接

--编辑2

我意识到我的 datepublished 索引没有排序,因此我在按 DESC 排序的列上创建了一个(btree)索引。这是我现在得到的 EXPLAIN ANALYZE 输出示例

   ->  Bitmap Heap Scan on post  (cost=65485.44..82297.13 rows=4441 width=16) (actual time=1397.734..7775.204 rows=3161 loops=1)
         Recheck Cond: ((tsvall @@ to_tsquery('debate'::text)) AND (datepublished >= '2013-04-01 00:00:00'::timestamp without time zone) AND (datepublished <= '2013-06-04 23:59:59'::timestamp without time zone) AND (at IS NULL))
         Filter: (NOT hide)
         ->  BitmapAnd  (cost=65485.44..65485.44 rows=4456 width=0) (actual time=1396.544..1396.544 rows=0 loops=1)
               ->  Bitmap Index Scan on index_tsvall  (cost=0.00..13526.88 rows=67979 width=0) (actual time=531.941..531.941 rows=71502 loops=1)
                     Index Cond: (tsvall @@ to_tsquery('debate'::text))
               ->  Bitmap Index Scan on datepublished_index  (cost=0.00..23142.92 rows=1103417 width=0) (actual time=382.808..382.808 rows=1164707 loops=1)
                     Index Cond: ((datepublished >= '2013-04-01 00:00:00'::timestamp without time zone) AND (datepublished <= '2013-06-04 23:59:59'::timestamp without time zone))
               ->  Bitmap Index Scan on index_at  (cost=0.00..28811.80 rows=1253179 width=0) (actual time=422.077..422.077 rows=1319617 loops=1)
                     Index Cond: (at IS NULL)

这里又是请求的链接http://explain.depesz.com/s/Ksss

标记

【问题讨论】:

运行analyze table,然后运行explain analyze this-query。将结果粘贴到您的问题中。 ... 并记住代码缩进解释分析;格式很重要。最好是粘贴到explain.depesz.com 并在此处链接。如果您的服务器版本支持,请使用explain (buffers, analyze) ... 。请参阅postgresql-performance 上的信息标签。 @CraigRinger 我已添加它们 - 抱歉耽搁了这么久! 【参考方案1】:

您的统计数据估计是合理的,而且这是一个非常简单的查询计划。这本身就是问题的一部分。

(非常)昂贵的节点是位图堆扫描:

Bitmap Heap Scan on post (cost=1049.44..15307.18 rows=927 width=16) (actual time=63.520..17702.219 rows=849 loops=1)
  Recheck Cond: (tsvall @@ to_tsquery('trialing'::text))
  Filter: ((at IS NULL) AND (NOT hide) AND (datepublished >= '2012-05-04 00:00:00'::timestamp without time zone) AND (datepublished <= '2013-06-04 23:59:59'::timestamp without time zone))

看到大而复杂的过滤子句了吗?这有点奇怪,因为这意味着 Pg 没有使用任何其他索引来满足这些条件。

减少random_page_cost 是否会导致 Pg 使用任何其他索引?

在最坏的情况下,您可能能够使用显式 CTE 来强制 Pg 先执行其他过滤器,然后将 tsquery 应用于结果。这需要一些具体化,所以它并不理想,例如:

WITH prefiltered AS (
  SELECT id, tsvall, datepublished
  FROM Table 
  WHERE datepublished BETWEEN '2012-05-01 00:00:00' AND '2013-05-15 23:59:59' 
    AND hide = false 
)
SELECT
FROM prefiltered
WHERE tsvall @@ to_tsquery('query')
ORDER BY datepublished DESC;

或者,正如 Denis 明智地指出的那样,尝试创建一个复合 btree-gist 索引,例如:

CREATE INDEX posts_blah ON posts USING gist(datepublished, tsvall) WHERE (hide = false);

...虽然这个索引的更大尺寸和它的更新成本可能是一个问题。

【讨论】:

感谢您的分析,Postgre 在云服务器上运行这一事实对 random_page_cost 是否重要?【参考方案2】:

它可能会忽略 tsvall 上的索引,因为它的选择性低于 datepublished 上的索引。

如果是这样,请尝试在 (tsvall, datepublished) 上添加 GIN 或 GIST 索引。

您可能需要根据需要安装 btree_gin 或 btree_gist 扩展:

http://www.postgresql.org/docs/9.2/static/btree-gin.html http://www.postgresql.org/docs/9.2/static/btree-gist.html

之后请务必analyze您的餐桌。

【讨论】:

我目前在 tsvall 上使用 GIN 索引。添加 btree_gin(tsvall,datepublished) 索引时,我看到性能下降。但是,我确实看到使用 btree_gist 索引(tsvall,datepublished)的搜索性能有所提高 - 我不明白,因为通常我知道 GIN 索引具有更快的读取时间。这可能与每个索引条目的词位数量有关吗? Tsvall 总共有超过 100 000 个独特的词位。但是,这些测试仅在我的开发笔记本电脑上进行,而不是在我们的生产服务器上

以上是关于云服务器上Postgres全文搜索的进一步优化的主要内容,如果未能解决你的问题,请参考以下文章

数组列上的 Postgres 全文搜索

腾讯云免费试用,领鸟云服申请通道

智慧杆系统采用自建服务器还是云服器

智慧杆系统采用自建服务器还是云服器

Qt客户端阿里云服上传文件

利用solr实现商品的搜索功能