MYSQL中自动删除7天以上行的存储过程

Posted

技术标签:

【中文标题】MYSQL中自动删除7天以上行的存储过程【英文标题】:Stored procedure that Automatically delete rows older than 7 days in MYSQL 【发布时间】:2015-12-07 01:23:44 【问题描述】:

我想知道是否有可能创建一个存储过程,它会在每天 00:00 自动删除超过 7 天的每个表的每一行。

我看到的解决方案很少,但不确定它是否是我正在寻找的,如果有人有任何好的例子,那就太好了。我知道这可以通过 python 和 php 中的简单脚本来完成,但我希望 mysql 更自动化。

任何帮助将不胜感激。

谢谢!

【问题讨论】:

如果这需要从 mysql 级别检查 mysql events 或者如果您想通过应用程序级别代码检查 crontab 来完成,您不需要为自动化任务创建存储过程跨度> 如果您愿意,我们可以将 CREATE EVENT 放在一起作为示例 Drew 的回答有效吗?,您没有接受任何回答? 道歉,是的,那个代码真的很有用:) 【参考方案1】:

Mysql 有它的 EVENT 功能,用于避免复杂的 cron 交互,当您计划的大部分内容与 sql 相关,而与文件相关的较少时。请参阅手册页here。希望以下内容可以作为对重要步骤和要考虑的事项以及可验证测试的快速概述。

show variables where variable_name='event_scheduler';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | OFF   |
+-----------------+-------+

糟糕,事件调度程序未打开。什么都不会触发。

SET GLOBAL event_scheduler = ON; -- turn her on and confirm below

show variables where variable_name='event_scheduler';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | ON    |
+-----------------+-------+

用于测试的架构

create table theMessages
(   id int auto_increment primary key,
    userId int not null,
    message varchar(255) not null,
    updateDt datetime not null,
    key(updateDt)
    -- FK's not shown
);
-- it is currently 2015-09-10 13:12:00
-- truncate table theMessages;
insert theMessages(userId,message,updateDt) values (1,'I need to go now, no followup questions','2015-08-24 11:10:09');
insert theMessages(userId,message,updateDt) values (7,'You always say that ... just hiding','2015-08-29');
insert theMessages(userId,message,updateDt) values (1,'7 day test1','2015-09-03 12:00:00');
insert theMessages(userId,message,updateDt) values (1,'7 day test2','2015-09-03 14:00:00');

创建 2 个事件,每天第一次运行,每 10 分钟运行第二次

忽略他们实际在做什么(互相对抗)。重点在于time difference 方法和调度

DELIMITER $$
CREATE EVENT `delete7DayOldMessages`
  ON SCHEDULE EVERY 1 DAY STARTS '2015-09-01 00:00:00'
  ON COMPLETION PRESERVE
DO BEGIN
   delete from theMessages 
   where datediff(now(),updateDt)>6; -- not terribly exact, yesterday but <24hrs is still 1 day
   -- etc etc all your stuff in here
END;$$
DELIMITER ;

...

DELIMITER $$
CREATE EVENT `Every_10_Minutes_Cleanup`
  ON SCHEDULE EVERY 10 MINUTE STARTS '2015-09-01 00:00:00'
  ON COMPLETION PRESERVE
DO BEGIN
   delete from theMessages 
   where TIMESTAMPDIFF(HOUR, updateDt, now())>168; -- messages over 1 week old (168 hours)
   -- etc etc all your stuff in here
END;$$
DELIMITER ;

显示事件状态(不同的方法)

show events from so_gibberish; -- list all events by schema name (db name)
show events; -- <--------- from workbench / sqlyog
show events\G;` -- <--------- I like this one from mysql> prompt

*************************** 1. row ***************************
                  Db: so_gibberish
                Name: delete7DayOldMessages
             Definer: root@localhost
           Time zone: SYSTEM
                Type: RECURRING
          Execute at: NULL
      Interval value: 1
      Interval field: DAY
              Starts: 2015-09-01 00:00:00
                Ends: NULL
              Status: ENABLED
          Originator: 1
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_general_ci
*************************** 2. row ***************************
                  Db: so_gibberish
                Name: Every_10_Minutes_Cleanup
             Definer: root@localhost
           Time zone: SYSTEM
                Type: RECURRING
          Execute at: NULL
      Interval value: 10
      Interval field: MINUTE
              Starts: 2015-09-01 00:00:00
                Ends: NULL
              Status: ENABLED
          Originator: 1
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_general_ci
2 rows in set (0.06 sec)

要考虑的随机因素

drop event someEventName; --

不能别名 datediff 并在 1 行的 where 子句中使用,所以

select id,DATEDIFF(now(),updateDt) from theMessages where datediff(now(),updateDt)>6;

更准确地说,1 周龄为 168 小时

select id,TIMESTAMPDIFF(HOUR, updateDt, now()) as `difference` FROM theMessages;
+----+------------+
| id | difference |
+----+------------+
|  1 |        410 |
|  2 |        301 |
|  3 |        169 |
|  4 |        167 |
+----+------------+

手册页的链接显示了相当多的间隔选择的灵活性,如下所示:

间隔:

quantity YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
          WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
          DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND

并发

嵌入任何必要的并发措施,以使多个事件(或同一事件的多次触发)不会导致数据异常运行。

一劳永逸

请记住,现在,因为您会忘记它,这些事件会一直触发。所以构建可靠的代码,即使你忘记了,它也会继续运行。你最有可能会的。

您的特殊要求

您需要确定需要首先按表删除哪些行,以便它遵守主键约束。只需通过 CREATE EVENT 语句将它们以适当的顺序集中在明显的区域内,这可能是巨大的。

【讨论】:

哇!谢谢你的例子。我会在这个周末尝试,让你知道是否适合我 :) 但谢谢你的例子。如果顺利的话,我会确认的:)【参考方案2】:

您可以使用下面的存储过程,并通过 crontab 或通过事件来安排它。

注意:只需将 mydb 更改为您的数据库,您要删除哪些数据库表数据并首先在测试环境中进行测试。

DELIMITER $$

USE `mydb`$$

DROP PROCEDURE IF EXISTS `sp_delete`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_delete`()
BEGIN
DECLARE done INT(1) DEFAULT 0;
DECLARE _tbl VARCHAR(100) DEFAULT '';
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=done;

DECLARE cur1 CURSOR FOR SELECT table_name FROM information_schema.tables WHERE table_schema='mydb' AND table_type='base table';
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=done;
OPEN cur1;

REPEAT
FETCH cur1 INTO _tbl;
IF _db = '' THEN
    SET done = 1;
END IF;
            IF (done<>1) THEN

                             SET @str=CONCAT("delete from ",_tbl," where updateon < SUBDATE(CURDATE(),INTERVAL 7 DAY)");
                 PREPARE stmt FROM @str;
                 EXECUTE stmt;
                 DEALLOCATE PREPARE stmt;

            END IF;

UNTIL done
END REPEAT;
     CLOSE cur1;
     SELECT 'done';


END$$

DELIMITER ;

【讨论】:

以上是关于MYSQL中自动删除7天以上行的存储过程的主要内容,如果未能解决你的问题,请参考以下文章

沫沫金原创Bat批处理完成Oracle数据库7天备份自动删除

头大了,Mysql写入数据十几秒后被自动删除了

自动定时备份删除脚本

linux mysql数据库备份 与自动删除30天以前的备份

mysql中使用@变量名:=值 生成的变量如何查看和删除?

为我的模式中的所有表自动生成 DML 存储过程的工具-MySQL