【数据库】分库分表分区
目录
- 通用的概念
- 拆分方式
- 水平拆分(Sharding)
- 垂直拆分
- 一、分区
- 1. 分区的特点
- 2. 分区路由规则
- 3. 分区优/缺点
- 参考
- 二、分库分表
- 为什么分库分表
- 1. 分库
- 2. 分表
- 3. 分库分表的数据量判断
- 中间件
- 有哪些问题
- 1. 数据扩缩容方式
- (1)根据范围range分表
- (2)根据hash取模
- (3)一致性hash(这种情况怎么在线迁移数据)
- 参考
- 2. 分库分表如何迁移数据(感觉不太好,待完善)
- 3. 分库后的事务问题
- 4. 对SQL的影响
- (1)join问题
- (2)group by聚合问题
- (3)order by + limit offset分页问题
- 5. 分布式ID(待补充细节)
- 6. 业务查询时没有分表键(待补充)
- 参考
- 三、业务场景
通用的概念
拆分方式
水平拆分(Sharding)
解释: 表结构不变,数据分散到多个其他相同结构的表中
优点: 缓解单数据库表的压力,流量按数据分布进行分流。
垂直拆分
解释: 表结构发生改变,一张表的列拆成多张表,每张表的数据行数一样,且保持不变。
优点: 常常按业务拆分,缓解表压力,流量按业务分流。
一、分区
以MySQL为例。在5.1版本之后增加了对分区的支持,常见的存储引擎都支持分区,如InnoDB、MYISAM、NDB等。
1. 分区的特点
- 分区是在物理上将一张表分割成多张物理分区,但是逻辑上对外还是一张表
- 支持水平分区,但不支持垂直分区
- 采用的是局部分区索引的方式,即一个分区对象存放一部分索引,而非全局分区索引方式(所有分区数据对应的索引存放在一个对象中)。因此若是查询未能定位数据在哪个分区,即使走索引也会在每个分区挨个走索引,成本翻多倍。
- 分区字段可以存在NULL
2. 分区路由规则
- Range:按连续数值区间分区
- LIST:按离散数值列表分区
- HASH:对用户自定义表达式(返回值是自然数)进行分区(求模分区)
- KEY:支持blob、text以外的字段为分区健
3. 分区优/缺点
如下场景分区表性能好:
- 删除某分区下的数据时,相比非分区表,不需要查出所有数据再删除,只需要删除分区即可。
- 查询的数据只存在一个分区内且数据量较大时,性能高。
- 查询分区表时,根据查询键找到所在分区,全表扫描。
- 查询非分区表时,要么因为查询数据量大发生全表扫描,要么走索引找到所有符合条件的数据,再回表,整体性能不如分区表的全表扫描
如下场景分区表性能差:
- 走索引且查询数据量小,查询条件无法判断数据所在分区
- 查询分区表时,会在所有的分区表进行索引扫描。代价是分区数量*单表IO次数
- 查询非分区表时,直接查询索引。代价是单表IO次数
其它优缺点:
- 程序对分区表无感,不需要修改代码
- 数据分布可能不均匀,性能提升有限
- 使用RANGE、LIST的分区方式,则需要不断对分区维护。有分区以外的数据时,需要新建分区。
参考
- mysql表分区详解
二、分库分表
为什么分库分表
1. 分库
- 数据量过大,单机磁盘不足,需要把数据分散到多台节点上
- 连接数过多,单机无法支持过多的连接
- 符合微服务按业务拆分理念
2. 分表
单表数据量过大,索引层数多,即使走索引性能优化也不是很好
- 个人猜想:比如单表2亿数据,建立非聚集索引,树高度为4。拆分成10张表后 ,单表2千万,树高度为3,查询一条数据,走索引并回表,IO次数为4*2=8
- 若分表,假设按查询条件分表。IO次数为1(查找分区)+ 3 * 2 (回表)= 7
- 若是查询条件里没有分表键,就会在所有表里查询,性能反而下降。
索引过大,一次无法将全部索引缓存,需要额外进行磁盘IO
数据插入时重建索引比较耗时
如何计算树的高度以及如何判断一次查询的IO次数
3. 分库分表的数据量判断
阿里巴巴的《Java开发手册》提出:单表行数超过500万行或者单表容量超过2GB,才推荐进行分库分表。
我个人认为需要计算索引的树高度,超过3层时就要考虑分表了。
中间件
Client模式 | Proxy模式 | |
---|---|---|
概念 | 分库分表逻辑在本地控制,直接连接多个数据库,并且将查询结果在本地汇总 | 独立的服务管理分库,应用连接代理服务。 |
性能方面 | 较好。直连数据库 | 一般,多了层代理转发,并且还要维护一个路由关系表 |
内存方面 | 本地数据合并,占用本地的CPU和内存 | 不额外占用调用者的CPU和内存 |
架构复杂度 | 只需要引入jar包,不会有单点故障问题 | 需要额外部署服务,要考虑高可用,复杂度增加 |
升级管理 | 需要单独维护jar包,升级要更改各个服务的依赖版本 | 对调用者透明,升级维护无感知 |
中间件 | Zebra、Sharding-jdbc、TSharding | MyCat、KingShard、Atlas、Cobar |
有哪些问题
1. 数据扩缩容方式
(1)根据范围range分表
优点:
- 扩容方便,直接增加对应的表即可
缺点:
- 存在热点问题,比如按日期分表,最近一个月的数据都在一张表里,访问量大。而历史数据访问量小
(2)根据hash取模
优点: 不会存在明显的热点问题
缺点: 扩容难,重hash会发生缓存雪崩
如何避免重计算hash并导致所有数据需要迁移(类似缓存雪崩): 可以参考hashmap的扩容方式。节点数为2的幂次,每次扩容节点数翻倍,并且重新计算hash后,只有一部分数据需要迁移到新节点。
(3)一致性hash(这种情况怎么在线迁移数据)
个人认为跟Redis Cluster的槽有点像。都是避免redis节点和数据直接关联,利用槽去绑定数据。
简单原理:
- 构造一个圆环,圆环上有 2 32 2^{32} 232个槽
- 对服务器的IP或者名称进行hash,然后用 2 32 2^{32} 232取模,将其映射到圆环的槽位上
- 将数据的key进行hash并取模,落到圆环的槽位上
- 圆环上的数据沿着顺时针查找到的第一个服务器,就是所属的服务器。
优点: 扩缩容方便,不会引起缓存雪崩。直接添加或者删除结点后,只会有一部分数据需要迁移
缺点: 可能有数据倾斜造成数据分布不均的问题,可以对机器名称或者ip加编号后进行hash,得到多个虚拟结点。虚拟节点数据越多,均匀分布概率越大。
参考
- 一致性哈希算法原理详解
- Redis Cluster为什么选哈希槽不选一致性哈希?
2. 分库分表如何迁移数据(感觉不太好,待完善)
停机迁移比较简单,建好新的分区表后直接将数据插过去就可以,然后修改代码读取表。这里主要描述下在线迁移。
数据双写:
- 代码层面,开启新旧表双写,并编写代理层能够控制在线切换读取的表。发布服务在线升级。
- 记录新表增量字段起始值,将旧表中小于该值的数据迁移到新表中
- 推荐增量字段为 有序主键>唯一索引键>非唯一索引键
- 唯一键好处理,非唯一键还需要将等于新表起始值的数据迁移过来(发生主键冲突的数据则不需要迁移)
异步监听: (没写清楚)
监听binlog,将数据迁移到新表上
3. 分库后的事务问题
需要分布式事务。不过分布式事务本身会带来额外的损耗,所以设计时应当尽量避免。
分布式事务见:分布式理论与Seata
4. 对SQL的影响
(1)join问题
跨库:
- 字段冗余,避免关联
- 若关联全局表,可以在所有库中冗余一份相同的全局表,避免跨结点
- 代码层面关联
- 借助ETL工具,定时关联汇聚,生成新的关联好的表
- 判断关联关系,将能够关联上的数据放到一个分片上。
同库分表后关联:
待办
(2)group by聚合问题
各节点得到结果后,程序端合并
(3)order by + limit offset分页问题
业务上禁止跳页,只允许上一页下一页:
- 根据主键排序的话,每次分页需要记录上次查询结果最后一条数据的主键。查询下一页数据(比如一页十条),需要在所有分表执行select xxx from table where id > xx limit 10 。然后在程序端合并,得到最小的10条数据。
- 根据唯一索引列排序时,方法同主键排序
- 根据非唯一索引列排序时,应该在这个基础上按主键排序。即 order by 非唯一索引列,主键 。这时要记录上次查询结果最后一条数据的非唯一索引列和主键
允许跳页:
一次返回数据较多,不推荐
比如查询第二页数据。需要返回所有表的前两页数据,在程序中合并计算第二页数据是哪些。页数越远,需要处理的数据越多,网络开销、CPU性能都会占用较大。
5. 分布式ID(待补充细节)
优点 | 缺点 | |
---|---|---|
uuid | 实现简单 |
连续性差,作为主键每次新增数据都会触发索引重建。 分布式环境中可能重复 |
雪花算法 | 性能好,有序 | 依赖服务器时间,时钟回拨可能生成重复ID |
号段模式 | ||
redis/zookeeper |
Redis基于INCR 命令生成 分布式全局唯一id zookeeper一种通过节点,一种通过节点的版本号 |
6. 业务查询时没有分表键(待补充)
详解分库分表后非分片键如何查询
参考
- 关于分库分表
- 数据库分区、分表、分库、分片
- 分库分表-理论、方案、问题总结
- 分库分表经典15连问
- MySQL:互联网公司常用分库分表方案汇总
三、业务场景
- 用户操作日志:分表
【数据库】分库分表分区相关推荐
- 数据库 分库 分表 分区
我们知道,如果我们使用mysql,当数据库数据量达到一定数据量之后,会考虑对数据库进行分库分表等操作,但是在什么情况下做怎么的切分,下面分表介绍. 一.分库 1 分库原因 首先,在单台数据库服务器性能 ...
- 数据库分库分表(sharding)系列(五) 一种支持自由规划无须数据迁移和修改路由代码的Sharding扩容方案...
为什么80%的码农都做不了架构师?>>> 版权声明:本文由本人撰写并发表于2012年9月份的<程序员>杂志,原文题目<一种支持自由规划的Sharding扩容方 ...
- MariaDB Spider 数据库分库分表实践
分库分表
分库分表 一般来说,数据库分库分表,有以下做法: 按哈希分片:根据一条数据的标识计算哈希值,将其分配到特定的数据库引擎中: 按范围分片:根据一条数据的标识(一般是值),将其分配到特定的数据库引擎中: ...
- 数据库--分库分表--垂直分表与水平分表
原文网址:数据库--分库分表--垂直分表与水平分表_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍数据库的分库分表的方案:垂直分表与水平分表. 关系型数据库本身比较容易成为系统瓶颈,单机存储容 ...
- 数据库分库分表解决方案
数据库分库分表解决方案 前言 MySQL表大小限制 分表方案 垂直分表 水平分表 按月分表 MySQL分区表 分库方案 按业务分库 按表分库 拆分后的问题及常见的解决方案 垂直拆分 跨库Join问题 ...
- 数据库分库分表中间件对比(很全)
数据库(分库分表)中间件对比 分区:对业务透明,分区只不过把存放数据的文件分成了许多小块,例如mysql中的一张表对应三个文件.MYD,MYI,frm. 根据一定的规则把数据文件(MYD)和索引文件( ...
- 亿级流量网站架构核心技术之“数据库分库分表策略”
本文节选自<亿级流量网站架构核心技术--跟开涛学搭建高可用高并发系统>一书 张开涛 著 电子工业出版社出版 小编会从留言中选择获赞最多的前五名用户免费送出此书哦!规则见文末. 数据库分库分 ...
- 一文搞懂MySQL数据库分库分表
如果数据量过大,大家一般会分库分表.分库需要注意的内容比较少,但分表需要注意的内容就多了. 工作这几年没遇过数据量特别大的业务,那些过亿的数据,因为索引设置合理,单表性能没有影响,所以实战中一直没用过 ...
- mysql 分库分表分区总结
Mysql目录结构 一个库一个目录 MyISAM引擎 InnoDB引擎 分库分表分区总结 对于分区分表 都可以进行横向(按表字段分),纵向分(按数据行分),此文暂时值考虑横向分. 对于分库:分库 分区 ...
- 数据库分库分表(sharding)系列
数据库分库分表(sharding)系列 转载于:https://www.cnblogs.com/gotodsp/p/6517478.html
最新文章
- linux进程间通信:POSIX 共享内存
- python 测试 多线程 _thread和threading模块 线程同步,线程优先级队列
- jzoj100046-收集卡片【暴力】
- php语句过滤掉html标签_php过滤html标签
- oracle 解死锁权限,讲解Oracle数据库中结束死锁进程的一般方法
- HDZ城市行深圳站|AIoT时代,如何抓住智联生活的战略机会点?
- 手把手教你部署Nagios
- 第三天.SQL语言基础
- linux jmeter 内存,怎么在Linux下改变JMeter内存
- datatable自定义表单或者导出excel按钮,搜索
- 计算机网络—4运输层(TCP连接管理、流量控制、拥塞控制)
- 一种数字全息散斑干涉测量仿真模拟系统
- UEditor(四)——表情包
- C语言哈希表uthash的使用方法详解(附下载链接)
- ​LeetCode刷题实战592:分数加减运算
- java-获取上个月的第一天和最后一天
- 使用svn报错之An error occurred while contacting the repository
- Java源码:Reference与ReferenceQueue
- 让打工人颤抖的监控系统:离职倾向、摸鱼通通都能被监测!你还敢上班摸鱼吗?...
- 学生成绩管理分析系统的设计与实现(论文+源码)_kaic