如何在 postgres 数据库中只获取最大行 version_id 而没有昂贵的子查询?

How to get only rows with max version_id without expensive subquery in postgres database?

我有一个这样的数据table:

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;

因此应忽略所有存在较新版本的行。

问题是,我需要一个非常好的性能,因为数据 table 可以包含例如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
);

这很慢。顺便说一下:对于这个 table:

我有以下唯一索引和 b-tree 索引
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);

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

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

@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;