有时我们需要保存大量数据,而这些数据是有时效性的,例如一些日志,在经过一段周期以后,这些数据存在的意义就不大了,除了占用大量的硬盘空间外还可能使数据查询变得缓慢。这些数据需要定时清除。我们可以采用表水平分割的方式(或分库分表)应对这种情况,但是水平分割表更适合具有大量查询或需要长期保存数据的情况。在某些情况下,我们数据的查询量并不大且表数据在单机情况下能满足系统需要,这时候Mysql分区表更适合。
首先创建分区表创建存储过程,并将其命名为:create_log_partition
BEGIN
select replace(partition_name,'device_log_','') into @PName from INFORMATION_SCHEMA. PARTITIONS where table_name = 'device_log' order by partition_ordinal_position desc limit 1;
IF isnull(@PName) THEN
select min(days) into @minDay from device_log;
select max(days) into @maxDays from device_log;
SET @partStr='';
WHILE @minDay <= @maxDays DO
SET @partStr = CONCAT(
@partStr,
'PARTITION device_log_' ,@minDay,
' VALUES in (' ,@minDay,
') ,'
);
SET @minDay = @minDay + 1;
END WHILE;
SET @sql = CONCAT('ALTER TABLE device_log PARTITION by list (days)(',@partStr,'PARTITION device_log_' ,@maxDays+1 ,' VALUES in (' ,@maxDays+1,') )');
PREPARE stmt FROM @sql ;
EXECUTE stmt ;
DEALLOCATE PREPARE stmt ;
ELSE
SET @minDay = CAST(@PName AS UNSIGNED INTEGER) + 1;
select (DATEDIFF(now(),'1970-1-1') + 1) into @days;
WHILE @minDay <= @days DO
SET @sql = CONCAT('ALTER TABLE device_log add PARTITION (PARTITION device_log_' ,@minDay,' VALUES in (' ,@minDay,') )');
PREPARE stmt FROM @sql ;
EXECUTE stmt ;
DEALLOCATE PREPARE stmt ;
SET @minDay = @minDay + 1;
END WHILE;
END IF;
END
创建分区表删除存储过程,并将其命名为:reduce_log_partition
BEGIN
select DATEDIFF(now(),'1970-1-1') into @days;
SET @find = 1;
WHILE @find > 0 DO
select replace(partition_name,'device_log_','') into @minDay from INFORMATION_SCHEMA. PARTITIONS where table_name = 'device_log' order by partition_ordinal_position asc limit 1;
IF ISNULL(@minDay) THEN
SET @find = 0;
ELSE
SET @minDay = CAST(@minDay AS UNSIGNED INTEGER);
IF @minDay + 15 <= @days THEN
SET @sql = CONCAT('alter table device_log drop partition device_log_',@minDay);
PREPARE stmt FROM @sql ;
EXECUTE stmt ;
DEALLOCATE PREPARE stmt ;
ELSE
SET @find = 0;
END IF;
END IF;
END WHILE;
END
这里创建2个存储过程是为了将来在某些时刻可能需要单独调用。
创建一个Mysql事件来定时执行以上两个存储过程:device_log_event
BEGIN
DECLARE r_code CHAR(5) DEFAULT '00000';
DECLARE r_msg TEXT;
DECLARE v_starttime DATETIME DEFAULT NOW();
BEGIN
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
GET DIAGNOSTICS CONDITION 1 r_code = RETURNED_SQLSTATE , r_msg = MESSAGE_TEXT;
END;
call create_log_partition();
call reduce_log_partition();
END;
insert into event_log (event_name,start_time,end_time,state,msg)values ('device_log_event',v_starttime,now(),r_code,r_msg);
END
设置执行周期
这里面有一个event_log表,用来记录事件执行情况,定义如下
CREATE TABLE `event_log` (
`event_log_id` int(11) NOT NULL AUTO_INCREMENT,
`event_name` varchar(255) NOT NULL,
`start_time` datetime NOT NULL,
`end_time` datetime NOT NULL,
`state` varchar(5) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '0',
`msg` text CHARACTER SET utf8 COLLATE utf8_general_ci,
PRIMARY KEY (`event_log_id`)
) ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=utf8;
device_log为分区表名称,可根据您的表名称进行更改。