手动分表 V.S 分区表
比如,按年份划分,分别创建普通表t_2017、t_2018、t_2019等。手工分表也要找到需要更新的所有分表,然后依次执行更新。
性能上和分区表没有差别。
- 分区表由server层决定使用哪个分区
- 手动分表由应用层代码决定使用哪个分表
所以从引擎层看,也没啥区别。
两种方式的区别,主要在server层。server层的分区表一个严重问题就是打开表的行为。
分区策略
第一次访问一个分区表时,MySQL需要把所有分区都访问一遍。
一个典型的报错场景:若一个分区表的分区很多,比如超过1000,而MySQL启动时,open_files_limit参数默认值1024,则在访问该表时,由于需要打开所有文件,导致打开表文件的个数超过了上限而报错。
比如对一个包含很多分区的表,执行insert直接报错:
这条insert其实只需要访问一个分区,但语句报错了。这个表是MyISAM,如果使用InnoDB,不会出现该问题。
MyISAM分区表使用通用分区策略(generic partitioning),每次访问分区都由server层控制。通用分区策略,是MySQL一开始支持分区表的时候就存在的代码,在文件管理、表管理的实现上很粗糙,性能问题很严重。
MySQL 5.7.9开始,InnoDB引入本地分区策略(native partitioning),在InnoDB内部自己管理打开分区的行为。
MySQL 5.7.17开始,将MyISAM分区表标记为deprecated。
MySQL 8.0开始,已经禁止创建MyISAM分区表,只允许创建已经实现了本地分区策略的引擎。
目前只有InnoDB和NDB引擎支持本地分区策略。
分区表的server层行为
对于server层,一个分区表就只是一个表。
如图,分别是该例的操作序列和执行结果图。
- 分区表的MDL锁
session_1 | session_2 |
begin; select * from tt where ftime=‘2018-4-1’; |
|
alter table tt truncate partition p_2017 (阻塞) |
show processlist
虽然session2只需操作p_2107分区,但因为session1持有整个表tt的MDL锁,导致session2的alter语句被阻塞。
所以分区表在做DDL时,影响会更大。若使用的普通分表,则当你在truncate一个分表时,肯定不会跟另外一个分表上的查询语句,出现MDL锁冲突。
小结
在server层,认为这是同一张表,因此所有分区共用同一MDL锁
在引擎层,认为这是不同表,因此MDL锁之后的执行过程,会根据分区表规则,只访问必要的分区。
什么是必要的分区?
根据SQL语句中的where条件,结合分区规则。比如上面的where ftime=‘2018-4-1’,根据分区规则year函数算出来的值是2018,那么就会落在p_2019分区。
但若这个where 条件改成 where ftime>='2018-4-1',虽然查询结果相同,但这时根据where条件,就要访问p_2019和p_others俩分区。
若查询语句的where条件没有分区key,就只能访问所有分区了。当然,这并非分区表的问题。即使是使用业务分表,where条件中没有使用分表的key,也必须访问所有的分表。
分区表的应用场景
一大优势是对业务透明,相对于用户分表来说,使用分区表的业务代码更简洁。还有,分区表可以很方便的清理历史数据。
如果一项业务跑的时间足够长,往往就会有根据时间删除历史数据的需求。这时按时间分区的分区表,就可直接通过alter table t drop partition …这个语法删掉分区,从而删掉过期的历史数据。
alter table t drop partition …是直接删除分区文件,跟drop普通表类似。与delete相比,优势是速度快、对系统影响小。
需要注意的是,我是以范围分区(range)为例和你介绍的。实际上,MySQL还支持hash分区、list分区等分区方法。
实际使用时,分区表跟用户分表,有两个问题:
第一次访问时,需要访问所有分区
共用MDL锁
因此,如果要使用分区表,就不要创建太多分区。我见过一个用户做了按天分区策略,然后预先创建了10年的分区。这种情况下,访问分区表的性能自然是不好的。这里有两个问题:
分区并不是越细越好
单表或单分区的数据一千万行,只要没有特别大的索引,对于现在的硬件能力来说都已是小表
分区不要提前预留太多,在使用之前预先创建即可
比如,如果是按月分区,每年年底时再把下一年度的12个新分区创建上即可。对于没有数据的历史分区,及时drop
分区表的其他问题,比如查询需要跨多个分区取数据,查询性能就会比较慢,基本上就不是分区表本身的问题,而是数据量或说使用方式问题。
如果你的团队已经维护了成熟的分库分表中间件,用业务分表,对业务开发同学没有额外的复杂性,对DBA也更直观,自然更好。