Mysql数据库分区及注意事项

Mysql数据库分区及注意事项

最近项目中用到数据库分区,在此记录下使用过程中遇到的问题及注意事项。

1、创建表

创建表时需要指定该表需要分区,使用关键字:PARTITION

CREATE TABLE `msg_log`  (
  `id` bigint(32) NOT NULL COMMENT '主键',
  `request_time` datetime(0) NOT NULL COMMENT '请求时间',
  `response_time` datetime(0) NOT NULL COMMENT '响应时间',
  `time_used` int(11) NOT NULL COMMENT '耗时(ms)',
  `create_by` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `update_by` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '创建时间',
  `update_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新时间',
  PRIMARY KEY (`id`, `request_time`) USING BTREE
) PARTITION BY RANGE (TO_DAYS(request_time)) (
    PARTITION p0 VALUES LESS THAN (0)
 ) ;

此处需要注意的是:如果想要按某个字段的进行分区,那么该字段必须包含在主键里。

2、创建分区

alter table msg_log add partition (partition p20220707 values less than (TO_DAYS("20220707")+1))

将每天的记录生成对应的分区,一天一个分区。

3、删除分区

alter table msg_log drop partition p20220707

根据分区名称删除。

4、注意事项

4.1 如果当前我们创建了四个分区:p20220706,p20220707,p20220708,p20220709,对应的每天一个数据分区,由于不小心删除了其中的某个分区,例如p20220707,如果后续想重新新增该分区,此时如果执行2中的alter语句,虽然不报错,但是分区创建失败。这种情况下,需要将后面的p20220708,p20220709两个分区删除,然后再重新创建。

4.2 一般动态创建分区有以下两种方式:第一种,在数据库上创建函数,通过应用程序定时进行调用创建;第二种,在数据库上创建存储过程,通过数据库自身的执行计划调用。具体情况根据实际业务等情形进行选择。

4.3 不管是函数调用,还是数据库存储过程调用,如果开启了事务,务必防止在执行过程中,遇到错误时,做到回滚或提交,防止锁表。

5、创建分区函数

该函数,根据传入的参数创建对应的分区,形如:p20220707。参数有:时间、schema、表名称、格式。

DELIMITER $$
CREATE PROCEDURE sp_create_partition (day_value datetime, tb_schema varchar(128),tb_name varchar(128),par_name_format varchar(20))
BEGIN
  DECLARE par_name varchar(32);
  DECLARE par_value varchar(32);
  DECLARE _err int(1);
  DECLARE par_exist int(1);
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND SET _err = 1;
  START TRANSACTION;
    SET par_name = CONCAT('p', DATE_FORMAT(day_value, par_name_format));
    SELECT
      COUNT(1) INTO par_exist
    FROM information_schema.PARTITIONS
    WHERE TABLE_SCHEMA = tb_schema AND TABLE_NAME = tb_name AND PARTITION_NAME = par_name;
    IF (par_exist = 0) THEN
      SET par_value = DATE_FORMAT(day_value, '%Y-%m-%d');
      SET @alter_sql = CONCAT('alter table ', tb_name, ' add PARTITION (PARTITION ', par_name, ' VALUES LESS THAN (TO_DAYS("', par_value, '")+1))');
      PREPARE stmt1 FROM @alter_sql;
      EXECUTE stmt1;
    END IF;
  COMMIT;
  END
$$

以上数据库函数,通过mybatis调用方式,形如:

<insert id="addPartition" >
		CALL sp_create_partition(DATE_ADD(NOW(), INTERVAL + (#{offsetDay}) DAY), #{schemaName}, #{tableName},'%Y%m%d')
	</insert>
public void addPartition(@Param("schemaName") String schemaName, @Param("tableName") String tableName,
			@Param("offsetDay") int offsetDay);

6、删除分区函数

DELIMITER $$
CREATE PROCEDURE sp_drop_partition (day_value datetime, tb_schema varchar(128), tb_name varchar(128),par_name_format varchar(20))
BEGIN
  DECLARE str_day varchar(64);
  DECLARE _err int(1);
  DECLARE done int DEFAULT 0;
  DECLARE par_name varchar(64);
  DECLARE cur_partition_name CURSOR FOR
  SELECT
    partition_name
  FROM INFORMATION_SCHEMA.PARTITIONS
  WHERE TABLE_SCHEMA = tb_schema AND table_name = tb_name
  ORDER BY partition_ordinal_position;
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND SET _err = 1;
  DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
  SET str_day = DATE_FORMAT(day_value, par_name_format);
  OPEN cur_partition_name;
  REPEAT
    FETCH cur_partition_name INTO par_name;
    IF (str_day > SUBSTRING(par_name, 2)) THEN
      SET @alter_sql = CONCAT('alter table ', tb_name, ' drop PARTITION ', par_name);
      PREPARE stmt1 FROM @alter_sql;
      EXECUTE stmt1;
    END IF;
  UNTIL done END REPEAT;
  CLOSE cur_partition_name;
END
$$

该函数,删除特定的分区名称,实现删除超过特定天数的记录分区。

mybatis调用方式,形如:

	<delete id="dropPartition">
		CALL sp_drop_partition(#{holdDate}, #{schemaName}, #{tableName},'%Y%m%d')
	</delete>

public void dropPartition(@Param("schemaName") String schemaName, @Param("tableName") String tableName,	@Param("holdDate") Date holdDate);

7、查询分区

select * from information_schema.partitions where table_name = 'msg_log';

查询某个表的某个分区是否存在

 select COUNT(1) t FROM information_schema.PARTITIONS   WHERE TABLE_SCHEMA = 'test_schema' AND TABLE_NAME = 'msg_log' AND PARTITION_NAME = 'p20220707';
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值