Używam postgres 9.4.
messages
Ma następujący schemat: Komunikaty należący do feed_id i ma posted_at, również komunikaty mogą mieć wiadomość nadrzędnego (w przypadku odpowiedzi).
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)
Chcę zwrócić wszystkie wiadomości uporządkowane według share_count
, ale dla każdej parent_id
chcę zwrócić tylko jedną wiadomość. tzn. jeśli wiele wiadomości ma to samo parent_id
, posted_at
zwracana jest tylko najnowsza ( ). parent_id
Może być null, null wiadomości parent_id
powinien cały zwrot.
Użyłem zapytania:
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;
Oto http://sqlfiddle.com/#!15/588e5/1/0 , w skrzynce SQL zdefiniowałem schemat, dokładne zapytanie i oczekiwany wynik.
Ale wydajność zapytania jest niska, gdy tabela komunikatów staje się duża. Próbowałem dodać wiele indeksów sortujących, ale wydaje się, że nie używa tego indeksu. Oto wyjaśnienie: http://explain.depesz.com/s/Sv2
Jak mogę utworzyć poprawny indeks?
feed_id
i posted_at
nie wspomniałeś metadata
wcale, który wydaje się być typem JSON? Napraw pytanie, aby było spójne. Wybierasz> 500 tys. Wierszy w CTE ... Ile wierszy znajduje się w tabeli? Jaki procent wierszy zazwyczaj wybierasz w CTE? Jaki procent wierszy ma parent_id IS NULL
? Rozważ informacje w tagu [postgresql-performance] w przypadku pytań dotyczących wydajności.
parent_id
? (min / avg / max)
metadata
. Obecnie tabela komunikatów zawiera 10 milionów danych, ale szybko rośnie. Myślę, że podzielę się na tabele partycji dla każdego feed_id. Ponieważ pobieram tylko identyfikator kanału. Procent Parent_id null vs not null wynosi około 60% / 40%. typowe pobranie stanowi około 1-2% tabeli. (około 100 000 wiadomości) Wydajność dla 100 000 wynosi około 1 s, ale gdy osiągnie 500 000 +, używa indeksu bitmap i zwykle zajmuje 10 sekund.
ORDER BY
podzapytanie jest całkowicie bezużyteczne. Ponadto połączony plan nie może być wynikiem wysłanego zapytania -metadata
na przykład nie ma wzmianki o nim .