笔者以为,分库分表确实好的。可是,动不动搞分库分表,太麻烦了。分库分表虽然是提升数据库性能的常规办法,可是太麻烦了。因此,尝试研究mysql的分区到底如何。html
以前写过一篇文章,http://www.cnblogs.com/wangtao_20/p/7115962.html 讨论过订单表的分库分表,折腾起来工做量挺大的,须要多少技术去折腾。作过的人才知道有多麻烦mysql
要按照什么字段切分,切分数据后,要迁移数据;分库分表后,会涉及到跨库、跨表查询,为了解决查询问题,又得用其余方案来弥补(好比为了应对查询得作用户订单关系索引表)。工做量确实不小。算法
从网上也能够看到,大部分实施过的人(成功的)的经验总结:水平分表,不是必须的,能不作,尽可能不作。sql
一、探讨分区的原理数据库
了解分区到底在作什么,存储的数据文件有什么变化,这样知道分区是怎么提升性能的。服务器
实际上:每一个分区都有本身独立的数据、索引文件的存放目录。本质上,一个分区,实际上对应的是一个磁盘文件。因此分区越多,文件数越多。架构
如今使用innodb存储较多,mysql默认的存储引擎从mysiam变为了innodb了。并发
以innodb来讨论:函数
innodb存储引擎一张表,对应两个文件:表名.ibd、表名.frm。性能
若是分区后,一个分区就单独一个ibd文件,以下图:
将fs_punch_in_log表拆分红4个分区,上图中看到,每一个分区就变成一个单独的数据文件了。mysql会使用"#p#p1"来命名数据文件,1是分区的编号。总共4个分区,最大值是4。
分表的原理,实际上相似,一个表对应一个数据文件。分表后,数据分散到多个文件去了。性能就提升了。
分区后的查询语句
语句仍是按照原来的使用。但为了提升性能。仍是尽可能避免跨越多个分区匹配数据。
以下图,因为表是按照id字段分区的。数据分散在多个分区。如今使用user_id做为条件去查询。mysql不知道到底分配在哪一个分区。因此要去所有分区扫描,若是每一个分区的数据量大,这样就耗时很长了。
分区思路和分区语句
id字段的值范围来分区:在1-2千万分到p0分区,4千万到-6千万p1分区。6千万到8千万p2分区。依此推算下去。这样能够分红不少的分区了。
为了保持线性扩容方便。那么只能使用range范围来算了。
sql以下
CREATE TABLE `fs_punch_in_log` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键自增' , `user_id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '签到的用户id' , `punch_in_time` int(10) UNSIGNED NULL DEFAULT NULL COMMENT '打卡签到时间戳' , PRIMARY KEY (`id`) )
partition BY RANGE (id) (
PARTITION p1 VALUES LESS THAN (40000000),
PARTITION p2 VALUES LESS THAN (80000000),
PARTITION p3 VALUES LESS THAN (120000000),
PARTITION p4 VALUES LESS THAN MAXVALUE
);
以上语句通过笔者测验,注意点:
状况:若是表结构已经定义好了,里面有数据了,怎么进行分区呢?使用alter语句修改便可,通过笔者测验了。
ALTER TABLE `fs_punch_in_log` PARTITION BY RANGE (id) ( PARTITION p1 VALUES LESS THAN (40000000), PARTITION p2 VALUES LESS THAN (80000000), PARTITION p3 VALUES LESS THAN (120000000), PARTITION p4 VALUES LESS THAN MAXVALUE )
注:因为表里面已经存在数据了,进行从新分区,mysql会把数据按照分区规则从新移动一次,生成新的文件。若是数据量比较大,耗时间比较长。
2、四种分区类型
mysql分区包括四种分区方式:hash分区、按range分区、按key分区、list分区。
四种有点多,实际上,为了好记,把类再缩小点,就两大类方式进行分区:一种是计算hash值、一种是按照范围值。
其实分库分表的时候,也会用到两大类,hash运算分、按值范围分。
一、HASH分区
有常规hash和线性hash两种方式。
怎么算出新插入一行数据,须要放到分区1,仍是分区4呢? id的值除以4,余下1,这一行数据就分到1分区。
常规hash,可让数据很是平均的分布每个分区。好比分为4个取,取余数,余数老是0-3之间的值(总到这几个分区去)。分配打散比较均匀。
可是也是有缺点的:因为分区的规则在建立表的时候已经固定了,数据就已经打散到各个分区。如今若是须要新增分区、减小分区,运算规则变化了,原来已经入库的数据,就须要适应新的运算规则来作迁移。
实际上在分库分表的时候,使用hash方式,也是数据量迁移的问题。不过还好。
针对这个状况,增长了线性hash的方式。
实际上线性hash算法,就是咱们memcache接触到的那种一致性hash算法。使用虚拟节点的方式,解决了上面hash方式分区时,当新增长分区后,涉及到的数据须要大量迁移的问题。也不是不须要迁移,而是须要迁移的数据量小。
在技术实现上:线性哈希功能使用的一个线性的2的幂(powers-of-two)运算法则,而常规哈希使用的是求哈希函数值的模数。
线性哈希分区和常规哈希分区在语法上的惟一区别在于,在“PARTITION BY”子句中添加“LINEAR”关键字。
二者也有有相同的地方:
考虑之后迁移数据量少,使用线性hash。
二、按照range范围分区
范围分区,能够自由指定范围。好比指定1-2000是一个分区,2000到5000千又是一个分区。范围彻底能够本身定。后面我要添加新的分区,很容易吗?
三、按key分区
相似于按HASH分区,区别在于KEY分区只支持计算一列或多列,且MySQL服务器提供其自身的哈希函数。必须有一列或多列包含整数值。
四、按list方式分区
能够把list当作是在range方式的基础上的改进版。list和range本质都是基于范围,本身控制范围。
range是列出范围,好比1-2000范围算一个分区,这样是一个连续的值。
而list分区方式是枚举方式。能够指定在1,5,8,9,20这些值都分在第一个分区。从list单词的字面意思命名暗示就是列表,指定列表中出现的值都分配在第几个分区。
3、如何根据业务选择分区类型
一、什么时候选择分区,什么时候选择分表
分表仍是比分区更加灵活。在代码中能够本身控制。通常分表会与分库结合起来使用的。在进行分表的时候,顺带连分库方案也一块儿搞定了。
分表分库,性能和并发能力要比分区要强。分表后,有个麻烦点:本身须要修改代码去不一样的表操做数据。