mysql---分表分库

分表分库

我们都建议MySQL单表数据量不要超过1000万,最好是在500万以内,如果能控制在100万以内,那是 最佳的选择了,基本单表100万以内的数据,性能上不会有太⼤的问题,前提是,只要你建好索引就⾏,其实保证 MySQL⾼性能通常没什么特别⾼深的技巧,就是控制数据量不要太⼤,另外就是保证你的查询⽤上了索引,⼀般就没 问题。

1. 为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?你们具体是如何对数据库如何进行垂直拆分或水平拆分的?

(1)为什么要分库分表?(设计高并发系统的时候,数据库层面该如何设计?)

因为此时**每天活跃用户数上千万,每天单表新增数据多达50万,**目前一个表总数据量都已经达到了两三千万了!扛不住啊!数据库磁盘容量不断消耗掉!高峰期并发达到惊人的5000~8000!系统支撑不到现在,已经挂掉了!比如你单表都几千万数据了,你确定你能抗住么?绝对不行,**单表数据量太大,会极大影响你的sql执行的性能,**到了后面你的sql可能就跑的很慢了。一般来说,就以我的经验来看,单表到几百万的时候,性能就会相对差一些了,你就得分表了。

分表是啥意思?就是把一个表的数据放到多个表中,然后查询的时候你就查一个表。比如按照用户id来分表,将一个用户的数据就放在一个表中。然后操作的时候你对一个用户就操作那个表就好了。这样可以控制每个表的数据量在可控的范围内,比如每个表就固定在200万以内。

分库是啥意思?就是你一个库一般我们经验而言,最多支撑到并发2000,一定要扩容了,而且一个健康的单库并发值你最好保持在每秒1000左右,不要太大。那么你可以将一个库的数据拆分到多个库中,访问的时候就访问一个库好了。

01_分库分表的由来

(2)用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?

sharding-jdbc:当当开源的,属于client层方案。确实之前用的还比较多一些,因为SQL语法支持也比较多,没有太多限制,而且目前推出到了2.0版本,支持分库分表、读写分离、分布式id生成、柔性事务(最大努力送达型事务、TCC事务),目前社区也还一直在开发和维护,还算是比较活跃,个人认为算是一个现在也可以选择的方案。

mycat:基于cobar改造的,属于proxy层方案,支持的功能非常完善,而且目前应该是非常火的而且不断流行的数据库中间件,社区很活跃,也有一些公司开始在用了。但是确实相比于sharding jdbc来说,年轻一些,经历的锤炼少一些。

sharding-jdbc这种client层方案的优点在于不用部署,运维成本低,不需要代理层的二次转发请求,性能很高,但是如果遇到升级啥的需要各个系统都重新升级版本再发布,各个系统都需要耦合sharding-jdbc的依赖;

mycat这种proxy层方案的缺点在于需要部署,自己及运维一套中间件,运维成本高,但是好处在于对于各个项目是透明的,如果遇到升级之类的都是自己中间件那里搞就行了。

通常来说,这两个方案其实都可以选用,但是我个人建议中小型公司选用sharding-jdbc,client层方案轻便,而且维护成本低,不需要额外增派人手,而且中小型公司系统复杂度会低一些,项目也没那么多;

但是中大型公司最好还是选用mycat这类proxy层方案,因为可能大公司系统和项目非常多,团队很大,人员充足,那么最好是专门弄个人来研究和维护mycat,然后大量项目直接透明使用即可。

(3)你们具体是如何对数据库如何进行垂直拆分或水平拆分的?

水平拆分的意思,就是把一个表的数据给弄到多个库的多个表里去,但是每个库的表结构都一样,只不过每个库表放的数据是不同的,所有库表的数据加起来就是全部数据。水平拆分的意义,就是将数据均匀放更多的库里,然后用多个库来抗更高的并发,还有就是用多个库的存储容量来进行扩容。

垂直拆分的意思,就是把一个有很多字段的表给拆分成多个表,或者是多个库上去。每个库表的结构都不一样,每个库表都包含部分字段。一般来说,会将较少的访问频率很高的字段放到一个表里去,然后将较多的访问频率很低的字段放到另外一个表里去。因为数据库是有缓存的,你访问频率高的行字段越少,就可以在缓存里缓存更多的行,性能就越好。这个一般在表层面做的较多一些。

这个其实挺常见的,不一定我说,大家很多同学可能自己都做过,把一个大表拆开,订单表、订单支付表、订单商品表。

还有表层面的拆分,就是分表,将一个表变成N个表,就是让每个表的数据量控制在一定范围内,保证SQL的性能。否则单表数据量越大,SQL性能就越差。一般是200万行左右,不要太多,但是也得看具体你怎么操作,也可能是500万,或者是100万。你的SQL越复杂,就最好让单表行数越少。

好了,无论 是分库了还是分表了,上面说的那些数据库中间件都是可以支持的。就是基本上那些中间件可以做到你分库分表之后,中间件可以根据你指定的某个字段值,比如说userid,自动路由到对应的库上去,然后再自动路由到对应的表里去。

而且这儿还有两种分库分表的方式,

一种是按照range来分,就是每个库一段连续的数据,这个一般是按比如时间范围来的,但是这种一般较少用,因为很容易产生热点问题,大量的流量都打在最新的数据上了;range来分,好处在于说,后面扩容的时候,就很容易,因为你只要预备好,给每个月都准备一个库就可以了,到了一个新的月份的时候,自然而然,就会写新的库了;缺点,但是大部分的请求,都是访问最新的数据。

或者是按照某个字段hash一下均匀分散,这个较为常用。hash分法,好处在于说,可以平均分配没给库的数据量和请求压力;坏处在于说扩容起来比较麻烦,会有一个数据迁移的这么一个过程

02_数据库如何拆分

2.现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统从未分库分表动态切换到分库分表上?

假设,你现有有一个单库单表的系统,在线上在跑,假设单表有600万数据

3个库,每个库里分了4个表,每个表要放50万的数据量

假设你已经选择了一个分库分表的数据库中间件,sharding-jdbc,mycat,都可以

你怎么把线上系统平滑地迁移到分库分表上面去

(1)停机迁移方案

我先给你说一个最low的方案,就是很简单,大家伙儿凌晨12点开始运维,网站或者app挂个公告,说0点到早上6点进行运维,无法访问。。。。。。

接着到0点,停机,系统挺掉,没有流量写入了,此时老的单库单表数据库静止了。然后你之前得写好一个导数的一次性工具,此时直接跑起来,然后将单库单表的数据哗哗哗读出来,写到分库分表里面去。

导数完了之后,就ok了,修改系统的数据库连接配置啥的,包括可能代码和SQL也许有修改,那你就用最新的代码,然后直接启动连到新的分库分表上去。

(2)双写迁移方案

02_不停机双写方案

这个是我们常用的一种迁移方案,比较靠谱一些,不用停机,不用看北京凌晨4点的风景

简单来说,就是在线上系统里面,之前所有写库的地方,增删改操作,都除了对老库增删改,都加上对新库的增删改,这就是所谓双写,同时写俩库,老库和新库。

然后系统部署之后,新库数据差太远,用之前说的导数工具,跑起来读老库数据写新库,写的时候要根据gmt_modified这类字段判断这条数据最后修改的时间,除非是读出来的数据在新库里没有,或者是比新库的数据新才会写。

接着导万一轮之后,有可能数据还是存在不一致,那么就程序自动做一轮校验,比对新老库每个表的每条数据,接着如果有不一样的,就针对那些不一样的,从老库读数据再次写。反复循环,直到两个库每个表的数据都完全一致为止。

接着当数据完全一致了,就ok了,基于仅仅使用分库分表的最新代码,重新部署一次,不就仅仅基于分库分表在操作了么,还没有几个小时的停机时间,很稳。所以现在基本玩儿数据迁移之类的,都是这么干了。

3.分库分表之后,id主键如何处理?

(1)数据库自增id()

获取一个数据库全局自增的一个id。拿到这个id之后再往对应的分库分表里去写入。

这个方案的好处就是方便简单,谁都会用;缺点就是单库生成自增id,要是高并发的话,就会有瓶颈的;如果你硬是要改进一下,那么就专门开一个服务出来,这个服务每次就拿到当前id最大值,然后自己递增几个id,一次性返回一批id,然后再把当前最大id值修改成递增几个id之后的一个值;但是无论怎么说都是基于单个数据库。

适合的场景:你分库分表就俩原因,要不就是单库并发太高,要不就是单库数据量太大;除非是你并发不高,但是数据量太大导致的分库分表扩容,你可以用这个方案,因为可能每秒最高并发最多就几百,那么就走单独的一个库和表生成自增主键即可。

并发很低,几百/s,但是数据量大,几十亿的数据,所以需要靠分库分表来存放海量的数据

(2)uuid

好处就是本地生成,不要基于数据库来了;不好之处就是,uuid太长了,作为主键性能太差了,不适合用于主键。

适合的场景:如果你是要随机生成个什么文件名了,编号之类的,你可以用uuid,但是作为主键是不能用uuid的。

(3)获取系统当前时间

这个就是获取当前时间即可,但是问题是,并发很高的时候,比如一秒并发几千,会有重复的情况,这个是肯定不合适的。基本就不用考虑了。

适合的场景:一般如果用这个方案,是将当前时间跟很多其他的业务字段拼接起来,作为一个id,如果业务上你觉得可以接受,那么也是可以的。你可以将别的业务字段值跟当前时间拼接起来,组成一个全局唯一的编号,订单编号,时间戳 + 用户id + 业务含义编码

(4)snowflake算法

twitter开源的分布式id生成算法,就是把一个64位的long型的id,1个bit是不用的,用其中的41 bit作为毫秒数,用10 bit作为工作机器id,12 bit作为序列号

1个bit为如果是1,那么都是负数,但是我们生成的id都是正数,所以第一个bit统一都是0

41 bit:表示的是时间戳,单位是毫秒。41 bit可以表示的数字多达2^41 - 1,也就是可以标识2 ^ 41 - 1个毫秒值,换算成年就是表示69年的时间。

10 bit:记录工作机器id,代表的是这个服务最多可以部署在2^10台机器上哪,也就是1024台机器。但是10 bit里5个bit代表机房id,5个bit代表机器id。意思就是最多代表2 ^ 5个机房(32个机房),每个机房里可以代表2 ^ 5个机器(32台机器)。

12 bit:这个是用来记录同一个毫秒内产生的不同id,12 bit可以代表的最大正整数是2 ^ 12 - 1 = 4096,也就是说可以用这个12bit代表的数字来区分同一个毫秒内的4096个不同的id

64位的long型的id,64位的long -> 二进制

0 | 0001100 10100010 10111110 10001001 01011100 00 | 10001 | 1 1001 | 0000 00000000

2018-01-01 10:00:00 -> 做了一些计算,再换算成一个二进制,41bit来放 -> 0001100 10100010 10111110 10001001 01011100 00

机房id,17 -> 换算成一个二进制 -> 10001

机器id,25 -> 换算成一个二进制 -> 11001

snowflake算法服务,会判断一下,当前这个请求是否是,机房17的机器25,在2175/11/7 12:12:14时间点发送过来的第一个请求,如果是第一个请求

假设,在2175/11/7 12:12:14时间里,机房17的机器25,发送了第二条消息,snowflake算法服务,会发现说机房17的机器25,在2175/11/7 12:12:14时间里,在这一毫秒,之前已经生成过一个id了,此时如果你同一个机房,同一个机器,在同一个毫秒内,再次要求生成一个id,此时我只能把加1

0 | 0001100 10100010 10111110 10001001 01011100 00 | 10001 | 1 1001 | 0000 00000001

比如我们来观察上面的那个,就是一个典型的二进制的64位的id,换算成10进制就是910499571847892992。

所以你自己利用这个工具类,自己搞一个服务,然后对每个机房的每个机器都初始化这么一个东西,刚开始这个机房的这个机器的序号就是0。然后每次接收到一个请求,说这个机房的这个机器要生成一个id,你就找到对应的Worker,生成。

他这个算法生成的时候,会把当前毫秒放到41 bit中,然后5 bit是机房id,5 bit是机器id,接着就是判断上一次生成id的时间如果跟这次不一样,序号就自动从0开始;要是上次的时间跟现在还是在一个毫秒内,他就把seq累加1,就是自动生成一个毫秒的不同的序号。

这个算法那,可以确保说每个机房每个机器每一毫秒,最多生成4096个不重复的id。

利用这个snowflake算法,你可以开发自己公司的服务,甚至对于机房id和机器id,反正给你预留了5 bit + 5 bit,你换成别的有业务含义的东西也可以的。

这个snowflake算法相对来说还是比较靠谱的,所以你要真是搞分布式id生成,如果是高并发啥的,那么用这个应该性能比较好,一般每秒几万并发的场景,也足够你用了。

4. 你们有没有做MySQL读写分离?如何实现mysql的读写分离?MySQL主从复制原理的是啥?如何解决mysql主从同步的延时问题?

(1)如何实现mysql的读写分离?

其实很简单,就是基于主从复制架构,简单来说,就搞一个主库,挂多个从库,然后我们就单单只是写主库,然后主库会自动把数据给同步到从库上去。

2)MySQL主从复制原理的是啥?

02_MySQL主从复制原理主库将变更写binlog日志,然后从库连接到主库之后,从库有一个IO线程,将主库的binlog日志拷贝到自己本地,写入一个中继日志中。接着从库中有一个SQL线程会从中继日志读取binlog,然后执行binlog日志中的内容,也就是在自己本地再次执行一遍SQL,这样就可以保证自己跟主库的数据是一样的。

这里有一个非常重要的一点,就是从库同步主库数据的过程是串行化的,也就是说主库上并行的操作,在从库上会串行执行。所以这就是一个非常重要的点了,由于从库从主库拷贝日志以及串行执行SQL的特点,在高并发场景下,从库的数据一定会比主库慢一些,是有延时的。所以经常出现,刚写入主库的数据可能是读不到的,要过几十毫秒,甚至几百毫秒才能读取到。

而且这里还有另外一个问题,就是如果主库突然宕机,然后恰好数据还没同步到从库,那么有些数据可能在从库上是没有的,有些数据可能就丢失了。

所以mysql实际上在这一块有两个机制,一个是半同步复制,用来解决主库数据丢失问题;一个是并行复制,用来解决主从同步延时问题。

这个所谓半同步复制,semi-sync复制,指的就是主库写入binlog日志之后,就会将强制此时立即将数据同步到从库,从库将日志写入自己本地的relay log之后,接着会返回一个ack给主库,主库接收到至少一个从库的ack之后才会认为写操作完成了。

所谓并行复制,指的是从库开启多个线程,并行读取relay log中不同库的日志,然后并行重放不同库的日志,这是库级别的并行。

1)主从复制的原理

2)主从延迟问题产生的原因

3)主从复制的数据丢失问题,以及半同步复制的原理

4)并行复制的原理,多库并发重放relay日志,缓解主从延迟问题

(3)mysql主从同步延时问题(精华)

线上确实处理过因为主从同步延时问题,导致的线上的bug,小型的生产事故

show status,Seconds_Behind_Master,你可以看到从库复制主库的数据落后了几ms

其实这块东西我们经常会碰到,就比如说用了mysql主从架构之后,可能会发现,刚写入库的数据结果没查到,结果就完蛋了。。。。

所以实际上你要考虑好应该在什么场景下来用这个mysql主从同步,建议是一般在读远远多于写,而且读的时候一般对数据时效性要求没那么高的时候,用mysql主从同步

所以这个时候,我们可以考虑的一个事情就是,你可以用mysql的并行复制,但是问题是那是库级别的并行,所以有时候作用不是很大

所以这个时候。。通常来说,我们会对于那种写了之后立马就要保证可以查到的场景,采用强制读主库的方式,这样就可以保证你肯定的可以读到数据了吧。其实用一些数据库中间件是没问题的。

一般来说,如果主从延迟较为严重

1、分库,将一个主库拆分为4个主库,每个主库的写并发就500/s,此时主从延迟可以忽略不计

2、重写代码,写代码的同学,要慎重,当时我们其实短期是让那个同学重写了一下代码,插入数据之后,直接就更新,不要查询

3、如果确实是存在必须先插入,立马要求就查询到,然后立马就要反过来执行一些操作,对这个查询设置直连主库。不推荐这种方法,你这么搞导致读写分离的意义就丧失了

1.大型电商网站的上亿数据量的用户表如何进行水平拆分?

⼀个背景是⼀个中型的电商公司,不 是那种顶级电商巨头,就算是⼀个垂直领域的中型电商公司吧,那么他覆盖的⽤户⼤概算他有1亿以内,⼤概⼏千万的 样⼦

可以选择把这个⽤户⼤表拆分为⽐如100张表,那么此时⼏千万 数据瞬间分散到100个表⾥去,类似user_001、user_002、user_100这样的100个表,每个表也就⼏⼗万数据⽽已

可以把这100个表分散到多台数据库服务器上去,此时要分散到⼏台服务器呢?你要考虑两个点,**⼀个是数据量 有多少个GB/TB,⼀个是针对⽤户中⼼的并发压⼒有多⾼。**实际上⼀般互联⽹公司对⽤户中⼼的压⼒不会⾼的太离 谱,因为⼀般不会有很多⼈同时注册/登录,或者是同时修改⾃⼰的个⼈信息,所以并发这块不是太⼤问题

⾄于数据量层⾯的话,我可以给⼤家⼀个经验值,⼀般1亿⾏数据,⼤致在1GB到⼏个GB之间的范围,这个跟具体你 ⼀⾏数据有多少字段也有关系,⼤致⼤致就是这么个范围,所以说你⼏千万的⽤户数据,往多了说也就⼏个GB⽽已

这点数据量,对于服务器的存储空间来说,完全没压⼒,不是问题。 所以综上所述,此时你完全可以给他分配两台数据库服务器,放两个库,然后100张表均匀分散在2台服务器上就可以 了,分的时候需要指定⼀个字段来分,⼀般来说会指定userid,根据⽤户id进⾏hash后,对表进⾏取模,路由到⼀个表 ⾥去,这样可以让数据均匀分散。

到此就搞定了⽤户表的分库分表,你只要给系统加上数据库中间件技术,设置好路由规则,就可以轻松的对2个分库上 的100张表进⾏增删改查的操作了。平时针对某个⽤户增删改查,直接对他的userid进⾏hash,然后对表取模,做⼀个 路由,就知道到哪个表⾥去找这个⽤户的数据了。

但是这⾥可能会出现⼀些问题,⼀个是说,⽤户在登录的时候,可能不是根据userid登陆的,可能是根据username之 类的⽤户名,⼿机号之类的来登录的,此时你⼜没有userid,怎么知道去哪个表⾥找这个⽤户的数据判断是否能登录 呢

关于这个问题,⼀般来说常规⽅案是建⽴⼀个索引映射表,就是说搞⼀个表结构为(username, userid)的索引映射 表,把username和userid⼀⼀映射,然后针对username再做⼀次分库分表,把这个索引映射表可以拆分为⽐如100个 表分散在两台服务器⾥。 然后⽤户登录的时候,就可以根据username先去索引映射表⾥查找对应的userid,⽐如对username进⾏hash然后取模 路由到⼀个表⾥去,找到username对应的userid,接着根据userid进⾏hash再取模,然后路由到按照userid分库分表的 ⼀个表⾥去,找到⽤户的完整数据即可。

但是这种⽅式会把⼀次查询转化为两个表的两次查询,先查索引映射表,再根据userid去查具体的数据,性能上是有⼀ 定的损耗的,不过有时候为了解决分库分表的问题,也只能⽤这种类似的办法

另外就是如果在公司运营团队⾥,有⼀个⽤户管理模块,需要对公司的⽤户按照⼿机号、住址、年龄、性别、职业等 各种条件进⾏极为复杂的搜索,这怎么办呢?其实没太多的好办法,基本上就是要对你的⽤户数据表进⾏binlog监听, 把你要搜索的所有字段同步到Elasticsearch⾥去,建⽴好搜索的索引。 然后你的运营系统就可以通过Elasticsearch去进⾏复杂的多条件搜索,ES是适合⼲这个事⼉的,然后定位到⼀批 userid,通过userid回到分库分表环境⾥去找出具体的⽤户数据,在页⾯上展⽰出来即可

2.⼀线电商公司的订单系统是如何进⾏数据库设计的?

⼀般互联⽹公司的订单系统是如何做分库分表的,既然要聊订单系统的分库分 表,那么就得先说说为什么订单需要分库分表,其实最关键的⼀点就是要分析⼀下订单系统的数据量,那么订单系统的数据量 有多⼤?这个就得看具体公司的情况了。

⽐如说⼀个⼩型互联⽹公司,如果是涉及到电商交易的,那么肯定每天都会有⼀些订单进来的,那么⽐如⼩型互联⽹公司假设 有500万的注册⽤户,每天⽇活的⽤户会有多少⼈?意思就是说,你500万的注册⽤户,并不是每个⼈每天都来光顾你这⾥ 的!

即使按照28法则,你5000万的注册⽤户,每天最多是20%的⽤户会过来光顾你这⾥,也就是会来访问你的APP/ ⼩程序/⽹站,也就是1000万的⽇活⽤户,但是这个⽇活⽐例恐怕很多公司都达不到,所以⼀般靠谱点就算他是10%的⽤户每天 会来光顾你,算下来就是平均每个注册⽤户10天会来光顾你⼀次,这就是100万的⽇活⽤户

但是这50万的⽇活⽤户仅仅是来看看⽽已,那么有多少⼈会来买你的东西呢?这个购买⽐例可就更低了,基本上很可能这种⼩ 型互联⽹公司每天就做个1w订单,或者⼏万订单,这就已经相当的不错了,咱们就以保守点按3w订单来算吧

这个互联⽹公司的订单表每天新增数据⼤概是3w左右,每个⽉是新增90w数据,每年是新增1080w数据。⼤家 对这个数据量感觉如何?看着不⼤是吧,但是按照我们上次说的,⼀般建议单表控制在千万以内,尽量是100w到500w之间, 如果控制在⼏⼗万是最好了!

所以说这个订单表,即使你按⼀年1080w数据增长来计算,最多3年就到千万级⼤表了,这个就绝对会导致你涉及订单的操作, 速度挺慢的。

所以说,基本上个这类订单表,哪怕是个⼩互联⽹公司,按分库分表⼏乎是必须得做的,那么怎么做呢?订单表,⼀般在拆分 的时候,往往要考虑到三个维度,⼀个是必然要按照订单id为粒度去分库分表,也就是把订单id进⾏hash后,对表数量进⾏取 模然后把订单数据均匀分散到100~1000个表⾥去,再把这些表分散在多台服务器上。

但是这⾥有个问题,另外两个维度是⽤户端和运营端,⽤户端,就是⽤户可能要查⾃⼰的订单,运营端就是公司可能要查所有 订单,那么怎么解决这类问题呢?其实就跟上次的差不多,基本上针对⽤户端,你就需要按照(userid, orderid)这个表结 构,去做⼀个索引映射表。

userid和orderid的⼀⼀对应映射关系要放在这个表⾥,然后针对userid为粒度去进⾏分库分表,也就是对userid进⾏hash后取 模,然后把数据均匀分散在很多索引映射表⾥,再把表放在很多数据库⾥。

然后每次⽤户端拿出APP查询⾃⼰的订单,直接根据userid去hash然后取模路由到⼀个索引映射表,找到这个⽤户的orderid, 这⾥当然可以做⼀个分页了,因为⼀般订单都是⽀持分页的,此时可以允许⽤于户分页查询orderid,然后拿到⼀堆orderid了, 再根据orderid去按照orderid粒度分库分表的表⾥提取订单完整数据

⾄于运营端,⼀般都是要根据N多条件对订单进⾏搜索的,此时跟上次讲的⼀样,可以把订单数据的搜索条件都同步到ES⾥, 然后⽤ES来进⾏复杂搜索,找出来⼀波orderid,再根据orderid去分库分表⾥找订单完整数据。 其实⼤家到最后会发现,分库分表的玩法基本都是这套思路,

按业务id分库分表,建⽴索引映射表同时进⾏分库分表,数据同 步到ES做复杂搜索,基本这套玩法就可以保证你的分库分表场景下,各种业务功能都可以⽀撑了

3.如果需要进行垮库的分页操作,应该怎么来做?

基本上你只要按照userid先去分库分表的(userid, orderid)索引映射表⾥查找到你的那些 orderid,然后搞⼀个分页就可以了,对分页内的orderid,每个orderid都得去按orderid分库分表的数据⾥查找完整的订 单数据,这就可以搞定分库分表环境的下分页问题了。

告诉你的是,如果要在分库分表环境下搞分页,最好是保证你的⼀个主数据粒度(⽐如userid)是 你的分库分表的粒度,你可以根据⼀个业务id路由到⼀个表找到他的全部数据,这就可以做分页了

但是此时可能有⼈会提出⼀个疑问了,那如果说现在我想要对⽤户下的订单做分页,但是同时还能⽀持指定⼀些查询 条件呢?对了,这其实也是很多APP⾥都⽀持的,就是对⾃⼰的订单查询,有的APP是⽀持指定⼀些条件的,甚⾄是 排序规则,⽐如订单名称模糊搜索,或者是别的条件,⽐如说订单状态。

举个例⼦吧,⽐如说最经典的某个电商APP,⼤家平时都玩⼉的⼀个,在我的订单界⾯,可以按照订单状态来搜索, 分别是全部、待付款、待收货、已完成、已取消⼏个状态,同时就是对订单购买的商品标题进⾏模糊搜索。 那么此时你怎么玩⼉分页呢?因为毕竟你的索引映射表⾥,只有(userid, orderid)啊!可是这⼜如何呢?你完全可以 在这个索引映射表⾥加⼊更多的数据,⽐如(userid, orderid, order_status, product_description),加上订单所处的状 态,以及商品的标题、副标题等⽂本。

对我的订单进⾏分页的 时候,直接就可以根据userid去索引映射表⾥找到⽤户的所有订单,然后按照订单状 态、商品描述⽂本模糊匹配去搜索,完了再分页,分页拿到的orderid,再去获取订单需要展⽰的数据,⽐如说订单⾥ 包含的商品列表,每个商品的缩略图、名称、价格以及所属店铺。

是针对运营端的分页查询需求呢?这还⽤说?上次都提过了,数据直接进⼊ES⾥,通过ES就可以对多条件进⾏ 搜索同时再进⾏分页了,这很好搞定!

当然,⽹上是有⼈说过⼀些所谓的跨库的分页⽅案,⽐如说⼀定要针对跨多个库和多个表的数据搞查询和分页,那这 种如果你⼀定要做,基本上只能是⾃⼰从各个库表拉数据到内存,⾃⼰内存⾥做筛选和分页了,或者是基于数据库中 间件去做,那数据库中间件本质也是⼲这个,把各个库表的数据拉到内存做筛选和分页。

实际上我是绝对反对这种⽅案的,因为效率和性能极差,基本都是⼏秒级别的速度。 所以当你觉得似乎必须要跨库和表查询和分页的时候,我建议你,第⼀,你考虑⼀下是不是可以把你查询⾥按照某个 主要的业务id进⾏分库分表建⽴⼀个索引映射表,第⼆是不是可以可以把这个查询⾥要的条件都放到索引映射表⾥去, 第三,是不是可以通过ES来搞定这个需求。 尽可能还是按照上述思路去做分库分表下的分页,⽽不要去搞跨库/表的分页查询。

4.当分库分表技术方案运行几年过后,再次进行扩容应该怎么做?

从⼀开始,你的表数量宁愿多⼀些,也别太少了,最好是计算⼀下数据增量,让⾃⼰永远不⽤增加更多的表

其次,万⼀是过了⼏年后,你的每⼀台服务器上的存储空间要耗尽了呢?或者是写并发压⼒太⼤,每个服务器的并发压⼒都到 瓶颈了呢?此时还⽤说么,当然要增加更多的数据库服务器了!但是增加服务器之后,那么你的表怎么办呢? 简单,此时你就得把你的表均匀分散迁移到新增加的数据库服务器上去,然后再修改⼀下系统⾥的路由规则就可以了,⽤新的 路由规则保证你能正确的把数据路由到指定表以及指定库上去就没问题了。 因此关于数据库扩容这块,虽然⽹上有很多⽅案,但是我们建议的就是,刚开始拆分,表数量可以多⼀些,避免后续要增加 表。然后数据库服务器要扩容是没问题的,直接把表做⼀下迁移就⾏了,然后修改路由规则。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值