垂直分库分表和水平分库分表有什么不同的地方?具体使用在类场景下呢?

平时跟身边开发哈牛皮的的时候,总是会聊起来,曾经哪哪个面试被问到了mysql大表要怎么优化呢?张口就是回答 分库分表啊~垂直分水平分啊等的, 是不是很熟悉?话说回来,你真的了解分库分表吗?

以下内容很肝,无废话 值得一看。

先来说说垂直分库分表吧:

现在有个需求:是商品表字段太多,每个字段访问频次不一样,浪费了IO资源,需要进行优化

这个需求就用到垂直分表啦,垂直分表介绍:

通俗点说垂直分库就是“大表拆小表”,基于列字段进行的
    拆分原则一般是表中的字段较多,将不常用的或者数据较大,长度较长的拆分到“扩展表 如text类型字段
    访问频次低、字段大的商品描述信息单独存放在一张表中
    访问频次较高的商品基本信息单独放在一张表中
垂直拆分原则
    把不常用的字段单独放在一张表
    把text,blob等大字段拆分出来放在附表中
    业务经常组合查询的列放在一张表中

举个例子:商品详情一般是拆分主表和附表 

//拆分前
CREATE TABLE `product` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(524) DEFAULT NULL COMMENT '视频标题',
  `cover_img` varchar(524) DEFAULT NULL COMMENT '封面图',
  `price` int(11) DEFAULT NULL COMMENT '价格,分',
  `total` int(10) DEFAULT '0' COMMENT '总库存',
  `left_num` int(10) DEFAULT '0' COMMENT '剩余',
  
  `learn_base` text COMMENT '课前须知,学习基础',
  `learn_result` text COMMENT '达到水平',
  `summary` varchar(1026) DEFAULT NULL COMMENT '概述',  
  `detail` text COMMENT '视频商品详情',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;


//拆分后
CREATE TABLE `product` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(524) DEFAULT NULL COMMENT '视频标题',
  `cover_img` varchar(524) DEFAULT NULL COMMENT '封面图',
  `price` int(11) DEFAULT NULL COMMENT '价格,分',
  `total` int(10) DEFAULT '0' COMMENT '总库存',
  `left_num` int(10) DEFAULT '0' COMMENT '剩余',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;


CREATE TABLE `product_detail` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `product_id` int(11) DEFAULT NULL COMMENT '产品主键',
  `learn_base` text COMMENT '课前须知,学习基础',
  `learn_result` text COMMENT '达到水平',
  `summary` varchar(1026) DEFAULT NULL COMMENT '概述',  
  `detail` text COMMENT '视频商品详情',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

再来一个需求:C端项目里面,单个数据库的CPU、内存长期处于90%+的利用率,数据库连接经常不够,需要进行优化

这里就是要垂直分库了,垂直分库介绍:

 垂直分库针对的是一个系统中的不同业务进行拆分, 数据库的连接资源比较宝贵且单机处理能力也有限

没拆分之前全部都是落到单一的库上的,单库处理能力成为瓶颈,还有磁盘空间,内存,tps等限制

拆分之后,避免不同库竞争同一个物理机的CPU、内存、网络IO、磁盘,所以在高并发场景下,垂直分库一定程度上能够突破IO、连接数及单机硬件资源的瓶颈

垂直分库可以更好解决业务层面的耦合,业务清晰,且方便管理和维护

一般从单体项目升级改造为微服务项目,就是垂直分库

 垂直分库分表解决的问题:

        垂直的分库分表可以提高访问并发量,但是依然没有解决单表数据量过大的问题,那单表过大问题怎么解决呢?继续往下看~

又来需求咯:当一张表的数据达到几千万时,查询一次所花的时间长,需要进行优化,缩短查询时间

首先要清楚一点,垂直分表是表结构的拆分,水平分表是表数据的拆分

这种缩小单表数据量的,当然要用水平分表了

水平分表介绍:

把一个表的数据分到一个数据库的多张表中,每个表只有这个表的部分数据
核心是把一个大表,分割N个小表,每个表的结构是一样的,数据不一样,全部表的数据合起来就是全部数据
针对数据量巨大的单张表(比如订单表),按照某种规则(RANGE,HASH取模等),切分到多张表里面去
但是这些表还是在同一个库中,所以单数据库操作还是有IO瓶颈,主要是解决单表数据量过大的问题
减少锁表时间,没分表前,如果是DDL(create/alter/add等)语句,当需要添加一列的时候mysql会锁表,期间所有的读写操作只能等待

 

 再来个需求:高并发的项目中,水平分表后依旧在单个库上面,1个数据库资源瓶颈 CPU/内存/带宽等限制导致响应慢,需要进行优化

这时候就用到水平分库啦。

把同个表的数据按照一定规则分到不同的数据库中,数据库在不同的服务器上
水平分库是把不同表拆到不同数据库中,它是对数据行的拆分,不影响表结构
每个库的结构都一样,但每个库的数据都不一样,没有交集,所有库的并集就是全量数据
水平分库的粒度,比水平分表更大

 例如5G流量包的这种在高并发场景下,多些流量包库加上存储用户流量包信息的表,再根据库表位一一对应,即可快速进行查找定位。


 下面聊聊水平分库分表怎么分,按照什么策略来分的话题

一下可以想到的分表策略有:

一、自增id,根据ID范围进行分表(左闭右开)

二、Range范围分库分表

三、hash取模

那么,这三种分别使用什么场景,都有哪些利弊呢?一个一个来聊聊叭

一、自增ID

规则案例
    1~1,000,000 是 table_1
    1,000,000 ~2,000,000 是 table_2
    2,000,000~3,000,000 是 table_3
    ...更多

优点:
id是自增长,可以无限增长
扩容不用迁移数据,容易理解和维护

缺点:

大部分读和写都访会问新的数据,慢慢老的id数据查看的概率不高,请求访问都集中到新数据的表中了,有IO瓶颈,整体资源利用率低
数据倾斜严重,热点数据过于集中,部分节点有瓶颈

 二、第二种范围的角度来分库分表

范围角度思考问题:

数字
    自增id范围
时间
    年、月、日范围
    比如按照月份生成 库或表 pay_log_2022_01、pay_log_2022_02
空间
    地理位置:省份、区域(华东、华北、华南)
    比如按照 省份 生成 库或表

阿里云的这种实例就是按照华东啊 华北大区等地理位置来划分的 

 比如以下几种基于Range范围分库分表业务场景:

微博发送记录、微信消息记录、日志记录,id增长/时间分区都行
    水平分表为主,水平分库则容易造成资源的浪费
网站签到等活动流水数据时间分区最好
    水平分表为主,水平分库则容易造成资源的浪费
大区划分(一二线城市和五六线城市活跃度不一样,如果能避免热点问题,即可选择)
    saas业务水平分库(华东、华南、华北等)

 

 范围分的话,需要实际根据业务情况来选择分片字段,容易产生热点问题。

三、最普遍使用的hash取模

为什么不直接取模要先hash呢?如果取模的字段不是整数型要先hash,统一规则就行啦

案例规则
	用户ID是整数型的,要分2库,每个库表数量4表,一共8张表
	用户ID取模后,值是0到7的要平均分配到每张表

库ID = userId % 库数量 2 
表ID = userId / 库数量 2 % 表数量4

 优点:保证数据较均匀的分散落在不同的库、表中,可以有效的避免热点数据集中问题

 缺点:扩容不是很方便,需要数据迁移 

具体大家怎么选择,还是根据实际业务情况来定。

这有个博客是讲的使用sharding-jdbc做的自定义库表位,可以避免数据增长带来的扩容迁移问题

短链服务分库分表-扩容免数据迁移方案-初级入门三 持续更新中_8年开发工作经验的老王,积极分享工作中遇到的问题~-CSDN博客

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值