MySQL数据库表分区

1.背景

当前数据库中,数据库表已经存在,同时该数据库表的数据还在每天不断增长。因为数据库表太大,导致检索过程耗时,为提高检索效率,故对相关数据库表进行分区处理。

2.MySQL分区

分区就是将一个表分解成多个区块进行操作和保存,从而降低每次操作的数据,提高性能。

而对应用来说是透明的,从逻辑上看是只有一个表,但在物理上这个表可能是由多个物理分区组成的,每个分区都是一个独立的对象,可以进行独立处理

四种常见的分区类型:

  • RANGE分区:最为常用,基于属于一个给定连续区间的列值,把多行分配给分区。最常见的是基于时间字段。

  • LIST分区:LIST分区和RANGE分区类似,区别在于LIST是枚举值列表的集合,RANGE是连续的区间值的集合。

  • HASH分区:基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的这些行的列值进行计算。这个函数可以包含MySQL中有效的、产生非负整数值的任何表达式。

  • KEY分区:类似于按HASH分区,区别在于KEY分区只支持计算一列或多列,且MySQL服务器提供其自身的哈希函数。必须有一列或多列包含整数值。

3.示例

3.1 RANGE分区

情景:现有hourdb数据库表,想要基于该数据库表的time字段进行分区。

实现:

sql 复制代码
-- 1.对hourdb表进行分区
-- 分区规则:
-- 2019年及之前
-- 2020年上半年--2020年下半年
-- 2021年上半年--2021年下半年
-- 2022年上半年--2022年下半年
-- 2023年上半年--2023年下半年
-- 2024年上半年--2024年下半年
-- 2025年上半年--2025年下半年
-- 2026年及之后

-- 基于time字段产生time_year_month字段,time_year_month=year*100+month
alter table hourdb add column time_year_month int generated always 
as(year(STR_TO_DATE(time,'%Y-%m-%d %H:%i:%s'))*100+month(STR_TO_DATE(time,'%Y-%m-%d %H:%i:%s'))) 
stored;

-- 创建新的分区表hourdb_partitioned,相比较原hourdb表,增加time_year_month字段
create table if not exists `hourdb_partitioned` (
 `senid` decimal(38,0) comment '传感器点号',
 `time` varchar(255) comment '时标',
 `v` decimal(11,3) comment '整点值',
 `avgv` decimal(11,3) comment '平均值',
 `maxv` decimal(11,3) comment '最大值',
 `maxt` varchar(255) comment '最大值发生时间',
 `minv` decimal(11,3) comment '最小值',
 `mint` varchar(255) comment '最小值发生时间',
 `s` decimal(38,0) comment '整点值标识',
 `avgs` decimal(38,0) comment '平均值标识',
 `maxs` decimal(38,0) comment '最大值标识',
 `mins` decimal(38,0) comment '最小值标识',
 `span` decimal(38,0) comment '计算时段',
 time_year_month int generated always 
 as(year(STR_TO_DATE(time,'%Y-%m-%d %H:%i:%s'))*100+month(STR_TO_DATE(time,'%Y-%m-%d %H:%i:%s'))) stored
)comment '小时数据信息'
partition by range(time_year_month)(
 partition p202000 values less than (202001) comment '2020年之前',
 partition p202001 values less than (202007) comment '2020年上半年',
 partition p202002 values less than (202101) comment '2020年下半年',
 partition p202101 values less than (202107)comment '2021年上半年',
 partition p202102 values less than (202201)comment '2021年下半年',
 partition p202201 values less than (202207)comment '2022年上半年',
 partition p202202 values less than (202301)comment '2022年下半年',
 partition p202301 values less than (202307)comment '2023年上半年',
 partition p202302 values less than (202401)comment '2023年下半年',
 partition p202401 values less than (202407)comment '2024年上半年',
 partition p202402 values less than (202501)comment '2024年下半年',
 partition p202501 values less than (202507)comment '2025年上半年',
 partition p202502 values less than (202601)comment '2025年下半年',
 partition p202511 values less than (maxvalue)comment '2026年及以后'
);

-- 将原数据库数据插入新的数据库
INSERT INTO `hourdb_partitioned`  (`senid`,`time`,`v`,`avgv`,`maxv`,`maxt`,`minv`,`mint`,`s`,`avgs`,`maxs`,`mins`,`span`)
select `senid`,`time`,`v`,`avgv`,`maxv`,`maxt`,`minv`,`mint`,`s`,`avgs`,`maxs`,`mins`,`span` from `hourdb` ;


-- 重命名表
rename table `hourdb` to `hourdb_backup`,`hourdb_partitioned` to `hourdb`;

-- 测试
select count(senid) from `hourdb` partition (p202401);

**注意:**在分区时,一定要按照从小到大的顺序,已经分区的内容将不再参与后续的分区。

3.2 LIST分区
sql 复制代码
CREATE TABLE `staff_partition_list` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `sex` tinyint(255) DEFAULT NULL,
  `age` int(3) DEFAULT NULL,
  PRIMARY KEY (`id`)
)ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
PARTITION BY List (id) (
	PARTITION p0 VALUES in (1,2,3,5),
	PARTITION p1 VALUES in (7,9,10),
	PARTITION p2 VALUES in (11,15)
);
3.3 HASH分区
sql 复制代码
CREATE TABLE `staff_partition_hash` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `sex` tinyint(255) DEFAULT NULL,
  `age` int(3) DEFAULT NULL,
  PRIMARY KEY (`id`)
)ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
PARTITION BY HASH (id)
PARTITIONS 3;

每次插入、更新、删除一行,hash表达式都要计算一次;这意味着非常复杂的表达式可能会引起性能问题,尤其是在执行同时影响大量行的运算(例如批量插入)的时候。

3.4 KEY分区
sql 复制代码
CREATE TABLE `staff_partition_key` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `sex` tinyint(255) DEFAULT NULL,
  `age` int(3) DEFAULT NULL,
  PRIMARY KEY (`id`)
)ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
PARTITION BY LINEAR Key (id)
PARTITIONS 3;

4.分区管理

4.1删除分区
sql 复制代码
alter table staff_partition drop partition p0;

上述语句删除p0分区,同时也会删除p0分区的数据。

sql 复制代码
 alter table staff_partition remove partitioning;

上述语句只删除p0分区,但是保留了p0分区的数据。

sql 复制代码
-- 对于hash分区和key分区
alter table staff_partition_hash COALESCE PARTITION 2;

上述命令将当前的分区数量减少到 2 个分区,数据库系统会自动选择哪些分区合并,重新分配数据

4.2增加分区

RANGE和LIST分区

sql 复制代码
alter table staff_partition add partition(partition p3 values LESS THAN (20));
  • 对于RANGE分区的表,只可以添加新的分区到分区列表的高端
  • 对于List分区的表,不能添加已经包含在现有分区值列表中的任意值

HASH和KEY分区

sql 复制代码
alter table test_staff_partition_hash add PARTITION partitions 2;
4.3重新分区
sql 复制代码
ALTER TABLE tbl_name REORGANIZE PARTITION partition_list INTO 
(partition_definitions)

-- 示例
ALTER TABLE example_table
  REORGANIZE PARTITION p1 INTO (
    PARTITION p1_1 VALUES LESS THAN (100),
    PARTITION p1_2 VALUES LESS THAN (200)
  );
4.4优化分区

如果从分区中删除了大量的行,或者对一个带有可变长度的行(也就是说,有VARCHAR,BLOB,或TEXT类型的列)作了许多修改,可以使用ALTER TABLE ... OPTIMIZE PARTITION来收回没有使用的空间,并整理分区数据文件的碎片。

sql 复制代码
alter table test_staff_partition OPTIMIZE PARTITION p2,p3;
相关推荐
武子康20 分钟前
Java-163 MongoDB 生产安全加固实战:10 分钟完成认证、最小权限、角色详解
java·数据库·分布式·mongodb·性能优化·系统架构·nosql
zhangyifang_00922 分钟前
PostgreSQL 的表继承与分区
数据库·postgresql
金仓拾光集1 小时前
国产化转型实战:制造业供应链物流系统从MongoDB至金仓数据库迁移全指南
数据库·mongodb·数据库平替用金仓·金仓数据库
天天进步20151 小时前
Django vs Flask:2025年该如何选择Python Web框架?
数据库·sqlite
JavaTree20171 小时前
【MySQL】mysqldump使用方法
数据库·mysql
HC02201 小时前
【保姆级教程】MySQL 5.7 彻底卸载与重新安装全流程(附常见问题解决)
数据库·mysql·mysql5.7·数据库安装·彻底卸载 mysql·mysql 配置教程
lkforce2 小时前
mysql表连接,因类型不匹配而导致索引失效的场景
数据库·mysql
超人小子2 小时前
mysql重置密码
数据库·mysql·adb
普通网友2 小时前
【mysql】锁机制 - 2.行锁间隙锁临键锁
数据库·mysql
zwtahql2 小时前
mysql的安装和卸载过程
数据库·mysql