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?
źródło
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 .feed_id
iposted_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 maparent_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.Odpowiedzi:
Pytanie
W każdym razie to zapytanie powinno być znacznie szybsze:
CTE nie robi tutaj niczego, czego zwykłe podzapytanie nie mogłoby również dostarczyć. CTE wprowadza barierę optymalizacyjną, ponieważ jest wykonywana osobno, a jej wynik jest materializowany.
Masz jeszcze jeden poziom podkwerendy, niż potrzebujesz.
Wyrażenie
(COALESCE(parent_id, message_id)
nie jest kompatybilne ze zwykłym indeksem, potrzebny byłby indeks tego wyrażenia. Ale może to również nie być bardzo przydatne, w zależności od dystrybucji danych. Aby uzyskać szczegółowe informacje, skorzystaj z moich linków poniżej.Podział prostego przypadku
parent_id IS NULL
na osobnySELECT
może, ale nie musi, zapewnić optymalnego. Zwłaszcza nie, jeśli i tak jest to rzadki przypadek, w którym to przypadku zapytanie łączone z indeksem(COALESCE(parent_id, message_id)
może działać lepiej. Obowiązują inne uwagi ...Wskaźniki
Zwłaszcza gdy są obsługiwane tymi indeksami:
Dwa częściowe indeksy pokrywają razem całą tabelę i są mniej więcej tego samego rozmiaru, co pojedynczy indeks całkowity.
Dwie ostatnie kolumny
parent_id, message_id
mają sens tylko wtedy, gdy wykonasz z nich skany tylko z indeksu . W przeciwnym razie usuń je z obu indeksów.SQL Fiddle.
W zależności od brakujących szczegółów
DISTINCT ON
może być najlepsza technika zapytań do tego celu. Przeczytaj szczegółowe wyjaśnienie tutaj:I być może szybsze alternatywy tutaj:
źródło