微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Postgres 在非常大的分区表上加入与聚合

如何解决Postgres 在非常大的分区表上加入与聚合

我有一个包含数百万行的大表。因为太大,所以先按日期范围分区,然后那个分区也按一个 period_id 分区。

CREATE TABLE research.ranks
(
    security_id           integer                  NOT NULL,period_id             smallint                 NOT NULL,classificationtype_id smallint                 NOT NULL,dtz                   timestamp with time zone NOT NULL,create_dt             timestamp with time zone NOT NULL DEFAULT Now(),update_dt             timestamp with time zone NOT NULL DEFAULT Now(),rank_1                smallint,rank_2                smallint,rank_3                smallint
)
CREATE TABLE zpart.ranks_y1990 PARTITION OF research.ranks
    FOR VALUES FROM ('1990-01-01 00:00:00+00') TO ('1991-01-01 00:00:00+00')
    PARTITION BY LIST (period_id);

CREATE TABLE zpart.ranks_y1990p1 PARTITION OF zpart.ranks_y1990
    FOR VALUES IN ('1');

每年都有一个分区,每年还有十几个分区。

我需要并排查看不同 period_ids 的 security_ids 结果。

所以我最初使用的连接是这样的:

select          c1.security_id,c1.dtz,c1.rank_2 as rank_2_1,c9.rank_2 as rank_2_9
from            research.ranks c1 
left join      research.ranks c9 on c9.dtz=c9.dtz and c1.security_id=c9.security_id and c9.period_id=9
where           c1.period_id =1 and c1.dtz>Now()-interval'10 years' 

这很慢,但可以接受。我将其称为 JOIN 版本。

然后,我们想再显示两个 period_ids 并扩展上述内容以在新的 period_ids 上添加额外的连接。 这减慢了连接速度,足以让我们考虑不同的解决方案。

我们发现以下类型的查询运行速度大约快 6 或 7 倍:

            select          c1.security_id,sum(case when c1.period_id=1 then c1.rank_2 end) as rank_2_1,sum(case when c1.period_id=9 then c1.rank_2 end) as rank_2_9,sum(case when c1.period_id=11 then c1.rank_2 end) as rank_2_11,sum(case when c1.period_id=14 then c1.rank_2 end) as rank_2_14
            from            research.ranks c1
            where           c1.period_id in (1,11,14,9) and c1.dtz>Now()-interval'10 years'
            group by        c1.security_id,c1.dtz;

我们可以使用总和,因为该表具有唯一索引,所以我们知道永远只会有一条记录被“求和”。我将其称为 SUM 版本。

速度快了很多,我之前写的代码有一半都被质疑了!两个问题:

  1. 我应该尝试在任何地方使用 SUM 版本而不是 JOIN 版本,还是效率可能是特定结构的一个因素,而在其他情况下不太可能有用?

  2. SUM 版本的逻辑有没有我没有考虑的问题?

解决方法

老实说,我认为您的“加入”版本无论如何都不是一个好主意。您只有一个(分区)表,因此永远不需要任何连接。

SUM() 是可行的方法,但我会使用 SUM(...) FILTER(WHERE ..) 而不是 CASE:

SELECT
    security_id,dtz,SUM(rank_2) FILTER (WHERE period_id = 1) AS rank_2_1,SUM(rank_2) FILTER (WHERE period_id = 9) AS rank_2_9,SUM(rank_2) FILTER (WHERE period_id = 11) AS rank_2_11,SUM(rank_2) FILTER (WHERE period_id = 14) AS rank_2_14,FROM
    research.ranks
WHERE
    period_id IN ( 1,11,14,9 ) 
AND dtz > now( ) - INTERVAL '10 years' 
GROUP BY
    security_id,dtz;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?