postgresql索引减少了数据大小,但使查询速度变慢

y53ybaqx  于 2021-07-29  发布在  Java
关注(0)|答案(1)|浏览(525)

我有一个postgresql表,其中包含7.9gb的json数据。我的目标是每天对整个表执行聚合,聚合结果稍后将用于googledatastudio中的分析报告。
我尝试运行的一个查询如下所示:

explain analyze
select tender->>'procurementMethodType' as procurement_method,
       tender->>'status' as tender_status,
       sum(cast(tender->'value'->>'amount' as decimal)) as total_expected_value
from tenders
group by 1,2

查询计划和执行时间如下:

问题是数据库必须扫描所有7.9gb的数据,即使查询只使用大约100个字段值中的3个字段值。所以我决定创建以下索引:

create index on tenders((tender->>'procurementMethodType'), (tender->>'status'), (cast(tender->'value'->>'amount' as decimal)))

索引的大小是44mb,这比整个表的大小小得多,所以我希望查询应该快得多。但是,在使用创建的索引运行同一查询时,会得到以下结果:

带索引的查询比较慢!这怎么可能?
编辑:表本身包含两列:id列和jsonb数据列:

create table tenders (
   id uuid primary key,
   tender jsonb
)
bjp0bcyl

bjp0bcyl1#

在这种情况下,执行仅索引扫描的代码有些不足。它认为它需要“投标”才能在指数中出现,以满足市场需求 cast(tender->'value'->>'amount' as decimal) . 它没有意识到 cast(tender->'value'->>'amount' as decimal) 指数本身避免了“投标”本身的需要。所以它要做一个常规的索引扫描,在扫描中,它必须从索引跳到表中它将返回的每一行,以找出“tender”,然后进行计算 cast(tender->'value'->>'amount' as decimal) . 这意味着它会在表上跳来跳去做随机io,这比仅仅按顺序读取表然后进行排序要慢得多。
你可以试试索引 ((tender->>'procurementMethodType'), (tender->>'status'), tender) . 如果能够构建这个索引,它将是巨大的(与表一样大),但是它将消除对排序的需要。
但您当前的查询将在30秒内完成。对于一天只运行一次的查询,它真的需要比这个更快吗?

相关问题