我记得这次面试好像也没人问我,但是两年前有人问过我,当时我非常牛逼,就回答了一句:当然是分表啊!然后就没有然后了,今天我来重新审视一下这个问题。

“假如一个表太大了,怎么办?”

既然问这个问题了,那么一定是这个表出问题了才会问,如果不出问题谁吃饱撑的研究这个。

一般情况单表谁过于大了,对查询速度会产生比较大的影响。但是也不代表一定要分表,我觉得首先第一步要做的就是确认一下在这个表上的sql慢查询是哪个。然后看看有没有索引,如果没有就加;如果有,就考虑是不是索引加的不太对。这是一个需要反复探索的过程,需要大量使用explain语句进行分析尝试。如果说索引已经没问题,就是因为数据量太大导致的,也并不代表一定要分表,这会儿可以考虑缓存的介入能不能解决问题,如果通过引入缓存可以快速解决压力,就可以先通过引入缓存来作为过渡方案。

以上是成熟的回答,因为但凡一个项目因为表太大出问题了,首先要考虑的就是最快时间内先解决了这个问题。分表是最后的解决方案,因为需要太多的时间。

那么以上都用上了,考虑过了,就确实不得不考虑分表了。那么分表如何操作?

1、通过程序进行分表。这里需要注意的是,一般分表都是只能通过某一个维度进行分表,这个要具体看你的业务需求。比如用户粉丝表,有些大v用户可能会有很多粉丝,假设我们数据表结构是下面这样的:

First Header

Second Header

Third Header

master

slave

createtime

其中master是大v的uid,slave是他粉丝的uid。这个表可能是已经一亿以上数据了,在每次查询我的粉丝的时候,会比较慢,那么现在根据业务场景需求,我们需要根据uid这个维度进行分表。分表的算法则是多种多样的,一般情况下都是通过取余的方式进行的。如果我们要分成10个表,那么就通过如下算法确定大v的数据将会落入到哪个表中:table_name = uid % 10。
这种分表需要你提前预估数据量,因为一旦分表确定了,如果再分表,所有的数据就会乱掉,必须提前将数据重新计算好。
这个时候,对程序将会有比较大的改动。首先你要琢磨从这个表读取数据的场景有哪些,改掉;其次,你要确定往这个表写入的场景有哪些,改掉;

2、这种办法非常偷懒,但是可以解放RD的压力,那就是通过mysql中间件来解决。一般套路是在中间件中配置分表规则,一般也是分表维度和分表数量。这样,程序要改动的地方只需要把数据库连接地址修改为中间件的地址就可以了,剩下的逻辑全部靠中间件来完成。

下面我再补充一个问题,就是如果分表后,虽然能满足你对uid的查询了,但是破坏了其他维度的查询。比如上面那个表偏偏有个业务是通过slave来查询的,此时分表了,怎么办?因为同一个slave可能会分布散落不不同的数据表中,怎么办?

一般套路就是双写,就是分表的时候,除了维护对master维度的表,同时再维护一个对slave维度的表。

高级点儿的套路就是,建立专门的搜索引擎,可以通过es来实现。这个就比较高端了,一般不推荐。