Reputation: 7693
I have a simple MySQL table like this:
CREATE TABLE `logins` (
`user` int(10) NOT NULL,
`time` int(10) NOT NULL,
`ip` varchar(20) NOT NULL,
PRIMARY KEY (`user`,`time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
With CRON, every 24 hours, I'm performing a cleanup on this table in a way that I keep only unique logins for every users's IP, i.e. if a certain user logins 5 times from IP X, I keep only the latest time he logged in with that IP and delete the remaining 4.
This is my QUERY:
DELETE FROM `logins` WHERE (`user`, `time`) NOT IN(
SELECT `user`, `maxtime`
FROM(
SELECT `user`, MAX(`time`) as `maxtime` FROM `logins` GROUP BY `user`, `ip`
) as `a`
)
This query-subquery way is kind of slow. It takes around 3 seconds to complete.
However, the inner part is extremely quick. If I leave out only the SELECT part, like this:
SELECT `user`, MAX(`time`) as `maxtime` FROM `logins` GROUP BY `user`, `ip`
It takes less than 0.005 seconds.
So I was wondering: what if I did the opposite? Not 'delete all but X', but instead, 'select X, delete all, re-insert X'?
Is this possible?
Something like this:
1) SELECT `user`, MAX(`time`) as `maxtime` FROM `logins` GROUP BY `user`, `ip`
/* store this somewhere temporarily */
2) TRUNCATE TABLE `logins`
3) reinsert data from step 1 to `logins`
Upvotes: 3
Views: 80
Reputation: 49049
I would use this to delete all record except the most recent for every combination of user and ip:
DELETE l1.*
FROM
logins l1 INNER JOIN logins l2
ON l1.user=l2.user
AND l1.ip=l2.ip
AND l1.time<l2.time
Please see fiddle here.
Upvotes: 1
Reputation: 12837
Use another (temporary or not) table to insert the data you want to keep. Truncate. Then insert it back...
INSERT INTO LoginsTemp
SELECT * FROM Logins WHERE ...;
TRUNCATE Logins;
INSERT INTO Logins
SELECT * FROM LoginsTemp;
Upvotes: 2