mysql partitions by range auto (mysql 自动创建按年月的表分区)

本文详细介绍如何在MySQL中创建表分区,并通过存储过程和事件调度实现按年月格式自动创建分区的功能。此外,还提供了具体步骤和示例代码。

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

环境:mysql 5.5
第一:怎么创建表分区
第二:怎么按年月格式(201601)自动创建分区

1、创建表,时间字段datetime由于业务需要必须要是unix_timestamp, 由于是按照时间来进行分区的,所以datetime这个字段必须要是主键。否则创建分区的时候会报错。

CREATE TABLE `test` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', `datetime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '时间', PRIMARY KEY (`id`,`datetime`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='测试表分区'/*!50100 PARTITION BY RANGE (datetime)(PARTITION p201511 VALUES LESS THAN (UNIX_TIMESTAMP("2015-12-01 00:00:00")) ENGINE = InnoDB, PARTITION p201512 VALUES LESS THAN (UNIX_TIMESTAMP("2016-01-01 00:00:00")) ENGINE = InnoDB) */;

2、创建存储过程,用于下面MYSQL的event定时器调用,自动创建就是event来完成的。这段存储过程的内容就是创建下月分区的意思。

DELIMITER $$

#该表所在数据库名称USE `test`$$DROP PROCEDURE IF EXISTS `create_partition_by_month`$$CREATE PROCEDURE `create_partition_by_month`(IN_SCHEMANAME VARCHAR(64), IN_TABLENAME VARCHAR(64))BEGIN DECLARE ROWS_CNT INT UNSIGNED; DECLARE BEGINTIME TIMESTAMP; DECLARE ENDTIME INT UNSIGNED; DECLARE PARTITIONNAME VARCHAR(16); DECLARE ENDTIME_DATETIME VARCHAR(30); SET BEGINTIME = DATE(NOW() - INTERVAL DAY(NOW()) DAY + INTERVAL 1 DAY + INTERVAL 1 MONTH); SET PARTITIONNAME = DATE_FORMAT( BEGINTIME, 'p%Y%m' ); SET ENDTIME = UNIX_TIMESTAMP(BEGINTIME + INTERVAL 1 MONTH); SET ENDTIME_DATETIME = FROM_UNIXTIME(ENDTIME); SELECT COUNT(*) INTO ROWS_CNT FROM information_schema.partitions WHERE table_schema = IN_SCHEMANAME AND table_name = IN_TABLENAME AND partition_name = PARTITIONNAME; IF ROWS_CNT = 0 THEN

SET @SQL = CONCAT( 'ALTER TABLE `', IN_SCHEMANAME, '`.`', IN_TABLENAME, '`', ' ADD PARTITION (PARTITION ', PARTITIONNAME, " VALUES LESS THAN (UNIX_TIMESTAMP('", 

ENDTIME_DATETIME ,"')) ENGINE = InnoDB);" );

PREPARE STMT FROM @SQL; EXECUTE STMT; DEALLOCATE PREPARE STMT; ELSE SELECT CONCAT("partition `", PARTITIONNAME, "` for table `",IN_SCHEMANAME, ".", IN_TABLENAME, "` already exists") AS result; END IF;END$$DELIMITER ;

2.1查看已经创建的存储过程。
show procedure status where db='logtop';

3、创建event。每分钟执行一次,检查下个月的表分区是否已经创建,如果没有创建,则调用上面的存储过程创建。

DELIMITER $$

#该表所在的数据库名称USE `test`$$CREATE EVENT IF NOT EXISTS `e_part_manage`ON SCHEDULE EVERY 1 MINUTE #执行周期,还有天、月等等STARTS '2016-01-07 18:27:00'ON COMPLETION PRESERVEENABLECOMMENT 'Creating partitions'DO BEGIN

#调用刚才创建的存储过程,第一个参数是数据库名称,第二个参数是表名称 CALL test.create_partition_by_month('test','test');END$$DELIMITER ;

3.1查看已经创建的event

SELECT * FROM information_schema.EVENTS;

4、检查MYSQL是否开启event,默认是Off,请设置成On,
SHOW VARIABLES LIKE 'event_scheduler';
SHOW GLOBAL VARIABLES LIKE 'event_scheduler';
SET GLOBAL event_scheduler = ON; #打开
只在全局设置的话,当MYSQL重启后该参数又会被重置成Off,所以需要在my.cnf里加上

vim /etc/my.cnf

[mysqld]

event_scheduler=ON

5、插入测试数据

INSERT INTO `test`.`test` (`datetime`) VALUES (unix_timestamp("2015-12-10"));INSERT INTO `test`.`test` (`datetime`) VALUES (unix_timestamp("2015-12-11"));INSERT INTO `test`.`test` (`datetime`) VALUES (unix_timestamp("2015-12-12"));INSERT INTO `test`.`test` (`datetime`) VALUES (unix_timestamp("2015-12-13"));INSERT INTO `test`.`test` (`datetime`) VALUES (unix_timestamp("2015-12-13"));INSERT INTO `test`.`test` (`datetime`) VALUES (unix_timestamp("2015-12-14"));INSERT INTO `test`.`test` (`datetime`) VALUES (unix_timestamp("2015-12-15"));INSERT INTO `test`.`test` (`datetime`) VALUES (unix_timestamp("2015-12-16"));INSERT INTO `test`.`test` (`datetime`) VALUES (unix_timestamp("2015-12-17"));INSERT INTO `test`.`test` (`datetime`) VALUES (unix_timestamp("2015-12-18"));INSERT INTO `test`.`test` (`datetime`) VALUES (unix_timestamp("2015-12-19"));INSERT INTO `test`.`test` (`datetime`) VALUES (unix_timestamp("2015-12-20"));

6、查看数据在每个分区中的分布情况

SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='test';


#添加分区

ALTER TABLE `test`.`test` ADD PARTITION (PARTITION p201601 VALUES LESS THAN (UNIX_TIMESTAMP("2016-02-01 00:00:00")) ENGINE = InnoDB);

#删除分区ALTER TABLE test.testDROP PARTITION p201511;

查看查询SQL是否使用的分区

explain PARTITIONS select *,FROM_UNIXTIME(datetime) from test where datetime > UNIX_TIMESTAMP("2015-12-10") and datetime < UNIX_TIMESTAMP("2015-12-15");

<think>嗯,用户之前问过如何用SQL查询指定表的分区信息,现在他想知道在MySQL 8中如何为指定表创建分区,特别是以user_id字段,每2000万一个分区。我需要先回顾一下MySQL分区功能,特别是MySQL 8的版本是否有变化。 首先,用户可能已经有一个表,或者需要新建一个分区表。根据之前的回答,用户可能对分区有一定了解,但需要具体的步骤。要注意MySQL分区类型,比如范围分区、列表分区、哈希分区等。这里用户提到的是每2000万一个分区,应该属于范围分区,按用户ID的范围划分。 接下来,我需要确认MySQL 8是否支持自动按数值范围分区,以及如何定义分区间隔。每2000万一个分区,可能需要手动指定每个分区的上限值,或者使用MySQL 8的新特性,比如自动分区?不过我记得MySQL没有自动按间隔创建分区的功能,需要手动定义每个分区的VALUES LESS THAN值。 然后,用户可能需要修改现有表结构来添加分区,或者创建新表时定义分区。如果表已经存在,需要使用ALTER TABLE语句,但需要注意现有表是否有主键或唯一索引,因为分区键必须是主键的一部分,或者不包含唯一索引。这可能是一个容易出错的地方,需要提醒用户检查表结构。 另外,用户提到user_id作为分区字段,需要确保这个字段是整数类型,比如INT或BIGINT。如果user_id是字符串类型,可能需要转换或者调整分区策略。此外,每个分区的数据量2000万,可能需要考虑存储引擎的性能,比如InnoDB的处理能力,以及分区数量是否合理,避免过多分区影响性能。 还要考虑分区后的查询优化,比如查询条件是否包含分区键,这样可以利用分区裁剪提高效率。同时,用户可能需要定期维护分区,比如添加新的分区或删除旧的分区,尤其是按范围递增的情况,需要提前创建分区,否则插入数据时可能会报错。 另外,是否需要给出示例代码?比如创建表时定义分区的SQL语句,以及如何为已有表添加分区的步骤。如果用户已有表,可能需要使用ALTER TABLE,但需要注意数据迁移的问题,可能需要使用在线DDL工具或者pt-online-schema-change来避免锁表。 还要提醒用户备份数据,在进行分区操作前做好备份,以防万一。此外,检查MySQL的版本是否确实支持分区功能,因为有些版本可能需要特定的配置或存储引擎支持。 最后,总结步骤:确定表结构是否支持分区,选择合适的分区类型(RANGE),定义每个分区的范围,执行创建或修改表的语句,验证分区是否成功,并测试插入数据是否符合预期。</think>在MySQL 8中为表创建按`user_id`字段范围分区的完整操作步骤如下(每2000万数据一个分区): **一、创建分区表** ```sql CREATE TABLE 你的表名 ( id INT AUTO_INCREMENT, user_id BIGINT NOT NULL, -- 其他字段... created_at DATETIME, PRIMARY KEY (id, user_id) -- 必须包含分区) PARTITION BY RANGE (user_id) ( PARTITION p0 VALUES LESS THAN (20000000), PARTITION p1 VALUES LESS THAN (40000000), PARTITION p2 VALUES LESS THAN (60000000), PARTITION p_max VALUES LESS THAN MAXVALUE ); ``` **二、为已有表添加分区(需满足前提条件)** 1. 检查现有表结构: ```sql SHOW CREATE TABLE 你的表名; ``` 2. 确认主键包含`user_id`字段(必须条件): ```sql ALTER TABLE 你的表名 DROP PRIMARY KEY, ADD PRIMARY KEY(id, user_id); -- 修改主键 ``` 3. 执行分区操作: ```sql ALTER TABLE 你的表名 PARTITION BY RANGE (user_id) ( PARTITION p0 VALUES LESS THAN (20000000), PARTITION p1 VALUES LESS THAN (40000000), PARTITION p2 VALUES LESS THAN (60000000), PARTITION p_max VALUES LESS THAN MAXVALUE ); ``` **三、动态扩展分区(当数据接近上限时)** ```sql ALTER TABLE 你的表名 REORGANIZE PARTITION p_max INTO ( PARTITION p3 VALUES LESS THAN (80000000), PARTITION p_max VALUES LESS THAN MAXVALUE ); ``` **四、验证分区效果** 1. 查看分区结构: ```sql SELECT partition_name, partition_expression, partition_description FROM information_schema.PARTITIONS WHERE TABLE_NAME = '你的表名'; ``` 2. 查看分区数据量: ```sql SELECT PARTITION_NAME, TABLE_ROWS FROM information_schema.PARTITIONS WHERE TABLE_NAME = '你的表名'; ``` **关键注意事项:** 1. 主键必须包含分区字段`user_id`(MySQL分区表的强制要求) 2. 建议使用`BIGINT`类型存储`user_id`(可支持到922亿数据量) 3. `MAXVALUE`分区是安全阀,必须保留一个最大分区防止数据写入失败 4. 当数据达到`6000万`时,需要及时执行`REORGANIZE`扩展新分区 5. 建议建立定期监控: ```sql -- 检查即将填满的分区 SELECT MAX(user_id) FROM 你的表名 PARTITION (p_max); ``` **性能优化建议:** 1. 将不同分区存储到不同磁盘(需要修改存储引擎配置) 2. 结合`KEY`分区实现二级分区(例如按年月+user_id组合分区) 3. 对`user_id`字段建立索引(虽然分区本身可以提升查询效率) 4. 使用`InnoDB`存储引擎(推荐使用`innodb_file_per_table`) **典型错误处理:** ```sql -- 当出现"ERROR 1503 (HY000)"时,通常是因为: -- 1. 主键未包含分区字段 -- 2. 分区字段类型不匹配 -- 3. 存在唯一索引未包含分区字段 ``` **自动分区的替代方案(使用事件调度):** ```sql -- 创建定时扩展任务(每天检查) DELIMITER $$ CREATE EVENT auto_extend_partitions ON SCHEDULE EVERY 1 DAY DO BEGIN IF (SELECT MAX(user_id) FROM 你的表名) > 当前最大分区值 THEN ALTER TABLE 你的表名 ...; -- 执行分区重组 END IF; END$$ DELIMITER ; ``` 根据实际业务增长情况,建议初始预留3-5个空分区(如示例中的p0-p2),避免频繁的分区维护操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值