mysql分库分表分区
为什么要设计分库分表
由于业务发展,单表的数据量激增,单库单表无法承载整体的数据存储时,采取的一种将整体数据分散存储到不同服务器上的不同数据库中的不同数据表的存储方案。这样可以缓解数据存储的压力。
分库分表策略
依照某一种策略将数据尽量平均地分配到多个数据库节点或者多个表中。
应用场景
当读多写少时,可以采用mysql读写分离架构。
当mysql单表数据量过大时,可以采用分库分表、sql语句优化方案。
垂直拆分
- 意思:对数据库竖着拆分,也就是将数据库的表拆分到多个不同的数据库中。
- 原则:一般是按照业务类型来拆分,核心思想是专库专用,将业务耦合度比较高的表拆分到单独的库中。
水平拆分
水平拆分指的是将单一数据表按照某一种规则拆分到多个数据库和多个数据表中,关注点在数据的特点。
-
拆分1:按照某一个字段的哈希值做拆分,这种拆分规则比较适用于实体表。
譬如将用户表拆分成16库64表:
先对id进行hash操作hash(id),这样有助于打散数据
然后对16取余 hash(id)%16,这样就得到了分库后的索引
最后对64取余 hash(id)%16%64,这样就得到了分表后的索引值 -
拆分2:按照某一个字段的区间来拆分,比较常用的是时间字段。
分库分表带来的问题1,查询难
从分库分表规则中你可以看到,无论是哈希拆分还是区间段的拆分,我们首先都需要选取一个数据库字段,这带来一个问题是:
我们之后所有的查询都需要带上这个字段,才能找到数据所在的库和表,否则就只能向所有的数据库和数据表发送查询命令。如果像上面说的要拆分成 16 个库和 64 张表,那么一次数据的查询会变成 16*64=1024 次查询,查询的性能肯定是极差的。
举例:
在医疗系统中当地的居民是处在不同的省市区县乡镇村的,所以主键前缀设计为行政编码。我们可以根据id进行分区这样,可以将数据水平切分成不同的表。这样不同的居民处于不同地区表中。
便利1:我们查询某个区域内的所有居民,这样我们可以查询指定的区域内的居民,这样是符合mysql的聚簇索引设计的。
新问题:如果我们想要查询某个人在哪个区域,就会很头痛。可能需要查询所有的库和表。我们不能为了查询名字,就用名字分区。为了查询身份证号,就用身份证号分区。这样增大存储成本,设计不合理。
解决思路:
当前我们的分库分表采用居民id,id设计是带有区域性的。这样我们就将一张大表水平拆分成不同区域的小表。但是我们用名字去查询这个居民的全部信息时,最好还是使用id查询,因为聚簇索引,叶子节点既是数据节点也是索引节点。这样的话,我们可以在名字和居民id之间搭桥就不用拆分了。建立一张名字、居民id关系表。
通过名字查询居民id,通过id查询居民信息。这样就不用过度拆分了。
分库分表带来的问题2,数据库特性实现难
-
跨库多表join困难:原本就是一条sql语句就解决了。现在通过程序拆分解决。
譬如,健康家庭中,父母所在地在上海,但是子女成家了所在地在北京。现在查询遗传病的问题,就要查询整个家族的遗传问题。这样就需要将上海的父母查出来、在北京的子女查出来。通过程序查询上海的父母基本信息,里面还获取其子女的表id。然后我们再通过程序查询子女的表id,查询出子女的基本信息。通过父母子女的id查询双方的既往疾病史。通过程序将他们组合即可。 -
统计记录count数量困难:原本直接一条select count即可。
譬如,健康系统中,统计全国的所有患有糖尿病的患者。那么有个问题,就是当前水平切分的居民表,都是根据地级市或者洲来划分的表,一般省里大概有10多个地级市,一个地级市大的几千万人口,小的几百万人口。所以我们需要将全国不同的省份、直辖市划分成不同的库,每个库里面存放10多个地级市居民的表。
我们可以搞一张统计表,来记录数据。本身糖尿病的形成标准也不是一日就形成,都是体检查出来问题,才给指定为糖尿病患者的。所以我们可以在每天晚上半夜12点使用定时器定时去统计,通过程序去实现统计。
分区
就是把一张表的数据分成N个区块,在逻辑上看最终只是一张表,但底层是由N个物理区块组成的。
分区好处:本身可以减少无用数据扫描。
参考:https://www.jianshu.com/p/adf6c3717b9a