这篇文章与mysql存储过程按月创建表分区 方式一 写的是相同的内容,只是在表分区创建方式上不一样。方式一是以less than(‘YYYY-mm-dd’)含引号作为分区格式,这样分区因为含有了引号,再执行sql查询数据属于哪个分区内时,容易产生问题;查询sql:
SELECT partition_name part,partition_description,partition_ordinal_position
from INFORMATION_SCHEMA.partitions
WHERE TABLE_SCHEMA = SCHEMA() AND TABLE_NAME='表名' and partition_description>='YYYY-mm-dd'。
因含有引号在查询时得到的结果永远都是 maxvalue或者null记录。
所有就重新写了这一种分区方式
#--设置mysql自动允许定时任务
set global event_scheduler =1;
#--建日志表
CREATE TABLE `sys_log_storage` (
`id` bigint(32) NOT NULL COMMENT 'ID',
`ip` varchar(16) DEFAULT NULL COMMENT '服务器IP',
`lvl` varchar(16) DEFAULT NULL COMMENT '日志级别',
`title` varchar(64) DEFAULT NULL COMMENT '标题',
`content` varchar(1024) DEFAULT NULL,
`createtime` datetime NOT NULL COMMENT '创建时间',
`classname` varchar(128) DEFAULT NULL,
`method` varchar(64) DEFAULT NULL
) ENGINE=InnoDB CHARSET=utf8 COMMENT='日志存储';
#--分区存储过程
create PROCEDURE pro_sys_logByMonth(IN tableName VARCHAR(20),IN timeColName VARCHAR(20))
COMMENT '每月按时添加表分区的存储过程,由定时任务调用'
BEGIN
DECLARE p_id int;
DECLARE nextDate date;
DECLARE lastDate LONG;
#--获取表中的现有的分区数量数量
SELECT COUNT(partition_name) into p_id FROM INFORMATION_SCHEMA.partitions
WHERE TABLE_SCHEMA = SCHEMA() AND TABLE_NAME=tableName;
if p_id=0 then
#--获取下个月第一天的时间值,根据此值设置时间分区
SELECT DATE_ADD(CURDATE()-DAY(CURDATE())+1,INTERVAL 1 MONTH) INTO nextDate from DUAL;
set @v_add=CONCAT('ALTER table ',tableName,' PARTITION by range(TO_DAYS(',timeColName,'))
(partition ',CONCAT('par',p_id),' values less than (TO_DAYS(\'',nextDate,'\')))');
ELSE
#--获取表中现有的最大的分区日期
SELECT max(partition_description) des into lastDate from INFORMATION_SCHEMA.partitions
WHERE TABLE_SCHEMA = SCHEMA() AND TABLE_NAME=tableName;
SELECT DATE_ADD(FROM_DAYS(lastDate),INTERVAL 1 MONTH) INTO nextDate from DUAL;
set @v_add=CONCAT('alter table ',tableName,' add partition (partition ',CONCAT('par',p_id),
' values less than (TO_DAYS(\'',nextDate,'\')))');
END IF;
PREPARE stmt from @v_add;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
#--每月创建一个分区的定时任务
create event event_sysLog on SCHEDULE EVERY 1 MONTH STARTS CURRENT_TIMESTAMP
on COMPLETION PRESERVE
ENABLE
do call pro_sys_logByMonth('sys_log_storage','createtime');
#--添加联合索引
alter table sys_log_storage add PRIMARY KEY(id,createtime);
alter table sys_log_storage change id id bigint(32) not null auto_increment;
alter table sys_log_storage auto_increment=1;
#--添加索引
alter TABLE sys_log_storage add index inx_syslog_ip(ip);
#--查看sql执行时,查询了那些分区,及使用的索引
EXPLAIN PARTITIONs select * from sys_log_storage where ip='125.76.249.62' and createtime <'2016-01-20';
当数据量大时,需要调整分区规则,比如按周或者天,代码如下:
-- 按日期格式自动添加分区存储过程
create PROCEDURE pro_sys_logByWeekDay (IN tableName VARCHAR(20),IN timeColName VARCHAR(20),IN dateFormat VARCHAR(10))
COMMENT '按日期格式(年YEAR,月month,周week,日day)添加表分区的存储过程,由定时任务调用'
BEGIN
DECLARE p_id int;
DECLARE lasttime Long;
DECLARE nexttime varchar(20);
-- 获取表中现有的最大的分区日期
SELECT max(partition_ordinal_position),max(partition_description) des into p_id,lasttime from INFORMATION_SCHEMA.partitions WHERE TABLE_SCHEMA = SCHEMA() AND TABLE_NAME=tableName;
-- lasttime的值是'2015-12-01' 含引号格式的字符串 必须转换成没有引号的字符串
set @v_add_a=CONCAT('select adddate(from_days(',lasttime,'),Interval 1 ',dateFormat,') into @nexttime from dual ');
PREPARE stm from @v_add_a;
EXECUTE stm;
DEALLOCATE PREPARE stm;
-- 将编译执行的stm结果存储到lasttimeadd中
set nexttime=@nexttime;
set @v_add=CONCAT('alter table ',tableName,' add partition (partition ',CONCAT('par',p_id),' values less than (TO_DAYS(\'',nexttime,'\')))');
PREPARE stmt from @v_add;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
-- 创建每周生成一次表分区的定时任务
create EVENT event_sysLogWeek on SCHEDULE EVERY 1 MONTH STARTS CURRENT_TIMESTAMP
on COMPLETION PRESERVE
ENABLE
DO call pro_sys_logByWeekDay('sys_log_storage6','createtime','Week');
-- 创建每天生成一次表分区的定时任务
create EVENT event_sysLogDay on SCHEDULE EVERY 1 DAY STARTS CURRENT_TIMESTAMP
on COMPLETION PRESERVE
ENABLE
DO call pro_sys_logByWeekDay('sys_log_storage6','createtime','day');