如何在 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);
greatest-n-per-group(其中 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;
我有一个这样的数据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);
greatest-n-per-group(其中 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;