分库分表认知总结

268 阅读2分钟

今天读了《芋道源码》的《分库分表会带来读扩散问题?怎么解决?》这篇文章,总结下重点内容。这篇文章偏理论,实践后续补充。

1、什么是分库分表?

背景:数据库底层结构是 B+ 树,数据达到2000万后,会造成树增高,数据一个页已无法装下,分散到多个页,磁盘 IO 增多,查询性能变差。分库分表就为解决这一问题。

垂直拆分:把某些列拆为一个新表,这样单行数据变小,单个页(16 KB)放入的数据变多,查询性能得到缓解。

水平拆分:本质就是一张 user 表,变为 user0 ,user1 ,user3 .... userN 等 N 张小表。如果在多个数据库做分表,就是分库分表。

分表:每个小表500万~2000万数据。(为何是500万~2000万?)

分表方案一:user0 的主键 id 为1~2kw,user1 的 id 为 2kw+1 ~ 4kw,依次划分。实现方式有,第三方库 orm 或者自己加 mysql 的 Proxy 服务。

分表方案二:根据 id 取模分表。比如id=31,31 % 5 = 1,就放在 user1 表。优点是数据分散在多张表,缺点是扩展分表数量时,比如 31 % 8 = 7,迁移就得全部重跑一遍数据。所以优先选方案一。

分表方案三:结合方案一和二。先根据id,判断是属于哪个2kw的表,之后再将这个表user0 拆为5个子表,user0-0到user0-4,根据取模运算 id % 5,判断在哪个字表中。这样就可以将写单表分摊为写多表,且数据扩容时,也不用迁移已有的数据。

2、分库分表带来的问题-读扩散

背景:如果查询的是id,则能很快定位哪个表。如果user还有name列,用name是查询,就需要到每个子表中去执行SQL语句。表越多,则查询次数阅越多,这就是读扩散问题。

解决方案一:引入新表。保存id和name列。根据name查询时,可查到id,根据id再去查数据在哪些子表,在子表查询即可,从全查询缩减为查固定几个表。缺点是,要维护两套表,且更新name列,需要两套表一起更新。增加了开发量。

解决方案二:以上方案类似于倒排索引。类似于es,es天然分片,且内部利用倒排索引加速查询。通过监听mysql的binlog,把数据写入es,实现实时查询的能力。

截屏2024-01-15 11.14.28.png

解决方案三:使用TiDB。其使用Range进行数据分片,类似于分表方案一。其支持类似于对普通列进行倒排索引,就是上述方案一。且有工具实现一键从mysql到tidb的迁移。