MySQL (pre 8.0) doesn't have a really convenient way to do this. One method uses variables to enumerate the values:
select m.*,
(@rn := if(@u = userid, @rn + 1,
if(@u := userid, 1, 1)
)
) as seqnum
from (select m.*
from messages m
order by userid, id desc
) m cross join
(select @u := -1, @rn := 0) params;
You can turn this into a delete
using join
:
delete m
from messages m join
(select m.*,
(@rn := if(@u = userid, @rn + 1,
if(@u := userid, 1, 1)
)
) as seqnum
from (select m.*
from messages m
order by userid, id desc
) m cross join
(select @u := -1, @rn := 0) params
) mm
on m.id = mm.id
where seqnum > 30;
As I say in a comment, I don't think this is a good solution for a real-world problem. The history of messages is useful and there are probably other ways to achieve the performance you want. The difference between 30 messages for a user and 70 messages for a user should not have that much of an effect on performance, in a tuned system.