109.MySQL大表优化为分区表-并使用定时任务实现按日自动分区功能

1.mysql 大表优化

--(1).案例。
(1)创建分区表
CREATE TABLE tsdp_server_log_info (
  id varchar(64) NOT NULL COMMENT '主键',
  execute_starttime datetime NOT NULL,
  waterfall bigint(20) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (id,execute_starttime),
  KEY waterfall (waterfall)
  )
ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
PARTITION BY RANGE (TO_DAYS(execute_starttime)) (
    PARTITION p20240112 VALUES LESS THAN (TO_DAYS('2024-01-12')),
    PARTITION p20240119 VALUES LESS THAN (TO_DAYS('2024-01-13')),
    PARTITION p20240126 VALUES LESS THAN (TO_DAYS('2024-01-14'))
);
Query OK, 0 rows affected (0.02 sec)
root@itpux 16:34:  [mydb]> 

(2)创建事件,定时删除30天前的分区,并创建新的分区。

--按日分区。

--日志表记录分区的删除和增加。
drop table mydb.add_partition_log;
create table mydb.add_partition_log(add_time datetime ,part_name varchar(30),flag varchar(20));

--切换到Mydb数据库
use  mydb; 
--drop procedure P_ADD_TAB_PARTITION;

DELIMITER //
CREATE PROCEDURE P_ADD_TAB_PARTITION()
BEGIN 

SELECT COUNT(1) INTO @PART_NUM1 FROM  INFORMATION_SCHEMA.PARTITIONS 
WHERE UPPER(TABLE_NAME)='TSDP_SERVER_LOG_INFO' 
AND PARTITION_NAME=CONCAT('p',DATE_FORMAT((SELECT DATE_SUB(NOW(), INTERVAL -2 DAY)),'%Y%m%d'));

IF @PART_NUM1=0 THEN 
	SET @ADD_PARTITION = CONCAT("alter table mydb.tsdp_server_log_info add partition(partition ", concat('p',date_format((SELECT DATE_SUB(now(), INTERVAL -2 DAY)),'%Y%m%d')) , " VALUES LESS THAN (TO_DAYS('",date_format((SELECT DATE_SUB(now(), INTERVAL -2 DAY)),'%Y-%m-%d'),"')));");  
	PREPARE STMT FROM @ADD_PARTITION;
	EXECUTE STMT;
	DEALLOCATE PREPARE STMT;
	INSERT INTO mydb.add_partition_log VALUES(NOW(),CONCAT('p',DATE_FORMAT((SELECT DATE_SUB(NOW(), INTERVAL -2 DAY)),'%Y%m%d')),'add');
ELSE 
	INSERT INTO mydb.add_partition_log VALUES(NOW(),concat('p',DATE_FORMAT((SELECT DATE_SUB(NOW(), INTERVAL -2 DAY)),'%Y%m%d')),'already exist');
END IF;

SELECT COUNT(1) INTO @PART_NUM2 FROM  INFORMATION_SCHEMA.PARTITIONS 
WHERE UPPER(TABLE_NAME)='TSDP_SERVER_LOG_INFO' 
AND PARTITION_NAME=CONCAT('p',DATE_FORMAT((SELECT DATE_SUB(NOW(), INTERVAL 30 DAY)),'%Y%m%d'));
IF @PART_NUM2=0 THEN 
	INSERT INTO mydb.add_partition_log VALUES(NOW(),concat('p',DATE_FORMAT((SELECT DATE_SUB(NOW(), INTERVAL 30 DAY)),'%Y%m%d')),'does not exist');
ELSE 
	SET @DROP_PARTITION= CONCAT("alter table mydb.tsdp_server_log_info drop partition  ", CONCAT('p',DATE_FORMAT((SELECT DATE_SUB(NOW(), INTERVAL 30 DAY)),'%Y%m%d')),';');  
	PREPARE STMT FROM @DROP_PARTITION;
	EXECUTE STMT;
	DEALLOCATE PREPARE STMT;
	INSERT INTO mydb.add_partition_log VALUES(NOW(),CONCAT('p',DATE_FORMAT((SELECT DATE_SUB(NOW(), INTERVAL 30 DAY)),'%Y%m%d')),'drop');
END IF;
END//
DELIMITER ;

--默认每次执行时删除30天前的分区,同时添加下一个自然日的分区。
--如果想要每次执行时添加sysdate+7 日的分区,则可以修改如下这段:
concat('p',DATE_FORMAT((SELECT DATE_SUB(NOW(), INTERVAL -2 DAY)),'%Y%m%d')) --1天后的日分区。
--修改为:
concat('p',DATE_FORMAT((SELECT DATE_SUB(NOW(), INTERVAL -8 DAY)),'%Y%m%d')) --7天后的日分区。

--(3)验证分区功能

root@itpux 18:41:  [mydb]> insert into tsdp_server_log_info values(19,'2024-01-19 23:00:00',null);
Query OK, 1 row affected (0.00 sec)

root@itpux 18:41:  [mydb]> select * from tsdp_server_log_info where execute_starttime between '2024-01-19 00:00:00' and '2024-01-19 23:59:00';
+----+---------------------+-----------+
| id | execute_starttime   | waterfall |
+----+---------------------+-----------+
| 19 | 2024-01-19 23:00:00 |         1 |
+----+---------------------+-----------+
1 row in set (0.00 sec)

root@itpux 18:42:  [mydb]> explain select * from tsdp_server_log_info where execute_starttime between '2024-01-19 00:00:00' and '2024-01-19 23:59:00';
+----+-------------+----------------------+------------+-------+---------------+-----------+---------+------+------+----------+--------------------------+
| id | select_type | table                | partitions | type  | possible_keys | key       | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+----------------------+------------+-------+---------------+-----------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | tsdp_server_log_info | p20240120  | index | NULL          | waterfall | 8       | NULL |    1 |   100.00 | Using where; Using index |
+----+-------------+----------------------+------------+-------+---------------+-----------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

(4)
--创建定时任务事件。

--从1月12日开始执行,以后每天11:00定时运行一次。
DROP EVENT E_ADD_PARTION;
CREATE EVENT E_ADD_PARTION ON SCHEDULE EVERY 1 DAY STARTS '2024-01-12 11:00:00'
DO CALL P_ADD_TAB_PARTITION;


--主库开启定时任务。
root@itpux 10:29:  [mydb]> set global event_scheduler=1;
Query OK, 0 rows affected (0.00 sec)
vi /etc/my.cnf 
[mysqld]
event_scheduler=1


--主库查看事件。
root@itpux 10:48:  [mydb]> show events;
+------+---------------+----------------+-----------+-----------+------------+----------------+----------------+---------------------+------+---------+------------+----------------------+----------------------+--------------------+
| Db   | Name          | Definer        | Time zone | Type      | Execute at | Interval value | Interval field | Starts              | Ends | Status  | Originator | character_set_client | collation_connection | Database Collation |
+------+---------------+----------------+-----------+-----------+------------+----------------+----------------+---------------------+------+---------+------------+----------------------+----------------------+--------------------+
| mydb | E_ADD_PARTION | root@localhost | SYSTEM    | RECURRING | NULL       | 1              | DAY            | 2024-01-12 10:50:00 | NULL | ENABLED |     513306 | utf8                 | utf8_general_ci      | utf8_general_ci    |
+------+---------------+----------------+-----------+-----------+------------+----------------+----------------+---------------------+------+---------+------------+----------------------+----------------------+--------------------+
--从库查看事件。
--可以看到从库禁用事件。
root@itpux 10:47:  [mydb]> show events;
+------+---------------+----------------+-----------+-----------+------------+----------------+----------------+---------------------+------+--------------------+------------+----------------------+----------------------+--------------------+
| Db   | Name          | Definer        | Time zone | Type      | Execute at | Interval value | Interval field | Starts              | Ends | Status             | Originator | character_set_client | collation_connection | Database Collation |
+------+---------------+----------------+-----------+-----------+------------+----------------+----------------+---------------------+------+--------------------+------------+----------------------+----------------------+--------------------+
| mydb | E_ADD_PARTION | root@localhost | SYSTEM    | RECURRING | NULL       | 1              | DAY            | 2024-01-12 10:50:00 | NULL | SLAVESIDE_DISABLED |     513306 | utf8                 | utf8_general_ci      | utf8_general_ci    |
+------+---------------+----------------+-----------+-----------+------------+----------------+----------------+---------------------+------+--------------------+------------+----------------------+----------------------+--------------------+

(5)定时任务开始前检查

--定时任务开始前检查。
root@itpux 10:55:  [mydb]> select * from add_partition_log;
Empty set (0.00 sec)

root@itpux 10:55:  [mydb]> show create table tsdp_server_log_info;
+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table                | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tsdp_server_log_info | CREATE TABLE `tsdp_server_log_info` (
  `id` varchar(64) NOT NULL COMMENT '主键',
  `execute_starttime` datetime NOT NULL,
  `waterfall` bigint(20) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`,`execute_starttime`),
  KEY `waterfall` (`waterfall`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
/*!50100 PARTITION BY RANGE (TO_DAYS(execute_starttime))
(PARTITION p20240112 VALUES LESS THAN (739262) ENGINE = InnoDB,
 PARTITION p20240113 VALUES LESS THAN (739263) ENGINE = InnoDB,
 PARTITION p20240120 VALUES LESS THAN (739270) ENGINE = InnoDB) */   |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+



(6)检查定时任务执行后的表分区

--每天11点执行一次,现在11:01检查一次,发现已经执行成功。
--我的系统时间比正常时间快一天,时间可以忽略。
root@itpux 10:55:  [mydb]> select * from add_partition_log;
+---------------------+-----------+----------------+
| add_time            | part_name | flag           |
+---------------------+-----------+----------------+
| 2024-01-20 11:00:00 | p20240122 | add            |
| 2024-01-20 11:00:00 | p20231221 | does not exist |
+---------------------+-----------+----------------+
--默认按日分区,每次添加下一个自然日的分区。
--同时删除30天前的分区,如果分区不存在,就写入日志文件,分区不存在"does not exist "。

--检查新增的分区:
CREATE TABLE `tsdp_server_log_info` (
  `id` varchar(64) NOT NULL COMMENT '主键',
  `execute_starttime` datetime NOT NULL,
  `waterfall` bigint(20) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`,`execute_starttime`),
  KEY `waterfall` (`waterfall`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
/*!50100 PARTITION BY RANGE (TO_DAYS(execute_starttime))
(PARTITION p20240112 VALUES LESS THAN (739262) ENGINE = InnoDB,
 PARTITION p20240113 VALUES LESS THAN (739263) ENGINE = InnoDB,
 PARTITION p20240120 VALUES LESS THAN (739270) ENGINE = InnoDB,
 PARTITION p20240122 VALUES LESS THAN (739272) ENGINE = InnoDB) */  
;
--可以看到新的分区已经添加。
--说明定时任务生效。

2.总结

mysql的分区功能相对较弱,目前尚无法实现自动分区,不过我们可以通过创建事件的方式,实现自动增加分区的功能。