Mysql分区——通过range分区

随着数据量增长,MySQL中的历史数据清理成为挑战。本文聚焦Range分区,介绍如何通过分区优化历史数据处理,包括新建分区表、备份旧表、改名及创建分区函数等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

随着MySQL越来越流行,Mysql里面的保存的数据也越来越大。在日常的工作中,我们经常遇到一张表里面保存了上亿甚至过十亿的记录。这些表里面保存了大量的历史记录。 对于这些历史数据的清理是一个非常头疼事情,由于所有的数据都一个普通的表里。所以只能是启用一个或多个带where条件的delete语句去删除(一般where条件是时间)。 这对数据库的造成了很大压力。即使我们把这些删除了,但底层的数据文件并没有变小。面对这类问题,最有效的方法就是在使用分区表。最常见的分区方法就是按照时间进行分区。 分区一个最大的优点就是可以非常高效的进行历史数据的清理。


一、分区类型

目前MySQL支持范围分区(RANGE),列表分区(LIST),哈希分区(HASH)以及KEY分区四种。这片文章我们主要介绍range分区。

二、RANGE分区

基于属于一个给定连续区间的列值,把多行分配给分区。最常见的是基于时间字段. 基于分区的列最好是整型,如果日期型的可以使用函数转换为整型。本例中使用to_days函数。

1.新建表用来创建分区

代码如下(示例):

drop table if exists `unmaintained_insurance_logs_bak`;
CREATE TABLE `unmaintained_insurance_logs_bak` (
  `id` bigint(10) NOT NULL AUTO_INCREMENT,
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `insurance_no` varchar(63) NOT NULL COMMENT '险种号',
  `insurance_name` varchar(255) NOT NULL COMMENT '险种名称',
  `insurance_type` int(10) NOT NULL DEFAULT '0' COMMENT '险种类型 1 主险 2 附加险',
  PRIMARY KEY (`id`,`gmt_create`) USING BTREE,
  KEY `insurance_no_idx` (`insurance_no`),
  KEY `insurance_name_idx` (`insurance_no`)
) ENGINE=InnoDB AUTO_INCREMENT=1812 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT

-- 根据入库时间进行RANGE分区(接在建表语句后,注意建表语句不能加分号)
PARTITION BY RANGE(TO_DAYS(gmt_create))(
		PARTITION p20191001 VALUES LESS THAN (TO_DAYS('2019-11-01 00:00:00')),

	  	PARTITION p20191101 VALUES LESS THAN (TO_DAYS('2019-12-01 00:00:00')),

   		PARTITION p20191201 VALUES LESS THAN (TO_DAYS('2020-01-01 00:00:00')),

		PARTITION p20200101 VALUES LESS THAN (TO_DAYS('2020-02-01 00:00:00')),

		PARTITION p20200201 VALUES LESS THAN (TO_DAYS('2020-03-01 00:00:00')),

		PARTITION p20200301 VALUES LESS THAN (TO_DAYS('2020-04-01 00:00:00')),

		PARTITION pMaxValue VALUES LESS THAN MAXVALUE

);

2.备份旧表

代码如下(示例):

drop table if exists `unmaintained_insurance_logs_temp`;
ALTER TABLE unmaintained_insurance_logs RENAME TO unmaintained_insurance_logs_temp;

3.将新表名称改为旧表

代码如下(示例):

ALTER TABLE unmaintained_insurance_logs_bak RENAME TO unmaintained_insurance_logs;

4.创建函数自动生成新的分区

delimiter $$
-- 创建函数名称
drop procedure if exists partition_unmaintained_insurance_logs;
CREATE PROCEDURE partition_unmaintained_insurance_logs()
BEGIN
-- 创建新的分区
-- 每个月创建下个月的分区
SET @cMonth = REPLACE(DATE(DATE_ADD(SYSDATE(),INTERVAL 1 MONTH)),'-','');
select concat('cMonth is ', @cMonth);
loop_label: loop
-- 查找当前除了MAXVALUE的最大分区项,并赋值给 P_Name
SELECT REPLACE
	(partition_name, 'p', '') INTO @P_Name
FROM
	INFORMATION_SCHEMA.PARTITIONS
WHERE
	table_name = 'unmaintained_insurance_logs'
	and partition_name <> 'pMaxValue'
ORDER BY
	partition_ordinal_position DESC
	LIMIT 0,1;
	-- 创建新分区名称,应该是比之前最大分区值多一月
SET @new_part= DATE(DATE_ADD(@P_Name+0, INTERVAL 1 MONTH))+0;
select concat('new_part is ', @new_part);
-- 创建新分区的条件值,每个月创建下一个月的分区
SET @order_date= DATE(DATE_ADD(@new_part+0, INTERVAL 1 MONTH))+0;
select concat('order_date is ', @order_date);
-- 如果新分区规则小于下个月的时间则循环创建分区
	if @order_date < @cMonth then
-- 删除最大分区maxValue
SELECT COUNT(*) INTO @cnt FROM INFORMATION_SCHEMA.PARTITIONS
	WHERE TABLE_SCHEMA = 'clie' and table_name='unmaintained_insurance_logs' and partition_name = 'pMaxValue';
  if @cnt > 0 then
    SET @s1=CONCAT('ALTER TABLE unmaintained_insurance_logs DROP PARTITION pMaxValue');
	  SELECT @s1;
    PREPARE stmt1 FROM @s1;
    EXECUTE stmt1;
    DEALLOCATE PREPARE stmt1;
  end if;
-- 创建新的分区语句
SET @s2=CONCAT('ALTER TABLE unmaintained_insurance_logs ADD PARTITION (PARTITION p',@new_part,' VALUES LESS THAN (TO_DAYS (''',DATE(@order_date),''')))');
  SELECT @s2;
  PREPARE stmt2 FROM @s2;
  EXECUTE stmt2;
  DEALLOCATE PREPARE stmt2;
-- 创建maxValue分区用于存放大于当前时间的异常数据
SET @s3=CONCAT('ALTER TABLE unmaintained_insurance_logs ADD PARTITION (PARTITION pMaxValue VALUES LESS THAN MAXVALUE)');
	SELECT @s3;
  PREPARE stmt3 FROM @s3;
  EXECUTE stmt3;
  DEALLOCATE PREPARE stmt3;
     iterate loop_label;
  end if;
  -- 如果新分区月份大于当前的月份,停止创建分区
  if @order_date > @cMonth then
     leave loop_label;
  end if;
  end loop loop_label;
	COMMIT ;
END $$
DELIMITER ;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值