数据库|面试官:说说MySQL数据库分库分表,并且会有哪些问题?


分库讲白了就是比如现在你有一个数据库服务器 , 数据库中有两张表分别是用户表和订单表 。 如果要分库的话现在你需要买两台机子 , 搞两个数据库分别放在两台机子上 , 并且一个数据库放用户表 , 一个数据库放订单表

数据库|面试官:说说MySQL数据库分库分表,并且会有哪些问题?
本文插图
这样存储压力就分担到两个服务器上了 , 但是会带来新的问题 , 所以东西变复杂了都会有新的问题产生 。
1、联表查询问题 也就是join了 , 之前在一个数据库里面可以用上join用一条sql语句就可以联表查询得到想要的结果 , 但是现在分为多个数据库了 , 所以join用不上了 。 就比如现在要查注册时间在2019年之后用户的订单信息 , 你就需要先去数据库A中用户表查询注册在2019年之后的信息 , 然后得到用户id,再拿这些id去数据库B订单表中查找订单信息 , 然后再拼接这些信息返回 。 所以等于得多写一些代码了 。
2、事务问题 搞数据库基本上都离不开事务 , 但是现在不同的数据库事务就不是以前那个简单的本地事务了 , 而是分布式事务了 , 而引入分布式事务也提高了系统的复杂性 , 并且有些效率不高还会影响性能例如Mysql XA 。 还有基于消息中间件实现分布式事务的等等这里不展开讲述 。
分表
我们已经做了分库了 , 但是现在情况是我们的表里面的数据太多了 , 就一不小心你的公司的产品火了 , 像抖音这种 , 所有用户如果就存在一张表里吃不消 , 所以这时候得分表 。 分别又分垂直分表和水平分表 。
垂直分表
垂直分表的意思形象点就像坐标轴的y轴 , 把x轴切成了两半 , 对应到我们的表就是比如我们表有10列 , 现在一刀切下去 , 分成了两张表 , 其中一张表3列 , 另一张表7列 。
这个一刀切下去让两个表分别有几列不是固定的 , 垂直分表适合表中存在不常用并且占用了大量空间的表拆分出去 。
就拿头条的用户信息 , 比如用户表只有用户id、昵称、手机号、个人简介这4个字段 。 但是手机号和个人简介这种信息就属于不太常用的 , 占用的空间也不小 , 个人简介有些人写了一坨 。 所以就把手机号和个人简介这两列拆分出去 。
【数据库|面试官:说说MySQL数据库分库分表,并且会有哪些问题?】那垂直分表影响就是之前只要一个查询的 , 现在需要两次查询才能拿到分表之前的完整用户表信息 。
水平分表
水平分表的意思形象点就像坐标轴的x轴 , 把y轴切成了两半(当然不仅限于切一刀 , 可以切好几份) 。 也拿用户表来说比如现在用户表有5000万行数据 , 我们切5刀 , 分成5个表 , 每个表1000万行数据 。
水平分表就适合用户表行数很多的情况下 , 一般单表行数超过5000万就得分表 , 如果单表的数据比较复杂那可能2000万甚至1000万就得分了 , 这个得看实际情况有些表很简单可能一亿行都不用分 。 所以当一个表行数超过千万级别的时候关注一下 , 如果没有性能问题就可以再等等看 , 不要急着分表 , 因为分表会是带来很多问题 。
水平分表的问题比垂直分表就更烦了 。
要考虑怎么切 , 讲的高级点就叫路由
1、按id也就是范围路由 , 比如id 值1~999万的放一张表 , 1000万~1999放一张表 , 一次类推 。 这个得试的 , 因为范围分的大了 , 可能性能还有问题 , 范围分的小了 。。 那表不得多死 。
这种分法的好处就是容易切啊 , 简单粗暴 , 以后新增的数据分表都不会影响到之前的数据 , 之前的数据都不需要移动 。
2、哈希路由 就是取几列哈希一下看看数据哪个库 , 比如拿id来做哈希 , 1500取余8等于4 , 所以这条记录就放在user_4这个表中 , 2011取余8等于3 , 所以这条记录就放在user_3中 。 这种分法好处就是分的很均匀 , 基本上每个表的数据都差不多 , 但是以后新增数据又得分表了咋办 , 以前的数据都得动 , 比较烦! 分页标题
3、搞一张表来存储路由关系 还是拿用户表来说 , 就是弄一个路由表 , 里面存userId和表编号 , 表示这个userId是这张user表的的 。 这种方式也简单 , 之后又要分表了之后改改路由表 , 迁移一部分数据 。 但是这种方法导致每次查询都得查两次 , 并且如果路由表太大了 , 那路由表又成为瓶颈了!
再说说查询时候的问题 。
比如你要查注册时间最早的前100名用户 , 这就等于你得在水平分的每一张表都order by 一下注册时间并且取100个 , 然后再把每个表的100个结果对比一下得到最终的结果 。 首先操作变麻烦了 , 以前一个order by就搞定的事情现在变的复杂了 , 而且还得考虑一个因素就是时间的问题 , 如果你拆成了20个表 , 那你得执行20个order by , 如果是串行执行的话 , 这个时间开销也是个问题!
分库分表的实现
具体实现也分为程序代码封装、数据库中间件封装 。 实现难度会比读写分离更大 , 至于两种封装的比较在讲读写分离时候已经说了 , 这里不再赘述 。
总结
说了这么多好像分库分表一点都不好啊 , 没错会引入很多问题 , 所以在架构设计要遵循演化原则 , 任何东西都不是一蹴而就的 , 在不同场景适配不同的架构 , 架构只有合适的 , 没有一个架构可以适配任何场景 。
在软件中简单够用就是好的 , 技术没有贵贱 , 不是用了分布式就牛逼 , 越复杂的系统维护的成本和难度越高 , 出现问题的几率越大 。 这种架构的演化往往都是被用户所驱动的 , 可以说是""不得已而为之"" 。
基本上单机数据库可以支撑10万用户量级别 。 所以一般情况下像数据库吃不消就升级硬件 , 优化数据库配置、优化代码、引入redis等 。 只有在真的不行了才上这些更复杂的东西 。