MySQL表分区
问题
今天项目上遇到一个我看不懂的SQLException,刚开始很懵逼!!不知道有没有小伙伴和我一样惊掉了下巴?上BUG
### Error updating database. Cause: java.sql.SQLException: Table has no partition for value 738735
### Cause: java.sql.SQLException: Table has no partition for value 738735
; uncategorized SQLException; SQL state [HY000]; error code [1526]; Table has no partition for value 738735; nested exception is java.sql.SQLException: Table has no partition for value 738735
未分类的SQLException,未分类是什么鬼?项目之前都没有报这个错,为什么突然就报这个错?还是个看不懂的错,按照程序员解决问题的惯例,复制问题到CSDN搜一下!看到有的博主给出如下解决方案:
alter table tableName add partition(partition p202112 VALUES LESS THAN (738521) ENGINE = InnoDB);
看了一下,说是MySQL中表可以进行分区存储数据,但是这个博主有点不厚道,给了解决方案,但这个解决方案只是相对于他的情况的,而且并没有讲解这个SQL的含义,导致原地蒙圈好久,于是就直接去了解学习一下MySQL的表分区。
前言
以往都是听说过什么分库分表,倒没有听说过表分区,表分区就是对同一个表中的数据根据指定的依据进行划分为多个部分,这样划分有什么好处呢?刚开始也不理解,都在一个表里了,还这样划分有什么意义呢?回想到实际问题上,项目中对表进行分区的这个表是一个操作日志表,记录用户对系统业务操作的记录,操作日志记录每天产生的量还是很大的,如果实行分区是否可以更好的管理?那有人可能会说,量大了为什么不水平分表?水平分表不是不可,要是知道操作日志我们只是需要保存一段时间,而不是永久保存,而且量这么大,如果按照时间来作为分表依据,那少说也得要有几个表,而且相对于MySQL单表存储的量是500万条记录,好几个月估计都没这么大的量,所以大可不必去水平分表,所以通过表分区的方式就可以解决问题了,所以两个方案都没有问题,具体选择还得根据实际情况来选择。
什么是表分区?
表分区就是根据一定的规则,将数据保存在同一张表中的不同区中,有点类似于水平分表,数据存在同一个库中的不同表中,只不过表分区的粒度比水平分表要小,表分区可以备份和恢复单个分区的数据。可以对数据更好的管理,一般都是对单条数据进行管理,或者对单个表进行管理,现在能对单个分区进行管理。还能提高查询效率,可以根据查询条件定位数据所在分区,进而可以在分区上进行查找。分区还能将数据存储在不同的物理设备上。
分区模式
RANGE
rang分区,见名知意,就是范围,可以根据一个值的范围选择分区,而这个字段可以是主键或者联合主键中的字段,好比如现在存在一张表,主键由id和create_at两个字段组成的主键,那么选择分区的依据字段就可以是这两个中的其中一个,需要注意的是这个字段的值必须要为整数,如下是通过TO_DAYS()函数对create_at字段进行取天数,所以符合要求。其次就是分区是由小往下,好比使用if…else结构对一个范围进行选择分支,从上往下范围是从小往大的,如果没有合适的分区就会报错。
CREATE TABLE USER(
ID INT PRIMARY KEY,
CREATE_AT DATETIME COMMENT '创建时间'
)ENGINE = InnoDB PARTITION BY RANGE (TO_DAYS(create_at))
PARTITIONS 2
(PARTITION `p20210601` VALUES LESS THAN (738307) ,
PARTITION `p20210701` VALUES LESS THAN (738337));
LIST
LIST分区,见名知意,就是依据字段是否存在一个LIST中,好比MySQL的IN,假如现在存在一个用户表,根据用户性别字段sex进行分区。
CREATE TABLE USER(
ID INT PRIMARY KEY,
SEX TINYINT(1) COMMENT '性别'
)ENGINE = InnoDB PARTITION BY LIST (sex)
PARTITIONS 2
(PARTITION `p20210601` VALUES IN (0) ,
PARTITION `p20210701` VALUES IN (1));
案例中都是单值的,也可以根据实际需要填入多个值。
HASH
HASH分区,见名知意,就是通过分区字段进行HASH计算,然后将数据落地到对应分区中,假设根据ID字段去进行HASH计算,然后将数据落入到计算到的分区中。
CREATE TABLE USER(
ID INT PRIMARY KEY
)ENGINE = InnoDB PARTITION BY HASH (ID)
PARTITIONS 2;
KEY
KEY分区和HASH分区有点相似,但是KEY支持的数据类型比HASH多,支持除text、blob之外的所以数据类型。KEY分区不允许使用用户自定义的表达式进行分区。KEY分区使用系统提供的HASH函数进行分区。
当表中存在主键或者唯一索引时,如果创建 KEY 分区时没有指定字段系统默认会首选主键列作为分区字段,如果不存在主键列会选择非空唯一索引列作为分区字段。
COLUMNS
COLUMNS分区是5.5开始引入的分区功能,COLUMNS分区包含RANGE COLUMN和LIST COLUMN分区,这两中分区支持整形、日期、字符串;
RANGE COLUMN类似于RANGE只是它支持的数据类型更多,并且省略了一些函数转换,就好比RANGE在对日期类型字段分区时需要通过函数去取整数,而RANGE COLUMN不需要了,可以直接写yyyy-MM-dd格式的日期。
LIST COLUMN分区类似于LIST,但它支持的数据类型比LIST分区更多。
总结
通过学习了解MySQL的表分区,在往后的开发中当遇到需求时能有更多的解决方案。相信大家看完MySQL的分区之后应该和我一样感到惊讶,原来还有这么多我们不知道的MySQL的隐藏功能!