Mysql数据按天分区,定期删除

摘要:
要求:1。日志表需要按天进行分区。2.只保留一个月的数据。方案:1。创建两个事件,一个事件生成将来需要的分区,另一个事件定期检查过期数据(删除分区)。2.每小时创建一次事件,每天删除一次事件。3.在事件开始时,您需要首先创建当前所需的完整分区。方法:1。首先构造存储过程create_partition_Today:将表转换为分区表,并将历史数据收集到分区中,然后按天放置未来数据:#alter

需求:

  1.日志表需要按天分区

  2.只保留一个月数据

方案:

  1.创建两个事件,一个事件生成未来需要的分区,另一个事件定期检查过期数据(移除分区)

  2.创建事件每小时执行一次,删除事件每天执行一次

  3.事件开始时需要先创建一个当前所需分区

全量方法:

  1.先构造存储过程 create_partition_today :将表转化为分区表,并将历史数据归集到该分区,未来数据则按天放置:

#alter table to partition table
DELIMITER $$
USE `dc_log`$$
DROP PROCEDURE IF EXISTS `create_partition_today`$$
CREATE PROCEDURE `create_partition_today`(IN_SCHEMANAME VARCHAR(64), IN_TABLENAME VARCHAR(64))
  BEGIN
    DECLARE BEGINTIME TIMESTAMP;
    DECLARE ENDTIME TIMESTAMP;
    DECLARE DAYS_ENDTIME INT;
    DECLARE PARTITIONNAME VARCHAR(16);
    SET BEGINTIME = NOW();
    SET ENDTIME = BEGINTIME + INTERVAL 1 DAY;
    SET PARTITIONNAME = DATE_FORMAT(BEGINTIME, 'p%Y%m%d');
    SET DAYS_ENDTIME = TO_DAYS(ENDTIME);
    SET @SQL = CONCAT('ALTER TABLE `', IN_SCHEMANAME, '`.`', IN_TABLENAME, '`',
                        ' PARTITION BY RANGE (to_days(create_time))
    (PARTITION ', PARTITIONNAME, ' VALUES LESS THAN (', DAYS_ENDTIME, '))');
    PREPARE STMT FROM @SQL;
    EXECUTE STMT;
    DEALLOCATE PREPARE STMT;
  END$$
DELIMITER ;

  2.按天构造分区的存储过程create_partition_by_day:

#procedure of build partition of today and next day
DELIMITER $$
USE `dc_log`$$
DROP PROCEDURE IF EXISTS `create_partition_by_day`$$
CREATE PROCEDURE `create_partition_by_day`(IN_SCHEMANAME VARCHAR(64), IN_TABLENAME VARCHAR(64))
  BEGIN
    DECLARE ROWS_CNT INT UNSIGNED;
    DECLARE BEGINTIME TIMESTAMP;
    DECLARE ENDTIME TIMESTAMP;
    DECLARE DAYS_ENDTIME INT;
    DECLARE PARTITIONNAME VARCHAR(16);
    SET BEGINTIME = NOW() + INTERVAL 1 DAY;
    SET PARTITIONNAME = DATE_FORMAT(BEGINTIME, 'p%Y%m%d');
    SET ENDTIME = BEGINTIME + INTERVAL 1 DAY;
    SET DAYS_ENDTIME = TO_DAYS(ENDTIME);
    SELECT COUNT(*)
    INTO ROWS_CNT
    FROM information_schema.partitions
    WHERE table_schema = IN_SCHEMANAME AND table_name = IN_TABLENAME AND partition_name = PARTITIONNAME;
    IF ROWS_CNT = 0
    THEN
      SET @SQL = CONCAT('ALTER TABLE `', IN_SCHEMANAME, '`.`', IN_TABLENAME, '`',
                        ' ADD PARTITION (PARTITION ', PARTITIONNAME, ' VALUES LESS THAN (', DAYS_ENDTIME, '))');
      PREPARE STMT FROM @SQL;
      EXECUTE STMT;
      DEALLOCATE PREPARE STMT;
    ELSE
      SELECT CONCAT("partition `", PARTITIONNAME, "` for table `", IN_SCHEMANAME, ".", IN_TABLENAME,
                    "` already exists") AS result;
    END IF;
  END$$
DELIMITER ;

  3.按天清除数据的存储过程clear_partition_by_day

DELIMITER $$
USE `dc_log`$$
DROP PROCEDURE IF EXISTS `clear_partition_by_day`$$
CREATE PROCEDURE `clear_partition_by_day`(IN_SCHEMANAME VARCHAR(64), IN_TABLENAME VARCHAR(64))
  BEGIN
    DECLARE NOWDAYS INT;
    DECLARE Done INT;
    DECLARE part VARCHAR(64);
    DECLARE descr INT;
    DECLARE rs CURSOR FOR SELECT
                            partition_name        part,
                            partition_description descr
                          FROM information_schema.partitions
                          WHERE
                            table_schema = IN_SCHEMANAME
                            AND table_name = IN_TABLENAME;
    /* 异常处理 */
    DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET Done = 1;
    OPEN rs;
    SET NOWDAYS = TO_DAYS(NOW());
    FETCH rs into part,descr;
    while Done is null DO
      IF NOWDAYS - descr > 30
        THEN
          select descr AS cc;
          SET @SQL = CONCAT('ALTER TABLE `', IN_SCHEMANAME, '`.`', IN_TABLENAME, '`',
                            ' DROP PARTITION ', part);
          select descr AS aa;
          SELECT @SQL AS result;
          select descr AS bb;
          PREPARE STMT FROM @SQL;
          EXECUTE STMT;
          DEALLOCATE PREPARE STMT;
        END IF;
      FETCH rs into part,descr;
    end WHILE;
    CLOSE rs;
  END$$
DELIMITER ;

  注意:以上过程有可能报错,这里记录两个错误:

  1.分区字段必须包含主键:

  这里采用的是事件字段作为分区字段,当然不可能是主键,所以再mysql中会报错,查阅资料大多说是因为分区表中不能保证数据唯一,需要将分区健纳入主键才可,不清楚原理.如果不愿意这样做也可以考虑,删除已有主键,无主键的表可以用任意字段作为分区字段

ALTER TABLE dc_system.service_push DROP PRIMARY KEY;

  2.时间字段不允许作为分区字段:

  这是因为 DATETIME 会受到时间区的影响,mysql里面分区的时间字段需要用CURRENT_TIMESTAMP

ALTER TABLE business_log
  MODIFY create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP;

4.继续往下,打开事件变量,这里直接修改

SET GLOBAL event_scheduler = 'ON'; #打开

  重启后会被重置,如果需要永久修改,在my.cnf(mysql配置文件)中[mysqld]部分中添加下面内容,重启MYSQL

event_scheduler=ON

5.调用存储过程创建当天分区:

#created today's partition
CALL create_partition_today('dc_log', 'business_log');

6.创建事件:

DELIMITER $$
USE `dc_log`$$
CREATE EVENT IF NOT EXISTS `e_part_manage`
  ON SCHEDULE EVERY 1 HOUR #every minute
  STARTS '2018-05-01 18:27:00'
  ON COMPLETION PRESERVE
ENABLE
  COMMENT 'Creating partitions'
DO BEGIN
  CALL dc_log.create_partition_by_day('dc_log', 'business_log');
END$$
DELIMITER ;


#event of clear data which out of date of 30 days
DELIMITER $$
USE `dc_log`$$
CREATE EVENT IF NOT EXISTS `clear_data`
  ON SCHEDULE EVERY 1 DAY #every minute
  STARTS '2018-05-01 15:58:51'
  ON COMPLETION PRESERVE
ENABLE
  COMMENT 'clearing data'
DO BEGIN
  CALL clear_partition_by_day('dc_log', 'business_log');
END$$
DELIMITER ;

7.如果有其他表也需要如此处理,则先执行创建当天分区,再修改事件:

#service_push #same steps of table business_log
ALTER TABLE dc_system.service_push DROP PRIMARY KEY;
CALL create_partition_today('dc_system', 'service_push');


DELIMITER ;
DELIMITER $$
ALTER EVENT e_part_manage
DO BEGIN
  CALL dc_log.create_partition_by_day('dc_log', 'business_log');
  CALL dc_log.create_partition_by_day('dc_system', 'service_push');
END$$
DELIMITER ;

DELIMITER $$
ALTER EVENT clear_data
DO BEGIN
  CALL dc_log.clear_partition_by_day('dc_log', 'business_log') ;
  CALL dc_log.clear_partition_by_day('dc_system', 'service_push');
END$$
DELIMITER ;

8.查看表的分区情况:

use dc_log;
SELECT
      partition_name part,
      partition_expression expr,
      partition_description descr,
      table_rows
FROM
      INFORMATION_SCHEMA.partitions
WHERE
      TABLE_SCHEMA = SCHEMA()
AND TABLE_NAME='service_push' ;

9.手动添加分区:

ALTER TABLE dc_log.all_log ADD PARTITION (PARTITION 'PARTITIONNAME' VALUES LESS THAN (TO_DAYS(now())));

10.查看事件和事件开关

show events;
SHOW VARIABLES LIKE 'event_scheduler';

done

免责声明:文章转载自《Mysql数据按天分区,定期删除》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇[Linux内核]软中断与硬中断在MSYS2环境下 用msvc 编译 zlib下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

OpenStack各组件的常用命令

openstack命令 openstack-service restart #重启openstack服务 openstack endpoint-list #查看openstack的端口 nova的常用命令 nova list #列举当前用户所有虚拟机 nova show ID #列举某个虚机的详细信息 nova delete ID #直接删除某个虚机 no...

MySql cmd下的学习笔记 —— 有关多表查询的操作(多表查询练习题及union操作)

先建立一张 m 表 mysql> create table m ( -> mid int, -> hid int, -> gid int, -> mres varchar(10), -> matime date -> )engine myisam charset u...

数据库6.高级

1.视图:什么是视图:视图是有一张或多张表的查询结果构成的一张虚拟表create view dept_view as select *from dept;为什么使用视图:使用权限控制 只能开放某一列的数据访问 对于目前的查看工资而言是没有意义的我们使用虎能够查看整条语句1.多次使用时,可以简化书写2.隔离数据,可以修改原表中的数据;但是我们一般不会这么做。总...

Mac安装PHP运行环境

先安装brew ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" nginx的安装与配置 brew install nginx 修改配置文件 sudo vim /usr/local/etc/nginx/nginx.conf #修...

android studio 中jni底层日志的打印

1 添加ndk对log支持若需要添加ndk对log的支持,只需要通过以下2步即可实现。 1.1 修改Android.mk如生成的库文件是“.so文件”,则在Android.mk中添加如下内容:LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog如生成的库文件是“.a文件”,则在Android.mk中添加如下内容:LOCAL_LD...

Navicat连接mysql数据库报错2003

用navigat连接数据库,不论怎样一直都无法连接mysql,一直报错2003 - Can’t connect to MySQL server on ‘47.112.13.231’ (60 “Operation timed out”) 然后上网各种搜,下面是网友提出的几个方面原因:1、/etc/mysql/mysql.conf.d/mysqld.cnf配置...