Подтвердить что ты не робот

Эффективный последний запрос записи с помощью Postgresql

Мне нужно сделать большой запрос, но мне нужны только последние записи.

Для одной записи я, вероятно, сделаю что-то вроде

SELECT * FROM table WHERE id = ? ORDER BY date DESC LIMIT 1;

Но мне нужно вывести последние записи для большого (тысячи записей) количества записей, но только самую последнюю запись.

Вот что у меня есть. Это не очень эффективно. Мне было интересно, есть ли лучший способ.

SELECT * FROM table a WHERE ID IN $LIST AND date = (SELECT max(date) FROM table b WHERE b.id = a.id);
4b9b3361

Ответ 1

Если вы не хотите изменять свою модель данных, вы можете использовать DISTINCT ON для извлечения самой последней записи из таблицы "b" для каждой записи в "a" :

SELECT DISTINCT ON (a.id) *
FROM a
INNER JOIN b ON a.id=b.id
ORDER BY a.id, b.date DESC

Если вы хотите избежать "сортировки" в запросе, добавление такого индекса может вам помочь, но я не уверен:

CREATE INDEX b_id_date ON b (id, date DESC)

SELECT DISTINCT ON (b.id) *
FROM a
INNER JOIN b ON a.id=b.id
ORDER BY b.id, b.date DESC

В качестве альтернативы, если вы хотите каким-либо образом отсортировать записи из таблицы "a" :

SELECT DISTINCT ON (sort_column, a.id) *
FROM a
INNER JOIN b ON a.id=b.id
ORDER BY sort_column, a.id, b.date DESC

Альтернативные подходы

Тем не менее, все вышеперечисленные запросы по-прежнему нуждаются в чтении всех ссылочных строк из таблицы "b" , поэтому, если у вас много данных, все равно может быть слишком медленным.

Вы можете создать новую таблицу, которая содержит только самую новую запись "b" для каждого a.id - или даже переместить эти столбцы в таблицу "a" .

Ответ 2

это может быть более эффективным. Разница: запрос для таблицы b выполняется только 1 раз, ваш коррелированный подзапрос выполняется для каждой строки:

SELECT * 
FROM table a 
JOIN (SELECT ID, max(date) maxDate
        FROM table
      GROUP BY ID) b
ON a.ID = b.ID AND a.date = b.maxDate
WHERE ID IN $LIST 

Ответ 3

В методе - создайте небольшую таблицу производных, содержащую самое последнее время обновления/вставки в таблице a - вызовите эту таблицу a_latest. Таблица a_latest потребует достаточной детализации для удовлетворения ваших конкретных запросов. В вашем случае должно быть достаточно использовать

CREATE TABLE 
a_latest 
( id INTEGER NOT NULL, 
  date TSTAMP NOT NULL, 
  PRIMARY KEY (id, max_time) );

Затем используйте запрос, аналогичный запросу najmeddine:

SELECT a.* 
FROM TABLE a, TABLE a_latest 
USING ( id, date );

Тогда трюк сохраняет актуальность a_latest. Сделайте это, используя триггер для вставок и обновлений. Триггер, написанный в plppgsql, довольно легко писать. Я рад представить пример, если вы пожелаете.

Дело здесь в том, что расчет самого последнего времени обновления выполняется во время самих обновлений. Это смещает большую часть нагрузки от запроса.

Ответ 4

что вы думаете об этом?

select * from (
   SELECT a.*, row_number() over (partition by a.id order by date desc) r 
   FROM table a where ID IN $LIST 
)
WHERE r=1

Я использовал его много в прошлом

Ответ 5

Если у вас много строк на идентификатор, вам определенно нужен коррелированный подзапрос. Он будет обрабатывать один индекс на один идентификатор, но это быстрее, чем сортировка всей таблицы.

Что-то вроде:

SELECT a.id,
(SELECT max(t.date) FROM table t WHERE t.id = a.id) AS lastdate
FROM table2;

"Таблица2", которую вы будете использовать, - это не та таблица, которую вы упомянули в своем запросе выше, потому что здесь вам нужен список отдельных идентификаторов для хорошей производительности. Так как ваши идентификаторы, вероятно, FKs в другую таблицу, используйте этот.