Você pode tentar isso - não vou garantir que ele tenha um desempenho melhor, mas é minha maneira usual de correlacionar uma linha com uma linha "anterior":
SELECT
* --TODO, list columns
FROM
data d
left join
data d_prev
on
d_prev.time < d.time --TODO - Other key columns?
left join
data d_inter
on
d_inter.time < d.time and
d_prev.time < d_inter.time --TODO - Other key columns?
WHERE
d_inter.time is null AND
(d_prev.value is null OR d_prev.value <> d.value)
(Acho que está certo - poderia fazer com alguns dados de amostra para validá-lo).
Basicamente, a ideia é juntar a tabela a ela mesma, e para cada linha (em
d
), encontre linhas candidatas (em d_prev
) para a linha "anterior". Em seguida, faça mais uma junção, para tentar encontrar uma linha (em d_inter
) que existe entre a linha atual (em d
) e a linha candidata (em d_prev
). Se não conseguirmos encontrar tal linha (d_inter.time is null
), então esse candidato era de fato a linha anterior.