Mysql查询优化之表分区

459 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

最近项目中某个查询接口遇到了速度瓶颈,当查询的主表数据量达到180万条左右的时候,光是执行查询语句就要2秒以上,并且该表还会以每天64万条数据量的速度新增,所有该接口的查询效率势必需要优化。

通过网上查找资料,最终决定将主表进行分区来提升查询速度。

数据库表分区

数据库分区是一种物理数据库设计技术。虽然分区技术可以实现很多效果,但其主要目的是为了在特定的SQL操作中减少数据读写的总量以缩减sql语句的响应时间,同时对于应用来说分区完全是透明的。

MYSQL的分区主要有两种形式:水平分区和垂直分区

水平分区(HorizontalPartitioning)

这种形式的分区是对根据表的行进行分区,通过这样的方式不同分组里面的物理列分割的数据集得以组合,从而进行个体分割(单分区)或集体分割(1个或多个分区)。 所有在表中定义的列在每个数据集中都能找到,所以表的特性依然得以保持。水平分区一定要通过某个属性列来分割。常见的比如年份,日期等。

垂直分区(VerticalPartitioning)

这种分区方式一般来说是通过对表的垂直划分来减少目标表的宽度,使某些特定的列被划分到特定的分区,每个分区都包含了其中的列所对应所有行。

Mysql表分区类型

根据所使用的不同分区规则可以分成几大分区类型。

RANGE 分区:

基于属于一个给定连续区间的列值,把多行分配给分区。

LIST 分区:

类似于按RANGE分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择。

HASH分区:

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

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

复合分区:

基于RANGE/LIST 类型的分区表中每个分区的再次分割。子分区可以是 HASH/KEY 等类型。

创建分区

由于这个接口查询的是某个机房某日一整天的环境数据变化趋势,所以这里我选用日期的月份来进行分区,这样主表将会被分为12个区,每次查询的时候相当于在总数量的1/12里去找所要查询的数据。

以下是表分区的sql脚本:

alter table record_cabinet_env partition by range(month(cur_time))(
partition month1 values less than(2),
partition month2 values less than(3),
partition month3 values less than(4),
partition month4 values less than(5),
partition month5 values less than(6),
partition month6 values less than(7),
partition month7 values less than(8),
partition month8 values less than(9),
partition month9 values less than(10),
partition month10 values less than(11),
partition month11 values less than(12),
partition month12 values less than(13)
);

验证查询效率

首先执行原sql语句,看看耗时:

image.png

可以看到,未用到分区的查询语句耗时接近2秒了,接着看看采用分区的查询语句:

image.png

效果还是很明显的,采用了分区的查询语句相对于未采用分区的查询语句,效率提升了62%,分区的效果还是非常显著的。