O que você precisa é de um "skip scan" ou "loose index scan ". O planejador do PostgreSQL ainda não os implementa automaticamente, mas você pode enganá-lo usando uma consulta recursiva.
WITH RECURSIVE t AS (
SELECT min(eventtype) AS eventtype FROM allevents
UNION ALL
SELECT (SELECT min(eventtype) as eventtype FROM allevents WHERE eventtype > t.eventtype)
FROM t where t.eventtype is not null
)
select eventtype, (select max(eventtime) from allevents where eventtype=t.eventtype) from t;
Pode haver uma maneira de recolher o max (eventtime) na consulta recursiva em vez de fazê-lo fora dessa consulta, mas, se for o caso, não a encontrei.
Isso precisa de um índice em (eventtype, eventtime) para ser eficiente. Você pode fazer com que seja DESC na hora do evento, mas isso não é necessário. Isso é eficiente apenas se eventtype tiver apenas alguns valores distintos (21 deles, no seu caso).