Sto usando Postgres 9.4.
L' messages
ha il seguente schema: i messaggi appartiene alla feed_id, e ha posted_at, anche i messaggi possono avere un messaggio principale (in caso di risposte).
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)
Voglio restituire tutti i messaggi ordinati per share_count
, ma per ciascuno di essi parent_id
voglio restituire un solo messaggio. cioè, se più messaggi hanno lo stesso parent_id
, posted_at
viene restituito solo l'ultimo ( ). La parent_id
può essere nullo, i messaggi con nulla parent_id
dovrebbe tutto il ritorno.
La query che ho usato è:
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;
Ecco il http://sqlfiddle.com/#!15/588e5/1/0 , nel SQL Fiddle, ho definito lo schema, la query esatta e il risultato atteso.
Ma le prestazioni della query sono lente quando la tabella dei messaggi diventa grande. Ho provato ad aggiungere più indici di ordinamento, ma non sembra utilizzare l'indice. Ecco la spiegazione: http://explain.depesz.com/s/Sv2
Come posso creare un indice corretto?
feed_id
e posted_at
e non hai menzionato metadata
affatto, che sembra essere un tipo JSON? Ripara la tua domanda per renderla coerente. Seleziona> 500k righe nel CTE ... Quante righe ci sono nella tabella? Quale percentuale di righe selezioni in genere nel CTE? Qual è la percentuale di righe parent_id IS NULL
? Considera le informazioni nel tag [postgresql-performance] per le domande sulle prestazioni.
parent_id
? (min / avg / max)
metadata
. Attualmente la tabella dei messaggi contiene 10 milioni di dati, ma sta aumentando rapidamente. Penso di separare in tabelle di partizione per ogni feed_id. Dal momento che sto recuperando solo per ID feed. la percentuale di parent_id null vs not null è di circa il 60% / 40%. un tipico recupero è circa l'1-2% della tabella. (circa 100 KB di messaggi) Le prestazioni per 100 KB sono di circa 1 secondo, ma una volta arriva a 500 KB + utilizza l'indice bitmap e normalmente impiega 10 secondi.
ORDER BY
la sottoquery è totalmente inutile. Inoltre, il piano collegato non può essere il risultato della query pubblicatametadata
, ad esempio non viene menzionato .