I've two tables , person and person_history to keep versioned records of a person entity.
person table will always have the latest version of the person entity, while person_history table keeps all the versions of the person.
The table person_history is growing exponentially in size as with every update of person, a new record is added to the history table.
The primary key of person table is referenced as person_id
from the person_history table. Column version_num
keeps track of versioning in the history table. With each update, version_num is bumped up by 1.
I wish to keep only 5 records per person_id, and purge the older ones.
For this I've prepared the below statement
DELETE
FROM person_history
WHERE id in (SELECT p0.id
FROM person_history p0
WHERE (
SELECT COUNT(*)
FROM person_history pi
WHERE p0.person_id = p1.person_id AND p0.version_num < p1.version_num
) >= 5);
This statement works, but is very slow and write operations are impacted at that time.
I tried adding order and limit to above condition to delete it in chunks and formed below query
DELETE
FROM person_history
WHERE id in (SELECT p0.id
FROM person_history p0
WHERE (
SELECT COUNT(*)
FROM person_history pi
WHERE p0.person_id = p1.person_id AND p0.version_num < p1.version_num
) >= 5)
ORDER BY p0.id
LIMIT 1000);
This query fails with error This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
I've also tried creating a procedure and but that threw error too
DROP PROCEDURE IF EXISTS purge_history;
DELIMITER $$
CREATE PROCEDURE purge_history()
BEGIN
REPEAT
DO SLEEP(1);
SET @z:= (SELECT p0.id
FROM person_history p0
WHERE (
SELECT COUNT(*)
FROM person_history p1
WHERE p0.person_id = p1.person_id AND p0.version_num < p1.version_num
) >= 5 ORDER BY p0.id LIMIT 1000);
DELETE
FROM person_history
WHERE id in z;
UNTIL ROW_COUNT() = 0 END REPEAT;
END$$
DELIMITER ;
This failed with ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'z; UNTIL ROW_COUNT() = 0 END REPEAT;
I've tried it on MySQL 8 and Mariadb 10.9
Please suggest any alternative to above chunk delete query so that the writes are not impacted while delete is in progress.