MySQL- 技术专题 - 分区表和合并表详解
分区表是MySQL5.1之后的新特性,MySQL合并表已经存在很长时间了。这篇文章主要介绍这两个概念以及他们基本的操作。
一.合并表
合并表说实话一种将要被淘汰的技术,但是掌握了合并表的概念再去看分区表就比较容易理解一点。
合并表其实就是合并了多个子表的逻辑表,子表使用了myisam存储引擎物理子表,合并表使用merge存储引擎,逻辑表和子表的结构完全相同(包括字段、索引等)。
删除一个合并表,它的子表不会受任何影响,而如果删除其中一个子表则可能会有不同的后果,这要视操作系统而定。
下面我们进行实操一下:创建量两张物理子表t1和t2,然后创建他们俩的合并表。
在上面我们进行了一些初始化操作。而且我们在创建合并表的时候,指定了insert_method为last,意思就是在最后一张物理表的末尾插入真实数据,这里最后一张真实物理表就是t2。此时我们插入一个数据5会发现:t1没有,t2有。
合并表的内容很简单,也很容易理解。既然表能合并肯定也能分开。我们接着看分区表:
二.分区表
分区表就是把一张表分开,对用户来说,分区表是一个独立的逻辑表,但是底层由多个物理子表组成。实现分区的代码实际上是对一组底层表的句柄对象的封装。对分区表的请求,都会通过句柄对象转化成对存储引擎的接口调用。分区表的每一个分区都是有索引的独立表。
分区表发挥大作用的场景:
(1)表非常大以至于无法全部都放在内存中,或者只在表的最后部分有热点数据,其他均是历史数据。
(2)分区表的数据更容易维护。
(3)分区表的数据可以分布在不同的物理设备上。
(4)可以使用分区表来避免某些特殊的瓶颈,例如InnoDB单个索引的互斥访问。
(5)如果需要,还可以备份和恢复独立的分区,这在非常大的数据集的场景下效果非常好。
分开的方式有三种:
(1)水平分区:根据行切分,也就是把记录分开。
(2)垂直分区:根据列切分,也就是把字段分开。
(3)复合分区:水平分区和垂直分区的结合。
我们按照这两种方式来实际操作一下:
1、水平分区
(1)range分区
range分区是基于连续的范围值。
在这里需要注意的是,alter形式删除分区比delete形式更加的高效。一般都是基于日期时间进行分区。
(2)List分区
range分区是基于连续的范围,list是基于确定值的范围,就好比集合。
这种不是指的范围,而是指的具体的值,10号和20在n1分区,30在n2分区。
(3)Hash分区
hash分区指的是根据hash运算的模,最终确定在哪一个分区。比如2020/4=0,就落在分区0上。
此时我们2020/4=0,就会保存在分区0中。
(4)线性Hash分区
线性hash指的是使用2的幂运算法则。运算起来比较麻烦。但是优点是可以使得数据分布均匀。举个例子。假设分区个数num=6,N表示数据最终存储的分区:
第一步:V = power(2, ceiling(log(2, num))),log是计算NUM以2为底的对数,ceiling()向上取整,power()是取2的次方值;
第二步:N=values&(V-1),&位与运算,
第三步:while N>=num,此时N =N & (CEIL(V/ 2) - 1)
比如插入2020-01-20,V=8,N=(2020)& (8-1)=4。4<6,所以保存在分区4。
代码就不演示了,区别就是by hash换成by linear hash。
2、垂直分区
垂直分区比较少,直接通过key字段名进行划分即可。
垂直分区相当简单。
3、复合分区
上面介绍了水平和复合的方式,复合分区的方式是进行组合。你可以随意搭配。这里演示一种。
父分区使用list,子分区使用垂直分区。
在这里介绍了分区表的一些概念和基础的使用方法。其实分区表也有很多限制。
分区表的限制:
(1)一个表最多只能有1024个分区。
(2)如果分区字段中有主键或者唯一索引的列,那么所有主键列和唯一索引列都必须包含进来。
(3)分区表中无法使用外键约束。
(4)所有分区都必须使用相同的存储引擎。
(5)某些存储引擎不支持分区。比如说merge、InnoDB、CSV、联合存储引擎等。
MERGE存储引擎。 用户定义的分区和MERGE 存储引擎不兼容。分区表无法合并。
联合存储引擎。 FEDERATED不支持 分区表; 不可能创建分区 FEDERATED表。
CSV存储引擎。 CSV不支持使用存储引擎的分区表; 不可能创建分区CSV表。
InnoDB存储引擎。 InnoDB外键和MySQL分区不兼容。分区 InnoDB表不能有外键引用,也不能有外键引用的列。InnoDB具有或由外键引用的表不能分区。
(6)对于MyISAM表,使用分区表时需要打开更多的文件描述符。
三.分区表的原理
MYSQL分区后每个分区成了独立的文件,虽然从逻辑上还是一张表其实已经分成了多张独立的表,从“information_schema.INNODB_SYS_TABLES”系统表可以看到每个分区都存在独立的TABLE_ID,由于Innodb数据和索引都是保存在".ibd"文件当中(从INNODB_SYS_INDEXES系统表中也可以得到每个索引都是对应各自的分区(primary key和unique也不例外),所以分区表的索引也是随着各个分区单独存储。
在INNODB_SYS_INDEXES系统表中type代表索引的类型;
0 : 一般的索引,
1 : (GEN_CLUST_INDEX)不存在主键索引的表,会自动生成一个6个字节的标示值,
2 : unique索引,
3:primary索引;所以当我们在分区表中创建索引时其实也是在每个分区中创建索引,每个分区维护各自的索引(其实也就是local index);
对于一般的索引(非主键或者唯一)没什么问题由于索引树中只保留了索引key和主键key(如果存在主键则是主键的key否则就是系统自动生成的6个的key)不受分区的影响;但是如果表中存在主键就不一样了,虽然在每个分区文件中都存在主键索引但是主键索引需要保证全局的唯一性就是所有分区中的主键的值都必须唯一(唯一键也是一样的道理),所以在创建分区时如果表中存在主键或者唯一键那么分区列必须包含主键或者唯一键的部分或者全部列(全部列还好理解,部分列也可以个人猜测是为了各个分区和主键建立关系),由于需要保证全局性又要保证插入数据更新数据到具体的分区所以就需要将分区和主键建立关系,由于通过一般的索引进行查找其它非索引字段需要通过主键如果主键不能保证全局唯一性的话那么就需要去每个分区查找了,这样性能可想而知。
To enforce the uniqueness we only allow mapping of each unique/primary key value to one partition.If we removed this limitation it would mean that for every insert/update we need to check in every partition to verify that it is unique. Also PK-only lookups would need to look into every partition.
索引方式:
性能依次降低
1.主键分区
主键分区即字段是主键同时也是分区字段,性能最好
2. 部分主键+分区索引
使用组合主键里面的部分字段作为分区字段,同时将分区字段建索引
3.分区索引
没有主键,只有分区字段且分区字段建索引
4.分区+分区字段没有索引
只建了分区,但是分区字段没有建索引
分区系列文章:
RANGE分区:http://www.cnblogs.com/chenmh/p/5627912.html
LIST分区:http://www.cnblogs.com/chenmh/p/5643174.html
COLUMN分区:http://www.cnblogs.com/chenmh/p/5630834.html
HASH分区:http://www.cnblogs.com/chenmh/p/5644496.html
KEY分区:http://www.cnblogs.com/chenmh/p/5647210.html
子分区:http://www.cnblogs.com/chenmh/p/5649447.html
指定各分区路径:http://www.cnblogs.com/chenmh/p/5644713.html
分区介绍总结:http://www.cnblogs.com/chenmh/p/5623474.html
总结
因为每一个表都需要有主键这样可以减少很多锁的问题,由于上面讲过主键需要解决全局唯一性并且在插入和更新时可以不需要去扫描全部分区,造成主键和分区列必须存在关系;所以最好的分区效果是使用主键作为分区字段其次是使用部分主键作为分区字段且创建分区字段的索引,其它分区方式都建议不采取。
评论