select
p.ID,
e.NAME
from
Paychecks p
inner join Employee e on p.EmployeeID = e.ID
group by
p.ID
order by
max(p.AmountPaid) desc
Uma maneira diferente de escrever, que parece mais lógica, mas pode ser mais lenta (você teria que testar) é:
select
e.ID,
e.NAME
from
Employee e
inner join Paychecks p on p.EmployeeID = e.ID
group by
e.ID
order by
max(p.AmountPaid) desc
Com dezenas de milhões de linhas, cada consulta está ficando lenta às vezes, mas com os índices adequados, isso é o mais rápido possível. Eu acho que você basicamente precisa de um índice em Paychecks.EmployeeID e Paychecks.AmountPaid combinados. E o índice em Employee.ID pode ajudar.
Se a junção estiver acabando com você, você pode executar duas consultas. O primeiro usa apenas os contracheques para agrupá-los por EmployeeID e ordená-los pelo max(PaycheckAmount), e um segundo pode ser usado para buscar os nomes para cada ID. Às vezes, as uniões custam mais desempenho do que você gostaria e, quando você recebe 10 milhões de contracheques para 500 funcionários, pode ser mais rápido fazê-lo em duas etapas, embora isso signifique que eles trabalham na empresa há cerca de 1600 anos em média .;-)