选择*比JSONB字段查找Postgres快

时间:2018-02-01 21:45:58

标签: postgresql

使用Postgres 9.5.3,我有一个包含~10k文本文档的表。其中一个字段content是JSONB,其条目看起来像这样:

{'title' : 'Short Document Title', 'text' : 'Some loooooong text......'}

一个简单的select *和sort查询工作正常:

EXPLAIN ANALYZE
SELECT *
FROM documents
ORDER BY date DESC LIMIT 25;

    Limit  (cost=2224.60..2224.67 rows=25 width=1393) (actual time=30.733..30.741 rows=25 loops=1)
       ->  Sort  (cost=2224.60..2246.16 rows=8624 width=1393) (actual time=30.731..30.733 rows=25 loops=1)
             Sort Key: release_date DESC
             Sort Method: top-N heapsort  Memory: 65kB
             ->  Seq Scan on document  (cost=0.00..1981.24 rows=8624 width=1393) (actual time=0.025..26.463 rows=8624 loops=1)
     Planning time: 0.388 ms
     Execution time: 30.840 ms

但是,使用单个JSONB字段查找,执行时间增加超过30x:

EXPLAIN ANALYZE
SELECT content->'title'
FROM documents
ORDER BY date DESC LIMIT 25;

Limit  (cost=2246.16..2246.23 rows=25 width=59) (actual time=972.382..972.389 rows=25 loops=1)
   ->  Sort  (cost=2246.16..2267.72 rows=8624 width=59) (actual time=972.380..972.382 rows=25 loops=1)
         Sort Key: release_date DESC
         Sort Method: top-N heapsort  Memory: 28kB
         ->  Seq Scan on document  (cost=0.00..2002.80 rows=8624 width=59) (actual time=0.582..964.898 rows=8624 loops=1)
 Planning time: 0.114 ms
 Execution time: 972.434 ms

为什么第二个查询要慢得多/应该采取哪些措施来提高性能(最好不要更改架构)?

更新:我已从9.5.3>升级10.1期望看到更好的表现。事实上,10.1上的表现相当糟糕:

EXPLAIN ANALYZE
SELECT content->'title'
FROM documents
ORDER BY date DESC LIMIT 25;

 Limit  (cost=2009.16..2009.23 rows=25 width=36) (actual time=1011.282..1011.288 rows=25 loops=1)
   ->  Sort  (cost=2009.16..2030.72 rows=8624 width=36) (actual time=1011.281..1011.285 rows=25 loops=1)
         Sort Key: release_date DESC
         Sort Method: top-N heapsort  Memory: 30kB
         ->  Seq Scan on documents  (cost=0.00..1765.80 rows=8624 width=36) (actual time=0.157..1005.157 rows=8624 loops=1)
 Planning time: 0.090 ms
 Execution time: 1011.315 ms

1 个答案:

答案 0 :(得分:2)

我认为这是因为您使用的是早于9.6的PostgreSQL版本。

9.6 release notes中,您可以看到相关条目:

  
      
  • 在适当的情况下,将SELECT输出表达式的评估推迟到ORDER BY排序后(Konstantin Knizhnik)

         

    此更改可确保输出列表中的易失性或昂贵函数按ORDER BY建议的顺序执行,并且当存在LIMIT子句时,它们的评估次数不会超过要求。以前,如果排序是通过索引扫描或预合并连接排序执行的,则会保留这些属性,但如果是通过顶级排序执行排序则不会。

  •   

jsonb值不存储在主表中,而是存储在属于它的 TOAST中。如果访问该值,则必须将其“解除”,即从TOAST表加载并解压缩。

在您的第一个查询中,这只发生在返回给客户端的25行中,但在第二个查询中,所有8624 jsonb值都被解除了。