Here's a way to do it without the stage table. I doubt the performance will be better because it sounds like your performance problems have to do with the amount of rows being deleted and the resulting transaction log growth. You probably need to run this or Peter's code (test both for performance) on single users or a range of users at a time so that you get smaller numbers of rows in each transaction.You just need to run the delete query on your data with the second top set to 500 instead of 5.declare @users table (UserId int)declare @messages table (UserId int, MsgDate datetime)insert @users values (1)insert @users values (2)insert @messages values (1, '1/1/2006')insert @messages values (1, '1/2/2006')insert @messages values (1, '1/3/2006')insert @messages values (1, '1/4/2006')insert @messages values (1, '1/5/2006')insert @messages values (1, '1/6/2006')insert @messages values (1, '1/7/2006')insert @messages values (1, '1/8/2006')insert @messages values (1, '1/9/2006')insert @messages values (1, '1/10/2006')insert @messages values (1, '1/11/2006')insert @messages values (2, '2/1/2006')insert @messages values (2, '2/2/2006')insert @messages values (2, '2/3/2006')insert @messages values (2, '2/4/2006')insert @messages values (2, '2/5/2006')insert @messages values (2, '2/6/2006')insert @messages values (2, '2/7/2006')insert @messages values (2, '2/8/2006')insert @messages values (2, '2/9/2006')insert @messages values (2, '2/10/2006')insert @messages values (2, '2/11/2006')--The delete querydelete @messagesfrom @messages mdinner join(select u.UserId, (select top 1 a.MsgDate from (select top 5 m.MsgDate from @messages m where m.UserId = u.UserId order by m.MsgDate desc) a order by a.MsgDate) MsgDatefrom @users u) d on d.UserId = md.UserId and md.MsgDate < d.MsgDate --where md.UserId = 2select * from @messages