Как получить только строки с max version_id без дорогостоящего подзапроса в базе данных postgres? - PullRequest
0 голосов
/ 24 августа 2018

У меня есть такая таблица данных:

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

Теперь мне нужен запрос с хорошей производительностью, который извлекает все строки данных с наибольшим значением 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 строк (они разделены на задний план - думаю, это не относится к моему вопросу).

Простое решение моей проблемы - проверить для каждой строки в подзапросе, является ли она строкой с наибольшим номером версии:

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 голосов
/ 24 августа 2018

Ответ DISTINCT ON от @a_horse - это путь, если вы действительно хотите получить только одну запись от каждой даты и сеанса. Но, предполагая, что могут быть связи, вы можете ранжировать аналитическую функцию здесь:

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;
0 голосов
/ 24 августа 2018

(где n = 1) запросы, как правило, лучше всего делать с использованием distinct on ():

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