本篇文章给大家谈谈mysql数据库分表分库的策略,以及mysql数据库分表分库的策略有哪些的知识点,同时本文还将给你拓展MyBatis如何实现Mysql数据库分库分表的实例详解、MyBatis实现My
本篇文章给大家谈谈mysql数据库分表分库的策略,以及mysql数据库分表分库的策略有哪些的知识点,同时本文还将给你拓展MyBatis如何实现Mysql数据库分库分表的实例详解、MyBatis实现Mysql数据库分库分表操作和总结(推荐)、MyCat:对MySQL数据库进行分库分表、mysql 分表分库策略等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:- mysql数据库分表分库的策略(mysql数据库分表分库的策略有哪些)
- MyBatis如何实现Mysql数据库分库分表的实例详解
- MyBatis实现Mysql数据库分库分表操作和总结(推荐)
- MyCat:对MySQL数据库进行分库分表
- mysql 分表分库策略
mysql数据库分表分库的策略(mysql数据库分表分库的策略有哪些)
一、先说一下为什么要分表:
当一张的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,有可能会死在那儿了。分表的目的就在于此,减小数据库的负担,缩短查询时间。日常开发中我们经常会遇到大表的情况,所谓的大表是指存储了百万级乃至千万级条记录的表。这样的表过于庞大,导致数据库在查询和插入的时候耗时太长,性能低下,如果涉及联合查询的情况,性能会更加糟糕。分表和表分区的目的就是减少数据库的负担,提高数据库的效率,通常点来讲就是提高表的增删改查效率。数据库中的数据量不一定是可控的,在未进行分库分表的情况下,随着时间和业务的发展,库中的表会越来越多,表中的数据量也会越来越大,相应地,数据操作,增删改查的开销也会越来越大;另外,由于无法进行分布式式部署,而一台服务器的资源(cpu、磁盘、内存、IO等)是有限的,最终数据库所能承载的数据量、数据处理能力都将遭遇瓶颈。
MysqL执行一个sql的过程如下:
1、接收到sql;
2、把sql放到排队队列中;
3、执行sql;
4、返回执行结果。
在这个执行过程中最花时间在什么地方呢?第一,是排队等待的时间,第二,sql的执行时间。其实这两个是一回事,等待的同时,肯定有sql在执行。所以我们要缩短sql的执行时间。
MysqL中有一种机制是表锁定和行锁定,为什么要出现这种机制,是为了保证数据的完整性,我举个例子来说吧,如果有二个sql都要修改同一张表的同一条数据,这个时候怎么办呢,是不是二个sql都可以同时修改这条数据呢?很显然MysqL对这种情况的处理是,一种是表锁定(myisam存储引擎),一个是行锁定(innodb存储引擎)。表锁定表示你们都不能对这张表进行操作,必须等我对表操作完才行。行锁定也一样,别的sql必须等我对这条数据操作完了,才能对这条数据进行操作。如果数据太多,一次执行的时间太长,等待的时间就越长,这也是我们为什么要分表的原因。
二、分表的方案
1、集群
1,做MysqL集群,有人会问MysqL集群,根分表有什么关系吗?虽然它不是实际意义上的分表,但是它启到了分表的作用,做集群的意义是什么呢?为一个数据库减轻负担,说白了就是减少sql排队队列中的sql的数量,举个例子:有10个sql请求,如果放在一个数据库服务器的排队队列中,他要等很长时间,如果把这10个sql请求,分配到5个数据库服务器的排队队列中,一个数据库服务器的队列中只有2个,这样等待时间是不是大大的缩短了呢?这已经很明显了。所以我把它列到了分表的范围以内,我做过一些MysqL的集群:
linux MysqL proxy 的安装,配置,以及读写分离
MysqL replication 互为主从的安装及配置,以及数据同步
优点:扩展性好,没有多个分表后的复杂操作(PHP代码)
缺点:单个表的数据量还是没有变,一次操作所花的时间还是那么多,硬件开销大。
2、分表
分表的2种方式:
讲字段拆分到不同表中,将原表中的string类型字段拆分到其他表,能够加快主表的查询。
2.垂直分割就是按字段分.
一个数据库有3000W用户记录.包括字段id,user,password,first_name,last_name,email,addr,等几十字段.用户登录时需要user,password字段,需要查找user,password字段比较慢,若是把它user,password单建立一表,速度会快.用户的其它字段独立再建立一个表.这仅是一个例子.
把数据拆分到多个同样结构的表中。
水平.就是按记录分.一个数据库有3000W用户记录.处理速度比较慢.这时可以把3000W.分成五份.每份都是600W.分别放在不同的机器上.
水平分表:
就是预先估计会出现大数据量并且访问频繁的表,将其分为若干个表,这种预估大差不差的,论坛里面发表帖子的表,时间长了这张表肯定很大,几十万,几百万都有可能。聊天室里面信息表,几十个人在一起一聊一个晚上,时间长了,这张表的数据肯定很大。像这样的情况很多。所以这种能预估出来的大数据量表,我们就事先分出个N个表,这个N是多少,根据实际情况而定。以聊天信息表为例:
我事先建100个这样的表,message_00,message_01,message_02……….message_98,message_99.然后根据用户的ID来判断这个用户的聊天信息放到哪张表里面,可以用求余的方式来获得
3、实际应用中:
需要把垂直分表和水平分表结合起来使用,如果一个数据库有3000w用户的话,可以先考虑垂直拆,拆完之后在进行水平拆分。
就是先将其他字段拆分到user_info表中,用户主表只留下用户id,密码,用户名等关键字段。
之后在进行水平拆分,将用户和用户信息表分为多个同样结构的表。
接下来我们来看下MysqL在分表存储数据的时候是如何运作的:
1、简单的MysqL主从复制:
MysqL的主从复制解决了数据库的读写分离,并很好的提升了读的性能,其图如下:
其主从复制的过程如下图所示:
但是,主从复制也带来其他一系列性能瓶颈问题:
1. 写入无法扩展
2. 写入无法缓存
3. 复制延时
4. 锁表率上升
5. 表变大,缓存率下降
那问题产生总得解决的,这就产生下面的优化方案,一起来看看。
2、MysqL垂直分区
如果把业务切割得足够独立,那把不同业务的数据放到不同的数据库服务器将是一个不错的方案,而且万一其中一个业务崩溃了也不会影响其他业务的正常进行,并且也起到了负载分流的作用,大大提升了数据库的吞吐能力。经过垂直分区后的数据库架构图如下:
然而,尽管业务之间已经足够独立了,但是有些业务之间或多或少总会有点联系,如用户,基本上都会和每个业务相关联,况且这种分区方式,也不能解决单张表数据量暴涨的问题,因此为何不试试水平分割呢?
3、MysqL水平分片(Sharding)
这是一个非常好的思路,将用户按一定规则(按id哈希)分组,并把该组用户的数据存储到一个数据库分片中,即一个sharding,这样随着用户数量的增加,只要简单地配置一台服务器即可,原理图如下:
如何来确定某个用户所在的shard呢,可以建一张用户和shard对应的数据表,每次请求先从这张表找用户的shard id,再从对应shard中查询相关数据,如下图所示:
单库单表
单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到。
单库多表
随着用户数量的增加,user表的数据量会越来越大,当数据量达到一定程度的时候对user表的查询会渐渐的变慢,从而影响整个DB的性能。如果使用MysqL,还有一个更严重的问题是,当需要添加一列的时候,MysqL会锁表,期间所有的读写操作只能等待。
可以通过某种方式将user进行水平的切分,产生两个表结构完全一样的user_0000,user_0001等表,user_0000 + user_0001 + …的数据刚好是一份完整的数据。
多库多表
随着数据量增加也许单台DB的存储空间不够,随着查询量的增加单台数据库服务器已经没办法支撑。这个时候可以再对数据库进行水平区分。
分库分表规则
设计表的时候需要确定此表按照什么样的规则进行分库分表。例如,当有新用户时,程序得确定将此用户信息添加到哪个表中;同理,当登录的时候我们得通过用户的账号找到数据库中对应的记录,所有的这些都需要按照某一规则进行。
路由
通过分库分表规则查找到对应的表和库的过程。如分库分表的规则是user_id mod 4的方式,当用户新注册了一个账号,账号id的123,我们可以通过id mod 4的方式确定此账号应该保存到User_0003表中。当用户123登录的时候,我们通过123 mod 4后确定记录在User_0003中。
分库分表产生的问题,及注意事项
1. 分库分表维度的问题
假如用户购买了商品,需要将交易记录保存取来,如果按照用户的纬度分表,则每个用户的交易记录都保存在同一表中,所以很快很方便的查找到某用户的 购买情况,但是某商品被购买的情况则很有可能分布在多张表中,查找起来比较麻烦。反之,按照商品维度分表,可以很方便的查找到此商品的购买情况,但要查找 到买人的交易记录比较麻烦。
所以常见的解决方式有:
a.通过扫表的方式解决,此方法基本不可能,效率太低了。
b.记录两份数据,一份按照用户纬度分表,一份按照商品维度分表。
c.通过搜索引擎解决,但如果实时性要求很高,又得关系到实时搜索。
2. 联合查询的问题
联合查询基本不可能,因为关联的表有可能不在同一数据库中。
3. 避免跨库事务
避免在一个事务中修改db0中的表的时候同时修改db1中的表,一个是操作起来更复杂,效率也会有一定影响。
4. 尽量把同一组数据放到同一DB服务器上
例如将卖家a的商品和交易信息都放到db0中,当db1挂了的时候,卖家a相关的东西可以正常使用。也就是说避免数据库中的数据依赖另一数据库中的数据。
一主多备
在实际的应用中,绝大部分情况都是读远大于写。MysqL提供了读写分离的机制,所有的写操作都必须对应到Master,读操作可以在 Master和Slave机器上进行,Slave与Master的结构完全一样,一个Master可以有多个Slave,甚至Slave下还可以挂 Slave,通过此方式可以有效的提高DB集群的 QPS.
所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。
此外,可以看出Master是集群的瓶颈,当写操作过多,会严重影响到Master的稳定性,如果Master挂掉,整个集群都将不能正常工作。
所以,1. 当读压力很大的时候,可以考虑添加Slave机器的分式解决,但是当Slave机器达到一定的数量就得考虑分库了。 2. 当写压力很大的时候,就必须得进行分库操作。
MysqL使用为什么要分库分表
可以用说用到MysqL的地方,只要数据量一大,马上就会遇到一个问题,要分库分表.
这里引用一个问题为什么要分库分表呢?MysqL处理不了大的表吗?
其实是可以处理的大表的.我所经历的项目中单表物理上文件大小在80G多,单表记录数在5亿以上,而且这个表
属于一个非常核用的表:朋友关系表.
但这种方式可以说不是一个最佳方式. 因为面临文件系统如Ext3文件系统对大于大文件处理上也有许多问题.
这个层面可以用xfs文件系统进行替换.但MysqL单表太大后有一个问题是不好解决: 表结构调整相关的操作基
本不在可能.所以大项在使用中都会面监着分库分表的应用.
从Innodb本身来讲数据文件的Btree上只有两个锁,叶子节点锁和子节点锁,可以想而知道,当发生页拆分或是添加
新叶时都会造成表里不能写入数据.
所以分库分表还就是一个比较好的选择了.
那么分库分表多少合适呢?
经测试在单表1000万条记录一下,写入读取性能是比较好的. 这样在留点buffer,那么单表全是数据字型的保持在
800万条记录以下,有字符型的单表保持在500万以下.
如果按 100库100表来规划,如用户业务:
500万*100*100 = 50000000万 = 5000亿记录.
心里有一个数了,按业务做规划还是比较容易的.
MyBatis如何实现Mysql数据库分库分表的实例详解
这篇文章主要介绍了mybatis实现
前言
作为一个数据库,作为数据库中的一张表,随着用户的增多随着时间的推移,总有一天,数据量会大到一个难以处理的地步。这时仅仅一张表的数据就已经超过了千万,无论是查询还是修改,对于它的操作都会很耗时,这时就需要进行数据库切分的操作了。
MyBatis实现分表最简单步骤
既然文章的标题都这么写了,不如直接上干货来的比较实际,我们就先来看看如何实现最简单的分表。
1、我们模拟用户表数据量超过千万(虽然实际不太可能)
2、用户表原来的名字叫做user_tab,我们切分为user_tab_0和user_tab_1(实际也可能不是这么随意的名字),这样就能把原来千万的数据分离成两个百万的数据量的两张表了。
3、如何操作这两张表呢?我们利用userId也就是用户的唯一标识进行区分。
4、userId%2 == 0的用户操作表user_tab_0,同理userId%2 == 1的用户操作表user_tab_1
5、那么在MyBatis中sql语句如何实现呢?下面是举例查询一个用户的sql语句
<select id="getUser" parameterType="java.util.Map" resultType="UserDO"> SELECT userId, name FROM user_tab_#{tabIndex} WHERE userId = #{userId} </select>
其中我们传入了两个参数tabIndex和userId,tabIndex就是需要操作表的标示值(0或1),这样如果需要查询userId为5的用户,那么最终出现的sql语句就会是:
SELECT userId, name FROM user_tab_1 WHERE userId = 5
其他多余的DAO服务和实现我这里就不多展示了,相信聪明的你肯定会的。
以上就是最简单的实现,不需要多余的框架,不需要任何的插件也就满足了分表的要求。
上面基本上就是所有实现的内容了,下面就要开始详细说说分离的细节了,看热闹的基本可以散了。
我将从下面几个角度分别来说说。我尽可能用最简单的白话来说。
分离的方式
切分的方式主要有两种,水平切分和垂直切分。
1、水平切分
简单的说就是,把一张表分离成几张一模一样的表,然后表的名字不同。就和上面最简单的例子一样。
这种切分适合于一张表的数据量过大而导致操作时间变慢的情况,如保存的一些记录表。
2、垂直切分
把不同的业务模块分成不同的数据库,这些业务模块直接最好是0耦合(简单的说就是毫无关系)。
这主要是适合数据量普遍较大,而且业务场景比较分散,互相之间没有逻辑关系的情况。
分离的策略
具体的策略有很多种,你也可以设计你自己的,普遍的策略有下面几种,只是列举就不具体展开了。
1、“%”取模,也就是上面例子中实现的,也是最简单的一种。
2、MD5哈希
3、移位
4、日期时间(根据不同的日期分表,如一个月一张表,这个月就操作这张表,下个月就下张表)
5、枚举范围(用户1-10000操作第一张表,用户10001-20000操作第二张表)
分离的问题
下面说说最终要的点,导致的问题。
数据库肯定不是你说分就分的。(人家比较有感情的,怎么能说分就分呢?)
正经来说,我列举了下面几个分离只有会导致的问题。
1、添加时主键唯一性的问题;分离之后多张表,就会导致原有的自增长主键不唯一,所以没有办法自增长了,导致问题,解决方案的也是有的,比如单独维护一张主键表专门用来存放当前主键,或者说用别的中间件等。
2、新增时的效率问题,虽然不是个大问题,但是新增肯定会多了计算量嘛,这个问题可以忽略不计。
3、查询所带来的分页问题,分离成多张表之后,分页查询就很困难了,这也考虑到不同的分离用不同的解决方案,总之会产生问题。
4、同理,关联查询,原本一张表关联别的表或者别的表关联一张表,都很简单,但是现在分离之后就难了。
5、事务问题,多张表需要使用分布式事务才能完成原来带有事务的操作。因为原来的事务只是锁一张表现在可能要锁多张了呢。
6、扩展性问题,有的切分策略下,对数据的扩展性其实不好,之后如果有更多的数据来了,是说还能再新建表来扩展吗?
分离的原则
下面总结了几点分离的原则,主要是参考了网络上的,没有任何实际的依据(我也不是个年薪百万的DBA也碰不到那么大的数据去实际检验嘛),所以如果有任何问题也请指出。
1、能不分就不分
2、能分少就不分多
3、多冗余,不关联
4、避免使用分布式事务,主要是太难我也不会啊
5、单表千万记录以内就不分
6、现在不分以后分也来得及
7、扩展,耦合,仔细考虑
实现分离的方式
最后说说分离的方式,现在流行使用的DAO框架是MyBatis,也有很多别的框架。分离的实现主要有下面几种方式。
1、原生实现,就和最上面的例子一样,不需要其他任何的东西,利用原生的框架,自己去控制实现。
优点是:容易控制,掌握主动权。
缺点是:代码量多,需要自己很清楚,修改不方便,不支持复杂的切分,比如切分之后还需要做一些分页查询,还有上面说的主键问题等。
2、插件实现,利用框架本身开发的一些插件,去实现这些插件,然后利用插件去访问数据库,直接实现分离。
优点是:代码量少,实现简单,扩展性好。
缺点是:不易控制,分离方式有限,出现问题难以解决。没有找到特别成熟的插件。
3、中间件实现。利用一些数据库访问的中间件,在访问数据库之前做一些操作使得sql进行相应的变化从而实现分离。
优点是:耦合小,扩展性好,可以解决分布式事务的问题。
确定是:实现比较复杂,需要对中间件进行学习,成本较大。维护也是一个大问题,万一挂掉了。。
总之方式各有千秋,但是考虑到成本上面,第一种几乎是0成本,即可上手,而且比较容易控制,就如同最上面给出的例子一样,而且当前我处理的数据还没有到达那种处处要分离的地步,所以我选择第一种。也推荐使用。如果你找到比较好用的插件或者中间件也可以在评论中推荐。
总结
在实际项目中,我是因为用户的账户记录过多所以不得不进行分离,而且因为账户记录更多的只是新增没有修改和删除,查询也是少数,所以使用了最简单的方式进行分离,也选择了最简单的策略。希望上面的原则策略方式和问题的总结能对你有所帮助,有所参考。如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
以上就是MyBatis如何实现Mysql数据库分库分表的实例详解的详细内容,更多请关注php中文网其它相关文章!
MyBatis实现Mysql数据库分库分表操作和总结(推荐)
这篇文章主要介绍了MyBatis实现MysqL数据库分库分表操作和总结,需要的朋友可以参考下
前言
作为一个数据库,作为数据库中的一张表,随着用户的增多随着时间的推移,总有一天,数据量会大到一个难以处理的地步。这时仅仅一张表的数据就已经超过了千万,无论是查询还是修改,对于它的操作都会很耗时,这时就需要进行数据库切分的操作了。
MyBatis实现分表最简单步骤
既然文章的标题都这么写了,不如直接上干货来的比较实际,我们就先来看看如何实现最简单的分表。
1、我们模拟用户表数据量超过千万(虽然实际不太可能)
2、用户表原来的名字叫做user_tab,我们切分为user_tab_0和user_tab_1(实际也可能不是这么随意的名字),这样就能把原来千万的数据分离成两个百万的数据量的两张表了。
3、如何操作这两张表呢?我们利用userId也就是用户的唯一标识进行区分。
4、userId%2 == 0的用户操作表user_tab_0,同理userId%2 == 1的用户操作表user_tab_1
5、那么在MyBatis中sql语句如何实现呢?下面是举例查询一个用户的sql语句
SELECT userId, name FROM user_tab_#{tabIndex} WHERE userId = #{userId}
其中我们传入了两个参数tabIndex和userId,tabIndex就是需要操作表的标示值(0或1),这样如果需要查询userId为5的用户,那么最终出现的sql语句就会是:
SELECT userId, name FROM user_tab_1 WHERE userId = 5
其他多余的DAO服务和实现我这里就不多展示了,相信聪明的你肯定会的。
以上就是最简单的实现,不需要多余的框架,不需要任何的插件也就满足了分表的要求。
上面基本上就是所有实现的内容了,下面就要开始详细说说分离的细节了,看热闹的基本可以散了。
我将从下面几个角度分别来说说。我尽可能用最简单的白话来说。
分离的方式
切分的方式主要有两种,水平切分和垂直切分。
1、水平切分
简单的说就是,把一张表分离成几张一模一样的表,然后表的名字不同。就和上面最简单的例子一样。
这种切分适合于一张表的数据量过大而导致操作时间变慢的情况,如保存的一些记录表。
2、垂直切分
把不同的业务模块分成不同的数据库,这些业务模块直接最好是0耦合(简单的说就是毫无关系)。
这主要是适合数据量普遍较大,而且业务场景比较分散,互相之间没有逻辑关系的情况。
分离的策略
具体的策略有很多种,你也可以设计你自己的,普遍的策略有下面几种,只是列举就不具体展开了。
1、“%”取模,也就是上面例子中实现的,也是最简单的一种。
2、MD5哈希
3、移位
4、日期时间(根据不同的日期分表,如一个月一张表,这个月就操作这张表,下个月就下张表)
5、枚举范围(用户1-10000操作第一张表,用户10001-20000操作第二张表)
分离的问题
下面说说最终要的点,导致的问题。
数据库肯定不是你说分就分的。(人家比较有感情的,怎么能说分就分呢?)
正经来说,我列举了下面几个分离只有会导致的问题。
1、添加时主键唯一性的问题;分离之后多张表,就会导致原有的自增长主键不唯一,所以没有办法自增长了,导致问题,解决方案的也是有的,比如单独维护一张主键表专门用来存放当前主键,或者说用别的中间件等。
2、新增时的效率问题,虽然不是个大问题,但是新增肯定会多了计算量嘛,这个问题可以忽略不计。
3、查询所带来的分页问题,分离成多张表之后,分页查询就很困难了,这也考虑到不同的分离用不同的解决方案,总之会产生问题。
4、同理,关联查询,原本一张表关联别的表或者别的表关联一张表,都很简单,但是现在分离之后就难了。
5、事务问题,多张表需要使用分布式事务才能完成原来带有事务的操作。因为原来的事务只是锁一张表现在可能要锁多张了呢。
6、扩展性问题,有的切分策略下,对数据的扩展性其实不好,之后如果有更多的数据来了,是说还能再新建表来扩展吗?
分离的原则
下面总结了几点分离的原则,主要是参考了网络上的,没有任何实际的依据(我也不是个年薪百万的DBA也碰不到那么大的数据去实际检验嘛),所以如果有任何问题也请指出。
1、能不分就不分
2、能分少就不分多
3、多冗余,不关联
4、避免使用分布式事务,主要是太难我也不会啊
5、单表千万记录以内就不分
6、现在不分以后分也来得及
7、扩展,耦合,仔细考虑
实现分离的方式
最后说说分离的方式,现在流行使用的DAO框架是MyBatis,也有很多别的框架。分离的实现主要有下面几种方式。
1、原生实现,就和最上面的例子一样,不需要其他任何的东西,利用原生的框架,自己去控制实现。
优点是:容易控制,掌握主动权。
缺点是:代码量多,需要自己很清楚,修改不方便,不支持复杂的切分,比如切分之后还需要做一些分页查询,还有上面说的主键问题等。
2、插件实现,利用框架本身开发的一些插件,去实现这些插件,然后利用插件去访问数据库,直接实现分离。
优点是:代码量少,实现简单,扩展性好。
缺点是:不易控制,分离方式有限,出现问题难以解决。没有找到特别成熟的插件。
3、中间件实现。利用一些数据库访问的中间件,在访问数据库之前做一些操作使得sql进行相应的变化从而实现分离。
优点是:耦合小,扩展性好,可以解决分布式事务的问题。
确定是:实现比较复杂,需要对中间件进行学习,成本较大。维护也是一个大问题,万一挂掉了。。
总之方式各有千秋,但是考虑到成本上面,第一种几乎是0成本,即可上手,而且比较容易控制,就如同最上面给出的例子一样,而且当前我处理的数据还没有到达那种处处要分离的地步,所以我选择第一种。也推荐使用。如果你找到比较好用的插件或者中间件也可以在评论中推荐。
总结
MyCat:对MySQL数据库进行分库分表
<div id="article_content"data-mod="popu_519" data-dsm="post"> <div> <p>本篇前提: <br> mycat配置正确,且能正常启动。</p>
<h3 id="1schemaxml"><a name="t0"></a>1、schema.xml</h3>
<p><code><table></code>标签:</p>
<pre><code>dataNode -- 分片节点指定(取值:dataNode中的name属性值) rule ------ 分片规则选择(取值:rule标签中的name属性值) </code></pre>
<pre><code>[root@dras-test conf]# vim schema.xml 1 <span><?xml version="1.0"?></span></br> 2 <span><!DOCTYPE mycat:schema SYSTEM "schema.dtd"></span></br> 3 <span><<span>mycat:schema</span> <span>xmlns:mycat</span>=<span>"http://io.mycat/"</span>></span></br> 4 <span><<span>schema</span> <span>name</span>=<span>"mycatdb"</span> <span>checkSQLschema</span>=<span>"false"</span> <span>sqlMaxLimit</span>=<span>"100"</span>></span></br> 5 <span><!-- auto sharding by id (long) --></span></br> 6 <span><<span>table</span> <span>name</span>=<span>"t_person"</span> <span>dataNode</span>=<span>"dn1,dn2"</span> <span>rule</span>=<span>"mod-long"</span> /></span></br> 7 <span><<span>table</span> <span>name</span>=<span>"t_user"</span> <span>primaryKey</span>=<span>"id"</span> <span>dataNode</span>=<span>"dn1,dn2"</span> <span>rule</span>=<span>"sharding-by-murmur"</span> /></span></br> <span><!-- 全局表 --></span></br> 8 <span><!-- table name="province" type="global" dataNode="dn1,dn2,dn3" /></br> 9 10 <table name="student" dataNode="dn1,dn2" rule="auto-sharding-long-sharejoin" /></br> 11 <table name="score" dataNode="dn2,dn3" rule="auto-sharding-long-sharejoin" /></br> 12 <table name="score" dataNode="dn1,dn2" rule="auto-sharding-long-sharejoin" /></br> 13 <!-- ER分片 --></span></br> 14 <span><<span>table</span> <span>name</span>=<span>"customer"</span> <span>dataNode</span>=<span>"dn1,dn2,dn3"</span> <span>rule</span>=<span>"auto-sharding-long-customer"</span>></span></br> 15 <span><<span>childTable</span> <span>name</span>=<span>"orders"</span> <span>joinKey</span>=<span>"customer_id"</span> <span>parentKey</span>=<span>"id"</span>/></span></br> 16 <span></<span>table</span> <span>--</span>></span></br> 17 18 <span><<span>table</span> <span>name</span>=<span>"user"</span> <span>primaryKey</span>=<span>"id"</span> <span>dataNode</span>=<span>"dn1,dn2"</span> <span>rule</span>=<span>"mod-long-test"</span>></span></br> 19 <span><<span>childTable</span> <span>name</span>=<span>"cell"</span> <span>joinKey</span>=<span>"user_id"</span> <span>parentKey</span>=<span>"id"</span>/></span></br> 20 <span><<span>childTable</span> <span>name</span>=<span>"note"</span> <span>joinKey</span>=<span>"user_id"</span> <span>parentKey</span>=<span>"id"</span>/></span></br> 21 <span><<span>childTable</span> <span>name</span>=<span>"lit"</span> <span>joinKey</span>=<span>"user_id"</span> <span>parentKey</span>=<span>"id"</span>/></span></br> 22 <span><<span>childTable</span> <span>name</span>=<span>"lit_usr"</span> <span>joinKey</span>=<span>"user_id"</span> <span>parentKey</span>=<span>"id"</span>/></span></br> 23 <span></<span>table</span>></span></br> 24 25 <span></<span>schema</span>></span></br> 26 27 <span><<span>dataNode</span> <span>name</span>=<span>"dn1"</span> <span>dataHost</span>=<span>"localhost1"</span> <span>database</span>=<span>"db1"</span> /></span></br> 28 <span><<span>dataNode</span> <span>name</span>=<span>"dn2"</span> <span>dataHost</span>=<span>"localhost1"</span> <span>database</span>=<span>"db2"</span> /></span></br> 29 <span><<span>dataNode</span> <span>name</span>=<span>"dn3"</span> <span>dataHost</span>=<span>"localhost1"</span> <span>database</span>=<span>"db3"</span> /></span></br> 30 31 <span><<span>dataHost</span> <span>name</span>=<span>"localhost1"</span> <span>maxCon</span>=<span>"500"</span> <span>minCon</span>=<span>"100"</span> <span>balance</span>=<span>"2"</span></br> <span>32</span> <span>writeType</span>=<span>"1"</span> <span>dbType</span>=<span>"mysql"</span> <span>dbDriver</span>=<span>"native"</span> <span>switchType</span>=<span>"1"</span> <span>slaveThreshold</span>=<span>"100"</span>></span> 33 <span><<span>heartbeat</span>></span>select user()<span></<span>heartbeat</span>></span></br> 34 35 <span><<span>writeHost</span> <span>host</span>=<span>"hostM1"</span> <span>url</span>=<span>"localhost:3306"</span> <span>user</span>=<span>"root"</span></br> <span>36</span> <span>password</span>=<span>""</span> ></span> 37 <span></<span>writeHost</span>></span></br> 38 39 <span></<span>dataHost</span>></span></br> 40 <span></<span>mycat:schema</span>></span></br> </code></pre>
<h3 id="2rulexml"><a name="t1"></a>2、rule.xml</h3>
<p><code><tablerule></code>标签 <br> columns—— 指定分片列的列名; <br> algorithm—- 选择分片算法(function标签中的name属性) <br> <code><function></code>标签 <br> 定义算法,class–分片算法类名及路径; <br> <code><count></code> 分片数,需要分成多少片; <br> <code><mapFile></code> 范围分片时使用的规则; <br> <code><type></code>默认值是0,表示分片列的值是整数,非0表示是字符串。</p>
<pre><code>[root@dras-test conf]# vim rule.xml <span><?xml version="1.0" encoding="UTF-8"?></span></br> <span><!DOCTYPE mycat:rule SYSTEM "rule.dtd"></span></br> <span><<span>mycat:rule</span> <span>xmlns:mycat</span>=<span>"http://io.mycat/"</span>></span></br> <span><<span>tableRule</span> <span>name</span>=<span>"mod-long"</span>></span></br> <span><<span>rule</span>></span></br> <span><<span>columns</span>></span>person_id<span></<span>columns</span>></span></br> <span><<span>algorithm</span>></span>mod-long<span></<span>algorithm</span>></span></br> <span></<span>rule</span>></span></br> <span></<span>tableRule</span>></span></br> <span><<span>tableRule</span> <span>name</span>=<span>"mod-long-test"</span>></span></br> <span><<span>rule</span>></span></br> <span><<span>columns</span>></span>id<span></<span>columns</span>></span></br> <span><<span>algorithm</span>></span>mod-long<span></<span>algorithm</span>></span></br> <span></<span>rule</span>></span></br> <span></<span>tableRule</span>></span></br> <span><<span>tableRule</span> <span>name</span>=<span>"auto-sharding-long-customer"</span>></span></br> <span><<span>rule</span>></span></br> <span><<span>columns</span>></span>id<span></<span>columns</span>></span></br> <span><<span>algorithm</span>></span>auto-sharding-long-customer<span></<span>algorithm</span>></span> <span></<span>rule</span>></span></br> <span></<span>tableRule</span>></span></br> <span><<span>tableRule</span> <span>name</span>=<span>"auto-sharding-long-sharejoin"</span>></span></br> <span><<span>rule</span>></span></br> <span><<span>columns</span>></span>id<span></<span>columns</span>></span></br> <span><<span>algorithm</span>></span>auto-sharding-long-sharejoin<span></<span>algorithm</span>></span> <span></<span>rule</span>></span></br> <span></<span>tableRule</span>></span></br> <span><<span>tableRule</span> <span>name</span>=<span>"sharding-by-murmur"</span>></span></br> <span><<span>rule</span>></span></br> <span><<span>columns</span>></span>uuid<span></<span>columns</span>></span></br> <span><<span>algorithm</span>></span>murmur<span></<span>algorithm</span>></span></br> <span></<span>rule</span>></span></br> <span></<span>tableRule</span>></span></br> <span><<span>function</span> <span>name</span>=<span>"mod-long"</span> <span>class</span>=<span>"io.mycat.route.function.PartitionByMod"</span>></span></br> <span><!-- how many data nodes --></span></br> <span><<span>property</span> <span>name</span>=<span>"count"</span>></span>2<span></<span>property</span>></span> <span></<span>function</span>></span></br> <span><<span>function</span> <span>name</span>=<span>"auto-sharding-long-customer"</span> <span>class</span>=<span>"io.mycat.route.function.AutoPartitionByLong"</span>></span></br> <span><<span>property</span> <span>name</span>=<span>"mapFile"</span>></span>autopartition-long.txt<span></<span>property</span>></span></br> <span></<span>function</span>></span></br> <span><<span>function</span> <span>name</span>=<span>"auto-sharding-long-sharejoin"</span> <span>class</span>=<span>"io.mycat.route.function.AutoPartitionByLong"</span>></span></br> <span><<span>property</span> <span>name</span>=<span>"mapFile"</span>></span>autopartition-long-sharejoin.txt<span></<span>property</span>></span></br> <span></<span>function</span>></span></br> <span><<span>function</span> <span>name</span>=<span>"murmur"</span> <span>class</span>=<span>"io.mycat.route.function.PartitionByMurmurHash"</span>></span></br> <span><<span>property</span> <span>name</span>=<span>"seed"</span>></span>0<span></<span>property</span>></span><span><!-- 默认是0 --></span></br> <span><<span>property</span> <span>name</span>=<span>"type"</span>></span>1<span></<span>property</span>></span><span><!-- 默认是0, 表示integer, 非0表示string--></span></br> <span><<span>property</span> <span>name</span>=<span>"count"</span>></span>2<span></<span>property</span>></span><span><!-- 要分片的数据库节点数量,必须指定,否则没法分片 --></span></br> <span><<span>property</span> <span>name</span>=<span>"virtualBucketTimes"</span>></span>160<span></<span>property</span>></span><span><!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 --></span></br> <span><!-- <property name="weightMapFile">weightMapFile</property> 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点索引为key,以节点权重值为值。>所有权重值必须是正整数,否则以1代替 --></span></br> <span><<span>property</span> <span>name</span>=<span>"bucketMapPath"</span>></span>/usr/local/mycat/logs/bucketMapPath<span></<span>property</span>></span></br> <span><!-- 用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不指定,就不会输出任何东西 --></span> <span></<span>function</span>></span></br> <span></<span>mycat:rule</span>></span></br> </code></pre>
<h3 id="3说明"><a name="t2"></a>3、说明</h3>
<p>对于以上配置文件,选择一个来说明,其他类推。 <br> <strong>对t_person表:</strong></p></br>
<p><strong><em>在sechma.xml中:</em></strong></p></br>
<p><code><table name="t_person" dataNode="dn1,dn2" rule="mod-long" /></code></p></br>
<p>说明,将其分别存在分片节点dn1和dn2上, 分别对应实际MySQL数据库的db1和db2:</p></br>
<p><code><dataNode name="dn1" dataHost="localhost1" database="db1" /></code> <br> <code><dataNode name="dn2" dataHost="localhost1" database="db2" /></code></p></br>
<p>数据库db1和db2又在分片主机localhost1上,localhost1是连接的实际MySQL服务器,</p></br>
<p><code><writeHost host="hostM1" url="localhost:3306" user="root" password="" ></code></p>
<p>因此,t_person表会被按照rule=’mod-long’被分别存储在实际MySQL服务器的db1和db2中。</p>
<p><strong><em>在rule.xml中,</em></strong></p></br>
<p>mod-long算法指定其分片里是id,分片算法是mod-long,对id列进行取模。</p></br>
<blockquote> <p>count=2,说明对2取模, <br></br> 取模后值为0,存入dn1,取模后值为1,存入dn2.</p></br> </blockquote>
<h3 id="4验证"><a name="t3"></a>4、验证</h3>
<p>在mycat数据库中创建含id列的t_person表,插入5条数据:</p>
<pre><code>[root@dras-test ~]# mysql -uroot -p123456 -h127.0.0.1 -P8066</br> Welcome to the MySQL monitor. Commands end with ; or \g.</br> Your MySQL connection id is 1</br> Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server (OpenCloundDB) Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.</br> Oracle is a registered trademark of Oracle Corporation and/or its</br> affiliates. Other names may be trademarks of their respective</br> owners.</br> Type <span>''help;''</span> or <span>''\h''</span> for help. Type <span>''\c''</span> to clear the current input statement.</br> <span>mysql> show databases;</br> +----------+</span></br> <span>| DATABASE |</br> +----------+</span></br> <span>| mycatdb |</br> +----------+</span></br> 1 row in set (0.00 sec)</br> mysql> use mycatdb;</br> Database changed</br> mysql> </br> mysql> create table t<span>_person(id int(11) primary key, name varchar(32));</br> Query OK, 0 rows affected (0.04 sec)</br> </span><span>mysql> desc t_person;</br> +-------+-------------+------+-----+---------+-------+</span></br> <span>| Field | Type | Null | Key | Default | Extra |</br> +-------+-------------+------+-----+---------+-------+</span></br> | id | int(11) | NO | PRI | NULL | |</br> <span>| name | varchar(32) | YES | | NULL | |</br> +-------+-------------+------+-----+---------+-------+</span></br> 2 rows in set (0.01 sec)</br> mysql> </br> mysql> insert into t<span>_person(id,name) values(1,"Moxiao1"),(2,"Moxiao2"),(3,"Moxiao3"),(4,"Moxiao4"),(5,"Moxiao5");</br> Query OK, 5 rows affected (0.02 sec)</br> Records: 3 Duplicates: 0 Warnings: 0</br> </span>mysql> </br> <span>mysql> select * from t_person;</br> +----+---------+</span></br> <span>| id | name |</br> +----+---------+</span></br> | 2 | Moxiao2 |</br> | 4 | Moxiao4 |</br> | 1 | Moxiao1 |</br> | 3 | Moxiao3 |</br> <span>| 5 | Moxiao5 |</br> +----+---------+</span></br> 5 rows in set (0.04 sec)</br> </code></pre></br>
<p>在实际的物理MySQL服务器中,查看:</p>
<pre><code>[root@dras-test conf]# mysql -uroot -p</br> Enter password: </br> Welcome to the MySQL monitor. Commands end with ; or \g.</br> Your MySQL connection id is 522063</br> Server version: 5.1.71-log Source distribution</br> Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.</br> Oracle is a registered trademark of Oracle Corporation and/or its</br> affiliates. Other names may be trademarks of their respective</br> owners.</br> Type <span>''help;''</span> or <span>''\h''</span> for help. Type <span>''\c''</span> to clear the current input statement.</br> <span>mysql> show databases;</br> +--------------------+</span></br> <span>| Database |</br> +--------------------+</span></br> | information<span>_schema |</br> | db1 |</br> | db2 |</br> | db3 |</br> | estudy |</br> | mysql |</br> | test |</br> | yundras |</br> +--------------------+</br> 8 rows in set (0.00 sec)</br> </span><span>mysql> select * from db1.t_person;</br> +----+---------+</span></br> <span>| id | name |</br> +----+---------+</span></br> | 2 | Moxiao2 |</br> <span>| 4 | Moxiao4 |</br> +----+---------+</span></br> 2 rows in set (0.00 sec)</br> <span>mysql> select * from db2.t_person;</br> +----+---------+</span></br> <span>| id | name |</br> +----+---------+</span></br> | 1 | Moxiao1 |</br> | 3 | Moxiao3 |</br> <span>| 5 | Moxiao5 |</br> +----+---------+</span></br> 3 rows in set (0.00 sec)</code></pre></br>
<p><strong>t_person表成功被mycat自动分散到db1和db2两个库的t_person中。</strong></p>
<p>解决单表数据量大的问题。在以分片列为条件进行查询时,会先查找其所在的分片,缩小查找范围。</p>
<pre><code><span>mysql> explain select * from t_person where id=3;</br> +-----------+-----------------------------------------------+</span></br> <span>| DATA_NODE | SQL |</br> +-----------+-----------------------------------------------+</span></br> <span>| dn2 | SELECT * FROM t_person WHERE id = 3 LIMIT 100 |</br> +-----------+-----------------------------------------------+</span></br> 1 row in set (0.01 sec)</br> </code></pre> </div></br>
<link rel="stylesheet" href="http://csdnimg.cn/release/phoenix/production/markdown_views-d4dade9c33.css">
</div>
mysql 分表分库策略
唯一ID的生成
下面列举几种常见的唯一ID生成方案,需要满足两大核心需求:1.全局唯一 2趋势有序
1. 用数据库的auto_increment(自增ID)来生成,每次通过写入数据库一条记录,利用数据库ID自增的特性获取唯一,有序的ID。
优点:使用数据库原有的功能,相对简单;能够保证唯一;能够保证递增性;ID之间的步长是固定且可以自定义的
缺点:可用性难以保证,当生成ID的那台服务器宕机,系统就玩不转了;由于写入是单点的,所以扩展性差,性能上限取决于数据库的写性能。
2. 用UUID
优点:简单方便;全球唯一,在遇见数据迁移、合并或者变更时可以从容应对;
缺点:没有递增性;UUID是很长的字符串,作为主键对存储空间有一定要求,查询效率也较低。
3. 使用Redis生成ID,主要利用Redis是单线程的,所以也可以用来生成唯一ID。当使用的是Redis集群的时候,比如集群中有5台Redis,初始化每台Redis的值为1,2,3,4,5,设置步长为5,并且确定一个不随机的负载均衡策略,能够保证有序,唯一。
优点:不依赖数据库,灵活,且性能相对于数据库有一定提高;使用Redis集群策略还能排除单点故障问题;ID天然有序
缺点:如果系统中没有Redis,还需要引入新的组件;编码和配置工作量大
4. 使用Twitter的snowflake算法;其核心思想是一个64位long型ID,使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。具体实现的代码可以参看https://github.com/twitter/snowflake。可以根据自身需求进行一定的修改。
优点:不依赖数据库,灵活方便,性能优于数据库;ID按照时间在单机上是递增的
缺点:单机上递增,但是当分布式环境下每台机器的时钟不可能完全同步,有时并不能做做全局递增。
5. 使用zookeeper生成唯一ID,主要通过znode数据版本来生成序列号,可以生成32为和64为的数据版本号。很少使用,因为是多步调用API,并发情况下还需要考虑分布式锁,不是很理想。
6. MongoDB的ObjectID,和snowflake算法类似。4字节Unix时间戳,3字节机器编码,2字节进程编码,3字节随机数
1 单表分表策略
a.当数据比较大的时候,对数据进行分表操作,首先要确定需要将数据平均分配到多少张表中,也就是:表容量。
这里假设有100张表进行存储,则我们在进行存储数据的时候,首先对用户ID进行取模操作,根据 user_id % 100获取对应的表进行存储查询操作.
user_id % 100 = 0 user_id % 100 = 1 user_id % 100 = 2
2 分表分库策略
a.
1、中间变量 = user_id%(库数量*每个库的表数量);
2、库序号 = 取整(中间变量/每个库的表数量);
3、表序号 = 中间变量%每个库的表数量;
例如:数据库有256 个,每一个库中有1024个数据表,用户的user_id=262145,按照上述的路由策略,可得:
1、中间变量 = 262145%(256*1024)= 1;
2、库序号 = 取整(1/1024)= 0;
3、表序号 = 1%1024 = 1;
这样的话,对于user_id=262145,将被路由到第0个数据库的第1个表中
关于mysql数据库分表分库的策略和mysql数据库分表分库的策略有哪些的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于MyBatis如何实现Mysql数据库分库分表的实例详解、MyBatis实现Mysql数据库分库分表操作和总结(推荐)、MyCat:对MySQL数据库进行分库分表、mysql 分表分库策略等相关内容,可以在本站寻找。
本文标签: