GVKun编程网logo

mysql数据库分表分库的策略(mysql数据库分表分库的策略有哪些)

2

本篇文章给大家谈谈mysql数据库分表分库的策略,以及mysql数据库分表分库的策略有哪些的知识点,同时本文还将给你拓展MyBatis如何实现Mysql数据库分库分表的实例详解、MyBatis实现My

本篇文章给大家谈谈mysql数据库分表分库的策略,以及mysql数据库分表分库的策略有哪些的知识点,同时本文还将给你拓展MyBatis如何实现Mysql数据库分库分表的实例详解、MyBatis实现Mysql数据库分库分表操作和总结(推荐)、MyCat:对MySQL数据库进行分库分表、mysql 分表分库策略等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

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如何实现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 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实现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数据库进行分库分表

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>&lt;table&gt;</code>标签:</p>

<pre><code>dataNode -- 分片节点指定(取值:dataNode中的name属性值) rule ------ 分片规则选择(取值:rule标签中的name属性值) </code></pre>

<pre><code>[root@dras-test conf]# vim schema.xml 1 <span>&lt;?xml version="1.0"?&gt;</span></br> 2 <span>&lt;!DOCTYPE mycat:schema SYSTEM "schema.dtd"&gt;</span></br> 3 <span>&lt;<span>mycat:schema</span> <span>xmlns:mycat</span>=<span>"http://io.mycat/"</span>&gt;</span></br> 4 <span>&lt;<span>schema</span> <span>name</span>=<span>"mycatdb"</span> <span>checkSQLschema</span>=<span>"false"</span> <span>sqlMaxLimit</span>=<span>"100"</span>&gt;</span></br> 5 <span>&lt;!-- auto sharding by id (long) --&gt;</span></br> 6 <span>&lt;<span>table</span> <span>name</span>=<span>"t_person"</span> <span>dataNode</span>=<span>"dn1,dn2"</span> <span>rule</span>=<span>"mod-long"</span> /&gt;</span></br> 7 <span>&lt;<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> /&gt;</span></br> <span>&lt;!-- 全局表 --&gt;</span></br> 8 <span>&lt;!-- table name="province" type="global" dataNode="dn1,dn2,dn3" /&gt;</br> 9 10 &lt;table name="student" dataNode="dn1,dn2" rule="auto-sharding-long-sharejoin" /&gt;</br> 11 &lt;table name="score" dataNode="dn2,dn3" rule="auto-sharding-long-sharejoin" /&gt;</br> 12 &lt;table name="score" dataNode="dn1,dn2" rule="auto-sharding-long-sharejoin" /&gt;</br> 13 &lt;!-- ER分片 --&gt;</span></br> 14 <span>&lt;<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>&gt;</span></br> 15 <span>&lt;<span>childTable</span> <span>name</span>=<span>"orders"</span> <span>joinKey</span>=<span>"customer_id"</span> <span>parentKey</span>=<span>"id"</span>/&gt;</span></br> 16 <span>&lt;/<span>table</span> <span>--</span>&gt;</span></br> 17 18 <span>&lt;<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>&gt;</span></br> 19 <span>&lt;<span>childTable</span> <span>name</span>=<span>"cell"</span> <span>joinKey</span>=<span>"user_id"</span> <span>parentKey</span>=<span>"id"</span>/&gt;</span></br> 20 <span>&lt;<span>childTable</span> <span>name</span>=<span>"note"</span> <span>joinKey</span>=<span>"user_id"</span> <span>parentKey</span>=<span>"id"</span>/&gt;</span></br> 21 <span>&lt;<span>childTable</span> <span>name</span>=<span>"lit"</span> <span>joinKey</span>=<span>"user_id"</span> <span>parentKey</span>=<span>"id"</span>/&gt;</span></br> 22 <span>&lt;<span>childTable</span> <span>name</span>=<span>"lit_usr"</span> <span>joinKey</span>=<span>"user_id"</span> <span>parentKey</span>=<span>"id"</span>/&gt;</span></br> 23 <span>&lt;/<span>table</span>&gt;</span></br> 24 25 <span>&lt;/<span>schema</span>&gt;</span></br> 26 27 <span>&lt;<span>dataNode</span> <span>name</span>=<span>"dn1"</span> <span>dataHost</span>=<span>"localhost1"</span> <span>database</span>=<span>"db1"</span> /&gt;</span></br> 28 <span>&lt;<span>dataNode</span> <span>name</span>=<span>"dn2"</span> <span>dataHost</span>=<span>"localhost1"</span> <span>database</span>=<span>"db2"</span> /&gt;</span></br> 29 <span>&lt;<span>dataNode</span> <span>name</span>=<span>"dn3"</span> <span>dataHost</span>=<span>"localhost1"</span> <span>database</span>=<span>"db3"</span> /&gt;</span></br> 30 31 <span>&lt;<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>&gt;</span> 33 <span>&lt;<span>heartbeat</span>&gt;</span>select user()<span>&lt;/<span>heartbeat</span>&gt;</span></br> 34 35 <span>&lt;<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> &gt;</span> 37 <span>&lt;/<span>writeHost</span>&gt;</span></br> 38 39 <span>&lt;/<span>dataHost</span>&gt;</span></br> 40 <span>&lt;/<span>mycat:schema</span>&gt;</span></br> </code></pre>

<h3 id="2rulexml"><a name="t1"></a>2、rule.xml</h3>

<p><code>&lt;tablerule&gt;</code>标签 <br> columns—— 指定分片列的列名; <br> algorithm—- 选择分片算法(function标签中的name属性) <br> <code>&lt;function&gt;</code>标签 <br> 定义算法,class–分片算法类名及路径; <br> <code>&lt;count&gt;</code> 分片数,需要分成多少片; <br> <code>&lt;mapFile&gt;</code> 范围分片时使用的规则; <br> <code>&lt;type&gt;</code>默认值是0,表示分片列的值是整数,非0表示是字符串。</p>

<pre><code>[root@dras-test conf]# vim rule.xml <span>&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span></br> <span>&lt;!DOCTYPE mycat:rule SYSTEM "rule.dtd"&gt;</span></br> <span>&lt;<span>mycat:rule</span> <span>xmlns:mycat</span>=<span>"http://io.mycat/"</span>&gt;</span></br> <span>&lt;<span>tableRule</span> <span>name</span>=<span>"mod-long"</span>&gt;</span></br> <span>&lt;<span>rule</span>&gt;</span></br> <span>&lt;<span>columns</span>&gt;</span>person_id<span>&lt;/<span>columns</span>&gt;</span></br> <span>&lt;<span>algorithm</span>&gt;</span>mod-long<span>&lt;/<span>algorithm</span>&gt;</span></br> <span>&lt;/<span>rule</span>&gt;</span></br> <span>&lt;/<span>tableRule</span>&gt;</span></br> <span>&lt;<span>tableRule</span> <span>name</span>=<span>"mod-long-test"</span>&gt;</span></br> <span>&lt;<span>rule</span>&gt;</span></br> <span>&lt;<span>columns</span>&gt;</span>id<span>&lt;/<span>columns</span>&gt;</span></br> <span>&lt;<span>algorithm</span>&gt;</span>mod-long<span>&lt;/<span>algorithm</span>&gt;</span></br> <span>&lt;/<span>rule</span>&gt;</span></br> <span>&lt;/<span>tableRule</span>&gt;</span></br> <span>&lt;<span>tableRule</span> <span>name</span>=<span>"auto-sharding-long-customer"</span>&gt;</span></br> <span>&lt;<span>rule</span>&gt;</span></br> <span>&lt;<span>columns</span>&gt;</span>id<span>&lt;/<span>columns</span>&gt;</span></br> <span>&lt;<span>algorithm</span>&gt;</span>auto-sharding-long-customer<span>&lt;/<span>algorithm</span>&gt;</span> <span>&lt;/<span>rule</span>&gt;</span></br> <span>&lt;/<span>tableRule</span>&gt;</span></br> <span>&lt;<span>tableRule</span> <span>name</span>=<span>"auto-sharding-long-sharejoin"</span>&gt;</span></br> <span>&lt;<span>rule</span>&gt;</span></br> <span>&lt;<span>columns</span>&gt;</span>id<span>&lt;/<span>columns</span>&gt;</span></br> <span>&lt;<span>algorithm</span>&gt;</span>auto-sharding-long-sharejoin<span>&lt;/<span>algorithm</span>&gt;</span> <span>&lt;/<span>rule</span>&gt;</span></br> <span>&lt;/<span>tableRule</span>&gt;</span></br> <span>&lt;<span>tableRule</span> <span>name</span>=<span>"sharding-by-murmur"</span>&gt;</span></br> <span>&lt;<span>rule</span>&gt;</span></br> <span>&lt;<span>columns</span>&gt;</span>uuid<span>&lt;/<span>columns</span>&gt;</span></br> <span>&lt;<span>algorithm</span>&gt;</span>murmur<span>&lt;/<span>algorithm</span>&gt;</span></br> <span>&lt;/<span>rule</span>&gt;</span></br> <span>&lt;/<span>tableRule</span>&gt;</span></br> <span>&lt;<span>function</span> <span>name</span>=<span>"mod-long"</span> <span>class</span>=<span>"io.mycat.route.function.PartitionByMod"</span>&gt;</span></br> <span>&lt;!-- how many data nodes --&gt;</span></br> <span>&lt;<span>property</span> <span>name</span>=<span>"count"</span>&gt;</span>2<span>&lt;/<span>property</span>&gt;</span> <span>&lt;/<span>function</span>&gt;</span></br> <span>&lt;<span>function</span> <span>name</span>=<span>"auto-sharding-long-customer"</span> <span>class</span>=<span>"io.mycat.route.function.AutoPartitionByLong"</span>&gt;</span></br> <span>&lt;<span>property</span> <span>name</span>=<span>"mapFile"</span>&gt;</span>autopartition-long.txt<span>&lt;/<span>property</span>&gt;</span></br> <span>&lt;/<span>function</span>&gt;</span></br> <span>&lt;<span>function</span> <span>name</span>=<span>"auto-sharding-long-sharejoin"</span> <span>class</span>=<span>"io.mycat.route.function.AutoPartitionByLong"</span>&gt;</span></br> <span>&lt;<span>property</span> <span>name</span>=<span>"mapFile"</span>&gt;</span>autopartition-long-sharejoin.txt<span>&lt;/<span>property</span>&gt;</span></br> <span>&lt;/<span>function</span>&gt;</span></br> <span>&lt;<span>function</span> <span>name</span>=<span>"murmur"</span> <span>class</span>=<span>"io.mycat.route.function.PartitionByMurmurHash"</span>&gt;</span></br> <span>&lt;<span>property</span> <span>name</span>=<span>"seed"</span>&gt;</span>0<span>&lt;/<span>property</span>&gt;</span><span>&lt;!-- 默认是0 --&gt;</span></br> <span>&lt;<span>property</span> <span>name</span>=<span>"type"</span>&gt;</span>1<span>&lt;/<span>property</span>&gt;</span><span>&lt;!-- 默认是0, 表示integer, 非0表示string--&gt;</span></br> <span>&lt;<span>property</span> <span>name</span>=<span>"count"</span>&gt;</span>2<span>&lt;/<span>property</span>&gt;</span><span>&lt;!-- 要分片的数据库节点数量,必须指定,否则没法分片 --&gt;</span></br> <span>&lt;<span>property</span> <span>name</span>=<span>"virtualBucketTimes"</span>&gt;</span>160<span>&lt;/<span>property</span>&gt;</span><span>&lt;!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 --&gt;</span></br> <span>&lt;!-- &lt;property name="weightMapFile"&gt;weightMapFile&lt;/property&gt; 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点索引为key,以节点权重值为值。&gt;所有权重值必须是正整数,否则以1代替 --&gt;</span></br> <span>&lt;<span>property</span> <span>name</span>=<span>"bucketMapPath"</span>&gt;</span>/usr/local/mycat/logs/bucketMapPath<span>&lt;/<span>property</span>&gt;</span></br> <span>&lt;!-- 用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不指定,就不会输出任何东西 --&gt;</span> <span>&lt;/<span>function</span>&gt;</span></br> <span>&lt;/<span>mycat:rule</span>&gt;</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>&lt;table name="t_person" dataNode="dn1,dn2" rule="mod-long" /&gt;</code></p></br>

<p>说明,将其分别存在分片节点dn1和dn2上, 分别对应实际MySQL数据库的db1和db2:</p></br>

<p><code>&lt;dataNode name="dn1" dataHost="localhost1" database="db1" /&gt;</code> <br> <code>&lt;dataNode name="dn2" dataHost="localhost1" database="db2" /&gt;</code></p></br>

<p>数据库db1和db2又在分片主机localhost1上,localhost1是连接的实际MySQL服务器,</p></br>

<p><code>&lt;writeHost host="hostM1" url="localhost:3306" user="root" password="" &gt;</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&gt; show databases;</br> +----------+</span></br> <span>| DATABASE |</br> +----------+</span></br> <span>| mycatdb |</br> +----------+</span></br> 1 row in set (0.00 sec)</br> mysql&gt; use mycatdb;</br> Database changed</br> mysql&gt; </br> mysql&gt; 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&gt; 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&gt; </br> mysql&gt; 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&gt; </br> <span>mysql&gt; 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&gt; 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&gt; 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&gt; 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&gt; 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 分表分库策略

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 分表分库策略等相关内容,可以在本站寻找。

本文标签: