Probabilmente non vuoi sentirlo, ma l'opzione migliore per accelerare SELECT DISTINCTè evitare DISTINCT di iniziare. In molti casi (non tutti!) Può essere evitato con una migliore progettazione del database o query migliori.
A volte, GROUP BYè più veloce, perché richiede un percorso di codice diverso.
Nel tuo caso particolare , non sembra che tu possa sbarazzartene DISTINCT. Ma potresti supportare la query con un indice specializzato se hai molte query di quel tipo:
CREATE INDEX foo ON events (project_id, "time", user_id);
L'aggiunta user_idè utile solo se si ottengono scansioni solo indice da questo. Segui il link per i dettagli. Rimuoverebbe la costosa scansione di heap di Bitmap dal piano di query, che consuma il 90% del tempo di query.
Il tuo EXPLAINoutput mi dice che la query deve condensare 2.491 utenti distinti su mezzo milione di righe corrispondenti. Questo non diventerà super-veloce, non importa quello che fai, ma può essere sostanzialmente più veloce.
Se gli intervalli di tempo nelle tue query sono sempre gli stessi, un MATERIALIIZED VIEWpieghevole user_idper (project_id, <fixed time intervall>)farebbe molta strada. Nessuna possibilità lì con intervalli di tempo variabili, però. Forse potresti almeno piegare gli utenti all'ora o qualche altra unità di tempo minimo, e questo acquisterebbe prestazioni sufficienti per giustificare il notevole sovraccarico.
Nitpick:
Molto probabilmente, i predicati su "time"dovrebbero essere davvero:
AND "time" >= '2015-01-11 8:00:00'
AND "time" < '2015-02-10 8:00:00';
A parte:
non usare timecome identificatore. È una parola riservata in SQL standard e un tipo di base in Postgres.