如何在postgres数据库中仅获取具有max version_id的行而没有昂贵的子查询?

时间:2018-08-24 08:55:42

标签: sql postgresql greatest-n-per-group postgresql-9.6

我有一个像这样的数据表:

CREATE TABLE public.data
(
    data_id bigint,
    date timestamp without time zone,
    value double precision,
    sensor_id integer,
    version_id integer
)

现在,我需要一个性能良好的查询,该查询可检索每个sensor_id和日期具有最高version_id的所有数据行。

换句话说,这行:

date='2018-08-24 10:31';value=1337;sensor_id=1;version_id=1;
date='2018-08-24 10:31';value=4;sensor_id=1;version_id=2;
date='2018-08-24 10:32';value=45;sensor_id=1;version_id=1;

应将查询引向该结果数据行:

date='2018-08-24 10:31';value=4;sensor_id=1;version_id=2;
date='2018-08-24 10:32';value=45;sensor_id=1;version_id=1;

因此应该忽略所有具有较新版本的行。

问题是,我需要一个非常好的性能,因为数据表可能包含例如2.000.000.000行(它们在背景中进行了分区-与我猜到的问题无关)。

我的问题的简单解决方案是检查子查询中的每一行是否是具有最高version_number的行:

SELECT * FROM data d1
WHERE d1.version_id= (
    SELECT MAX(d2.version_id) FROM data d2
    WHERE d2.sensor_id = d1.sensor_id AND d2.date = d2.date
);

这非常慢。顺便说一句:该表具有以下唯一索引和b树索引:

CREATE UNIQUE INDEX data_unique_index
    ON public.data USING btree
    (sensor_id, date, version_Id);

CREATE INDEX data_version_id_idx
    ON public.data USING btree
    (version_id);

CREATE INDEX data_date_idx
    ON public.data USING btree
    (date);

CREATE INDEX data_sensor_id_idx
    ON public.data USING btree
    (sensor_id);

CREATE INDEX data_date_sensor_id_idx
    ON public.data USING btree
    (date, sensor_id);

2 个答案:

答案 0 :(得分:3)

(其中n = 1)查询通常最好使用distinct on ()完成:

SELECT distinct on (sensor_id, date) * 
FROM data
order by sensor_id, date, version_id DESC;

答案 1 :(得分:1)

如果您真的想从每个日期和会话中仅获取一条记录,那么@a_horse的DISTINCT ON答案就是解决方法。但是,假设有联系,您可以在此处进行排名分析功能:

SELECT data_id, date, value, sensor_id, version_id
FROM
(
    SELECT *,
        RANK() OVER (PARTITION BY sensor_id, date ORDER BY version_id DESC) rank
    FROM yourTable
) t
WHERE rank = 1;