Я использую Postgres 9.4.
Схема messages
имеет следующую схему: сообщения принадлежат feed_id, и имеет posts_at, также сообщения могут иметь родительское сообщение (в случае ответов).
Table "public.messages"
Column | Type | Modifiers
------------------------------+-----------------------------+-----------
message_id | character varying(255) | not null
feed_id | integer |
parent_id | character varying(255) |
posted_at | timestamp without time zone |
share_count | integer |
Indexes:
"messages_pkey" PRIMARY KEY, btree (message_id)
"index_messages_on_feed_id_posted_at" btree (feed_id, posted_at DESC NULLS LAST)
Я хочу вернуть все заказанные сообщения share_count
, но для каждого parent_id
я хочу вернуть только одно сообщение. т. е. если несколько сообщений имеют одинаковое значение parent_id
, posted_at
возвращается только последнее ( ). Значение parent_id
может быть нулевым, все сообщения с нулевым значением parent_id
должны возвращаться.
Запрос, который я использовал:
WITH filtered_messages AS (SELECT *
FROM messages
WHERE feed_id IN (7)
AND (posted_at >= '2015-01-01 04:00:00.000000')
AND (posted_at < '2015-04-28 04:00:00.000000'))
SELECT *
FROM (SELECT DISTINCT ON(COALESCE(parent_id, message_id)) parent_id,
message_id,
posted_at,
share_count
FROM filtered_messages
ORDER BY COALESCE(parent_id, message_id), posted_at DESC NULLS LAST
) messages
ORDER BY share_count DESC NULLS LAST, posted_at DESC NULLS LAST;
Вот http://sqlfiddle.com/#!15/588e5/1/0 , в скрипте SQL я определил схему, точный запрос и ожидаемый результат.
Но производительность запроса замедляется, как только таблица сообщений становится большой. Я пытался добавить несколько индексов сортировки, но он, похоже, не использует индекс. Вот объяснение: http://explain.depesz.com/s/Sv2
Как я могу создать правильный индекс?
feed_id
и , posted_at
и вы не упоминали metadata
вообще, что , как представляется, типа JSON? Пожалуйста, исправьте свой вопрос, чтобы сделать его последовательным. Вы выбираете> 500 тыс. Строк в CTE ... Сколько строк в таблице? Какой процент строк вы обычно выбираете в CTE? Какой процент строк имеет parent_id IS NULL
? Посмотрите информацию в теге [postgresql-performance] для вопросов производительности.
parent_id
? (мин. / ср. / макс.)
metadata
. В настоящее время таблица сообщений содержит 10 мил данных, но быстро увеличивается. Я думаю, чтобы разделить на таблицы разделов для каждого feed_id. Так как я получаю только по идентификатору канала. процентное значение parent_id NULL против NULL составляет около 60% / 40%. типичная выборка составляет около 1-2% таблицы. (около 100K сообщений) Производительность для 100K составляет около 1 с, но когда он достигает 500K +, он использует индекс растрового изображения и обычно занимает 10 с.
ORDER BY
подзапрос совершенно бесполезен. Кроме того, связанный план не может быть результатом опубликованного запроса - например, нет упоминания о немmetadata
.