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

PostgreSQL索引减少了数据大小,但使查询速度变慢,sql,postgresql,indexing,jsonb,Sql,Postgresql,Indexing,Jsonb,我有一个包含7.9GB JSON数据的PostgreSQL表。我的目标是每天对整个表执行聚合,聚合结果稍后将用于Google Data Studio中的分析报告 我尝试运行的查询之一如下所示: explain analyze select tender->>'procurementMethodType' as procurement_method, tender->>'status' as tender_status, sum(cast(ten

我有一个包含7.9GB JSON数据的PostgreSQL表。我的目标是每天对整个表执行聚合,聚合结果稍后将用于Google Data Studio中的分析报告

我尝试运行的查询之一如下所示:

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
)
                                                                  

在这种情况下,执行仅索引扫描的代码有点缺陷。它认为需要在索引中提供“投标书”,以满足
cast(投标书->'value'>>'amount'作为小数)
的需求。它没有意识到索引中的
cast(投标->'value'->>'amount'为十进制)
本身就不需要“投标”本身。因此,它要做一个常规的索引扫描,在扫描过程中,它必须从索引跳转到它将返回的每一行的表中,以找出“tender”,然后计算
cast(tender->“value”->“amount”作为十进制)
。这意味着它在整个表中进行随机io,这比仅仅按顺序读取表然后进行排序要慢得多

您可以在
((投标->>“采购方法类型”)、(投标->>“状态”)、投标上尝试索引
。如果能够构建这个索引,它将是巨大的(与表一样大),但它将不再需要排序


但您当前的查询将在30秒内完成。对于一个每天只运行一次的查询,它真的需要比这个更快吗?

你能在这个问题中包含表定义吗?@TheImpler我已经在问题中包含了表定义。好吧,你正在检索所有行,所以一开始索引是没有帮助的。第二个计划是
索引扫描
,它在索引和表之间来回移动。只有索引的扫描
会让事情变得更快。尝试
真空分析标书
并查看是否提供了仅索引扫描。如果您在Postgres 12上,将这三个值提取到计算列(无索引)中可能也值得一试,因为这样就不需要完全接触JSON值(有效地“规范化”您的模型)@a_horse_和_no_name。我认为你应该把你的评论扩展成一个答案。在
vacuum analyze
postgres之后,他们只是忽略了索引,使用了seq扫描。我是11级博士后,所以我明白我不能做任何事情来加快查询速度。无论如何,非常感谢你的回答。好吧,查询不一定要更快。我只是在做一个概念验证,所以我想知道它是否能更快。顺便说一句,现在我面临另一个问题:我更改了postgresl.conf文件(增加了work_mem、shared_buffers、wal size和最大worker数,还将随机页面成本更改为1.1,因为数据位于SSD上),现在查询不使用并行worker,运行速度更慢,我不知道这是否是一个单独问题的主题