我有一个名为 Controllers 的表,其中记录了一些具有唯一 IMEI 号码的设备。
田野 | 类型 | 空 | 钥匙 | 默认 | 额外 |
---|---|---|---|---|---|
id | int | 不 | PRI | 空 | 自动增量 |
设备名称 | varchar(200) | 不 | 空 | ||
设备位置 | 文字 | 不 | 空 | ||
imei_number | varchar(15) | 不 | 空 | ||
电压 | 十进制(10,2) | 不 | 0.00 | ||
当前 | 十进制(10,2) | 不 | 0.00 | ||
温度 | 十进制(10,2) | 不 | 0.00 | ||
故障 | int | 不 | 0 | ||
创建于 | 时间戳 | 不 | 当前_时间戳 | ||
更新于 | 时间戳 | 不 | 当前_时间戳 | 更新 CURRENT_TIMESTAMP 时为 DEFAULT_GENERATED |
我有另一个名为Logs的表,它存储每个设备的日志。每个设备每 10 秒插入一次日志,现在 RMSLogs 表有 1 亿多行
田野 | 类型 | 空 | 钥匙 | 默认 | 额外 |
---|---|---|---|---|---|
id | int | 不 | PRI | 空 | 自动增量 |
imei_number | varchar(15) | 不 | 空 | ||
电压 | 十进制(10,2) | 不 | 0.00 | ||
当前 | 十进制(10,2) | 不 | 0.00 | ||
温度 | 十进制(10,2) | 不 | 0.00 | ||
故障 | 小小 | 不 | 0 | ||
创建于 | 时间戳 | 不 | 当前_时间戳 | ||
更新于 | 时间戳 | 不 | 当前_时间戳 | 更新 CURRENT_TIMESTAMP 时为 DEFAULT_GENERATED |
我想删除与imei_number的时间差小于10分钟的行。
我尝试了以下步骤:
第1步 使用简单的删除查询。
DELETE t1
FROM RMSLogs t1
JOIN RMSLogs t2 ON t1.id = t2.id + 1
WHERE TIMESTAMPDIFF(MINUTE, t2.created_at, t1.created_at) < 10;
当我执行查询时,它影响了大约不超过 8500 行,并且花费了大约 2 分钟。
第2步 使用存储过程。
DELIMITER //
CREATE PROCEDURE DeleteLogsLessThan10Minutes()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE imei_number VARCHAR(255);
DECLARE curr_timestamp DATETIME;
DECLARE previous_timestamp DATETIME;
-- Declare cursor to fetch distinct IMEI numbers from RmsController table
DECLARE cur CURSOR FOR
SELECT imei_number FROM RMSController;
-- Declare continue handler for cursor
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO imei_number;
IF done THEN
LEAVE read_loop;
END IF;
-- Temporary table to hold log entries for the current IMEI number
CREATE TEMPORARY TABLE IF NOT EXISTS Temp_Logs (
created_at DATETIME
);
-- Insert log entries for the current IMEI number into the temporary table
INSERT INTO Temp_Logs (created_at)
SELECT created_at
FROM RMSLog
WHERE imei_number = imei_number
ORDER BY created_at;
-- Initialize variables for timestamp comparison
SET previous_timestamp = NULL;
-- Loop through the log entries for the current IMEI number
WHILE (SELECT COUNT(*) FROM Temp_Logs) > 0 DO
SELECT MIN(created_at) INTO curr_timestamp FROM Temp_Logs;
IF previous_timestamp IS NOT NULL AND TIMESTAMPDIFF(MINUTE, previous_timestamp, curr_timestamp) < 10 THEN
-- Delete the log entry if the time difference is less than 10 minutes
DELETE FROM RMSLog
WHERE imei_number = imei_number AND created_at = curr_timestamp;
END IF;
SET previous_timestamp = curr_timestamp;
-- Remove the processed log entry from the temporary table
DELETE FROM Temp_Logs WHERE created_at = curr_timestamp;
END WHILE;
-- Drop the temporary table
DROP TEMPORARY TABLE IF EXISTS Temp_Logs;
END LOOP;
CLOSE cur;
END //
DELIMITER ;
当我执行此存储过程时,导致超时。
要清除数据,请使用
PRIMARY KEY
以 1000 块为单位浏览表格。对于每 1000 块,删除可以删除的内容。更多:https://mysql.rjweb.org/doc.php/deletebig
对于桌子的其他缩小,
DECIMAL(5,2)
只需 3 个字节。imei_number
可能是 DECIMAL(15,0)
,它需要 7 个字节,而不是 `VARCHAR(...),它需要 17 个字节。location
被重复了很多次。updated_at
吗? (TIMESTAMP
为 5 个字节。)如果您仅保存最后 N 天的数据,请考虑使用 分区 作为删除旧数据的有效方法。