参考自
https://mp.weixin.qq.com/s/J_zVlrR9cDX9Vrg6YVjUiA
怎么分
水平分表:将表数据按记录分到多个表<i>(涉及<b>分片策略</b>)</i><br>
垂直分表:将表数据按字段分到多个表
路由策略
第三方orm库,放在<b>客户端侧</b><i>(需要根据不同的语言实现不同的代码库,常用组件有sharding-jdbc)</i>
在mysql和业务代码之间加个<b>proxy服务</b><i style="">(</i><i>不需要关心上游服务用的是什么语言,常用组件有MyCat)</i><br>
读扩散问题
背景
上面分表策略用了id这一列作为分表的依据,这其实就是所谓的<b>分片键</b>。实际上我们一般也是用的数据库主键作为分片键。<br>但很多情况下,我们的查询又不是只查主键,如果我的数据库表有一列name,并且加了个普通索引。<br>由于name并不是分片键,我们没法定位到具体要到哪个分表上去执行sql。<br>于是就会对所有分表都执行上面的sql,当然不会是串行执行sql,一般都是并发执行sql的。<br>如果我有100张表,就执行100次sql。<br>如果我有200张表,就执行200次sql。<br>随着我的表越来越多,次数会越来越多,这就是所谓的读扩散问题。<br>
问题核心
主键是分片键,而普通索引列并不分片<br>
怎么解决
单独建个新的分片表<i>(这个新表里的列就只有旧表的主键id和普通索引列,而这次换<b>普通索引列来做分片键</b>。)</i>
例子:为name列建个新表(nameX),以name为新的分片键
缺点
<b>需要维护两套表</b>,并且普通索引列更新时,要两张表同时进行更改。有一定的开发量。
更优解
分析
<i>上面的方案,则通过引入一个新表,倒过来,先用name查到对应的id,再拿id去获取具体的数据。<br>这其实就像是建立了一个新的索引一样,像这种,通过name列反查原数据的思想,其实就很类似于<b>倒排索引</b></i><br>
方案
使用<b>es</b>,es天然分片,而且内部利用倒排索引的形式来加速数据查询
<b>ES+MySQL。通过开源工具 canal 监听mysql的binlog日志变更,再将数据解析后写入es</b>
更更优解
使用<b>tidb</b>
这是个分布式数据库。它通过引入Range的概念进行数据表分片,比如第一个分片表的id在0~2kw,第二个分片表的id在2kw~4kw。<br>这是根据id范围进行数据库分表。它支持普通索引,并且普通索引也是分片的,这是不是又跟上面提到的倒排索引方案很类似。<br>
总结
1 mysql在<b>单表数据过大</b>时,查询性能会变差,因此当数据量变得巨大时,需要<b>考虑水平分表</b>
2 水平分表需要选定一个<b>分片键</b>,一般选择主键,然后根据id进行取模,或者根据id的范围进行分表
3 mysql水平分表后,对于非分片键字段的查询会有<b>读扩散</b>的问题,可以用普通索引列作分片键建一个新表,先查新表拿到id后再回到原表再查一次原表。<br>这本质上是借鉴了倒排索引的思路<br>
4 如果想要支持更多维度的查询,可以监听mysql的binlog,将数据写入到<b>es</b>,提供近实时的查询能力
5 用tidb替换mysql也是个思路