在不使用<= join的情况下针对时间序列回填丢失的数据?

时间:2019-06-12 22:45:26

标签: postgresql citus

我有一个大致遵循此模式的表:

Table Name: history
╔════╤══════╤══════════╤═════╤═════════════════════╗
║ id │ stat │ stat_two │ ... │ updated_at          ║
╠════╪══════╪══════════╪═════╪═════════════════════╣
║ 1  │ 100  │ 5        │ ... │ 2019-01-01 12:30 PM ║
╟────┼──────┼──────────┼─────┼─────────────────────╢
║ 1  │ 105  │ 7        │ ... │ 2019-01-02 12:30 PM ║
╟────┼──────┼──────────┼─────┼─────────────────────╢
║ 1  │ 300  │ 10       │ ... │ 2019-02-01 12:30 PM ║
╟────┼──────┼──────────┼─────┼─────────────────────╢
║ 1  │ 700  │ 20       │ ... │ 2019-05-01 12:30 PM ║
╟────┼──────┼──────────┼─────┼─────────────────────╢
║ 2  │ 50   │ 0        │ ... │ 2019-01-01 12:30 PM ║
╟────┼──────┼──────────┼─────┼─────────────────────╢
║ 2  │ 55   │ 0        │ ... │ 2019-01-02 12:30 PM ║
╟────┼──────┼──────────┼─────┼─────────────────────╢
║ 2  │ 75   │ 3        │ ... │ 2019-02-01 12:30 PM ║
╟────┼──────┼──────────┼─────┼─────────────────────╢
║ 2  │ 90   │ 7        │ ... │ 2019-05-01 12:30 PM ║
╚════╧══════╧══════════╧═════╧═════════════════════╝

表很大。

我试图产生以下结果,而过滤仅包括一些IDS(仅像1和2):

╔═════════╤═══════════════════╤═══════════════════════════════════════════════╤═══════════════════════════════════════════════════╗
║ month   │ count_of_ids_seen │ sum_of_(last_seen_stat_for_that_month per ID) │ sum_of_(last_seen_stat_two_for_that_month per ID) ║
╠═════════╪═══════════════════╪═══════════════════════════════════════════════╪═══════════════════════════════════════════════════╣
║ 2019-01 │ 2                 │ 160                                           │ 7                                                 ║
╟─────────┼───────────────────┼───────────────────────────────────────────────┼───────────────────────────────────────────────────╢
║ 2019-02 │ 2                 │ 375                                           │ 13                                                ║
╟─────────┼───────────────────┼───────────────────────────────────────────────┼───────────────────────────────────────────────────╢
║ 2019-03 │ 2                 │ 375                                           │ 13                                                ║
╟─────────┼───────────────────┼───────────────────────────────────────────────┼───────────────────────────────────────────────────╢
║ 2019-04 │ 2                 │ 375                                           │ 13                                                ║
╟─────────┼───────────────────┼───────────────────────────────────────────────┼───────────────────────────────────────────────────╢
║ 2019-05 │ 2                 │ 790                                           │ 27                                                ║
╚═════════╧═══════════════════╧═══════════════════════════════════════════════╧═══════════════════════════════════════════════════╝

我已经尝试了last_value窗口函数,并且可以获取显示的记录,但是问题是,如果记录未出现在表中,则我需要将数据滞后。假设,例如对于第3个月,由于没有记录,我们应该获取该日期之前的最后看到的记录。

我当前的解决方案使用了<=联接,这是瓶颈,当尝试数百万个ID时,它太慢了,无法以我需要的速度运行。

我正在加入一个generate_series,就像这样:

    FROM
        (SELECT month::date FROM generate_series('2018-03-01'::date, '2019-06-01'::date, '1 month') month) d
    LEFT JOIN
        history h
    ON date_trunc('month', h.updated_at) <= d.month

关于如何更有效地执行此操作并删除<=连接的任何想法?这会导致嵌套循环,并导致开销太大。

1 个答案:

答案 0 :(得分:0)

在Citus,我们利用汇总表为实时数据查询创建中间结果。您可以计算每天(或一小时)的汇总,然后使用这些中间值来计算几个月的汇总。

此解决方案不会消除您使用联接的需要,但计算成本会大大降低。

您可以在我们的汇总表用法中查看our docs。即使您不使用Citus分发表格,此处的信息也可以指导您