Você provavelmente não quer ouvir isso, mas a melhor opção para acelerar SELECT DISTINCT é evitar DISTINCT começar. Em muitos casos (nem todos!), Isso pode ser evitado com um melhor design do banco de dados ou com melhores consultas.
Às vezes, GROUP BYé mais rápido, porque leva um caminho de código diferente.
No seu caso particular , não parece que você possa se livrar deDISTINCT . Mas você pode dar suporte à consulta com um índice especializado se tiver muitas consultas desse tipo:
CREATE INDEX foo ON events (project_id, "time", user_id);
A adição user_idé útil apenas se você conseguir verificações somente de índice . Siga o link para detalhes. Removeria o caro verificação de heap de bitmap do seu plano de consulta, que consome 90% do tempo da consulta.
Sua EXPLAINsaída me diz que a consulta precisa condensar 2.491 usuários distintos em meio milhão de linhas correspondentes. Isso não se tornará super-rápido, não importa o que você faça, mas pode ser substancialmente mais rápido.
Se os intervalos de tempo em suas consultas forem sempre os mesmos, uma MATERIALIIZED VIEWdobra user_idpor(project_id, <fixed time intervall>) percorrerá um longo caminho. Não há nenhuma chance com intervalos de tempo variados. Talvez você possa pelo menos dobrar os usuários por hora ou alguma outra unidade de tempo mínima, e isso compraria desempenho suficiente para garantir a sobrecarga considerável.
Nitpick:
Muito provavelmente, os predicados "time"devem realmente ser:
AND "time" >= '2015-01-11 8:00:00'
AND "time" < '2015-02-10 8:00:00';
Lado:
Não use timecomo identificador. É uma palavra reservada no SQL padrão e um tipo básico no Postgres.