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

Я не требую никакого кредита на ответ, потому что я нашел его после некоторого поиска:

то, Что я не знал, - то, что PostgreSQL позволяет, Вы для определения собственных агрегатных функций с СОЗДАЕТЕ АГРЕГАТ

Это сообщение на шоу списка PostgreSQL, как тривиальный это должно создать функцию, чтобы сделать то, что требуется:

CREATE AGGREGATE textcat_all(
  basetype    = text,
  sfunc       = textcat,
  stype       = text,
  initcond    = ''
);

SELECT company_id, textcat_all(employee || ', ')
FROM mytable
GROUP BY company_id;

47
задан blahdiblah 12 October 2012 в 12:51
поделиться

4 ответа

Если вы не хотите изменять свою модель данных, вы можете использовать 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»

48
ответ дан 7 November 2019 в 13:17
поделиться

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

Примерно так:

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

'table2', который вы будете использовать, не та таблица, которую вы упомянули в своем запросе выше, потому что здесь вам нужно список отдельных идентификаторов для хорошей производительности. Поскольку ваши идентификаторы, вероятно, являются FK в другой таблице, используйте эту.

1
ответ дан 7 November 2019 в 13:17
поделиться

это могло бы быть более эффективным. Разница: запрос для таблицы 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 
36
ответ дан 7 November 2019 в 13:17
поделиться

Метод On - создать небольшую производную таблицу, содержащую самое последнее время обновления / вставки в таблице 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
ответ дан 7 November 2019 в 13:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: