数据库开发(3) 数据表的物理实现
1. 物理组织
2. 数据自动分组
分区(partition)也是⼀种数据分组的⽅式
- 提⾼并发性(concurrency)和并⾏性(parallelism)
从⽽增强系统架构的可伸缩性(scalable)
应用:滑动窗口(循环分区)
2.1 循环分区
循环分区:不受数据影响的内部机制
- 分区定义为各个磁盘的存储区域
- 可以看作是随意散布数据的机制
- 保持更改带来的磁盘I/O操作的平衡
2.2 数据驱动分区
根据⼀个或多个字段中的值(partition key)来定义分区
- ⼀般叫分区视图(partitioned view),⽽MYSQL称为(merge table)
分区的实现⽅式
- 哈希分区(Hash-partitioning)
- 按照 partition key 哈希后的值分区
- 范围分区(Range-partitioning)
- 对 partition key 的取值范围进行分区,重要应用为滑动窗口,最常见的就是按时间(往往不会被修改),与业务紧密相关
- 列表分区(List-partitioning)
- 对于一张大表,把部分字段的全部记录放到某个分区
- 有些字段经常被访问,有些字段访问频率很低
要点:partition key 均匀分布,不做修改
2.3 分区是把双刃剑
分区能解决并发问题吗?
又回到了IOT类似的问题:“冲突”
- A. 通过分区键将数据聚集,利于⾼速检索
- B. 对并发执⾏的更改操作,分散的数据可以避免访问过于集中的问题
So,A or B……完全取决于您的需求
2.4 分区与数据分布
- 表非常⼤,且希望避免并发写⼊数据的冲突就⼀定要用分区吗?
- 例如客户订单明细表……
- 对分区表进⾏查询,当数据按分区键均匀分布时,收益最⼤
2.5 数据分区的最佳方法
整体改善业务处理的操作,才是选择非缺省的存储选项的目标
更新分区键会引起移动数据,似乎应该避免这么做
- 例如实现服务队列,类型(T1…Tn)状态({W|P|D})
- 按请求类型分区:进程的等待降低
- 按状态分区:轮询的开销降低
- 取决于:服务器进程的数量、轮询频率、数据的相对流量、各类型请求的处理时间、已完成请求的移除频率
对表分区有很多⽅法,显⽽易见的分区未必有效,⼀定要整体考虑
2.6 数据分区的问题
分区的⼀些缺点,⼤数据量和⾼并发下
- 如果SQL不⾛分区键,很容易造成全表锁
- 在分区中实现关联查询,就是⼀个灾难
- 分区表,隐藏复杂,使得⼯程师不可控
- DBA给OP埋坑,容易⼤打出⼿,造成同事⽭盾
3. 分区、分表、分库
分区
- 就是把⼀张表的数据分成 N 个区块,在逻辑上看最终只是⼀张表,但底层是由 N 个物理区块组成的
分表
- 就是把⼀张表按⼀定的规则分解成 N 个具有独立存储空间的实体表。系统读写时需要根据定义好的规则得到对应的字表明,然后操作它。
分库
3.1 瓶颈
IO瓶颈
- 热点数据太多,数据缓存不够,每次查询产⽣⼤量IO——分库、垂直分表
- ⽹络IO瓶颈,请求的数据太多,带宽不够、连接数过多——分库
CPU瓶颈
- SQL问题,join、group by、order by——SQL优化,构建索引
- 单表数据量过⼤,扫描⾏太多,SQL效率过低——⽔平分表
3.2 分表解决的问题
- 分表后单表的并发能⼒提⾼了,磁盘I/O性能也提⾼了,写操作效率提⾼了
- 数据分布在不同的⽂件,磁盘I/O性能提⾼
- 读写锁影响的数据量变小
- 插⼊数据库需要重新建立索引的数据减少
- 分表的实现⽅式(复杂)
- 需要业务系统配合迁移升级,⼯作量较⼤
3.3 分区和分表的区别与联系
分区和分表的目的都是减少数据库的负担,提⾼表的增删改查效率。
分区只是⼀张表中的数据的存储位置发⽣改变,分表是将⼀张表分成多张表。
- 当访问量⼤,且表数据比较⼤时,两种⽅式可以互相配合使用。
- 当访问量不⼤,但表数据比较多时,可以只进⾏分区。
常见分区分表的规则策略(类似)
3.4 分库
什么时候考虑使用分库?
- 单台DB的存储空间不够
- 随着查询量的增加单台数据库服务器已经没办法支撑
分库解决的问题
- 其主要目的是为突破单节点数据库服务器的 I/O 能⼒限制,解决数据库扩展性问题。
3.5 分库的方法
垂直拆分
- 将不存在关联关系或者需要 join 的表可以放在不同的数据库不同的服务器中。
- 按照业务垂直划分。比如:可以按照业务分为资⾦、会员、订单三个数据库。
- 需要解决的问题:跨数据库的事务、join查询等问题。
⽔平拆分
- 例如,⼤部分的站点。数据都是和用户有关,那么可以根据用户,将数据按照用户⽔平拆分。
- 按照规则划分,⼀般⽔平分库是在垂直分库之后的。比如每天处理的订单数量是海量的,可以按照⼀定的规则⽔平划分。
- 需要解决的问题:数据路由、组装。
读写分离
- 对于时效性不⾼的数据,可以通过读写分离缓解数据库压⼒。
- 需要解决的问题:在业务上区分哪些业务上是允许⼀定时间延迟的,以及数据同步问题。
3.6 分库的问题和解决方案
问题
- 事务的支持,分库分表,就变成了分布式事务
- join时跨库,跨表的问题
- 分库分表,读写分离使用了分布式,分布式为了保证强⼀致性,必然带来延迟,导致性能降低,系统的复杂度变⾼。
常用的解决⽅案:
- 对于不同的⽅式之间没有严格的界限,特点不同,侧重点不同。需要根据实际情况,结合每种⽅式的特点来进⾏处理。
- 选用第三⽅的数据库中间件(Atlas,Mycat,TDDL,DRDS),同时业务系统需要配合数据存储的升级。
3.7 全局ID生成策略
自动增长列
- 自带功能、有序、性能不错
- 单库单表没问题,但分库分表需要⼿动规划(自增偏移+步长;全局ID映射表Redis)
UUID(128位):
- 简单,全球唯⼀
- 存储和传输空间⼤,⽆序,性能⽋佳
COMB(组合)
- GUID(10字节)+时间(6字节)
Snowflake(雪花算法)
- Twitter开源的分布式ID⽣成算法,结果是long(64bit)数值。
- 其特征是各个节点⽆需协调,按时间⼤致有序,且整个集群各个节点不重复。
3.8 Holy Simplicity
除了堆⽂件之外的任何存储⽅法,都会带来复杂性
除了单库单表之外任何的存储⽅式,都会带来复杂性
选错存储⽅式会带来⼤幅度的性能降低
总结 :
- 测试,测试,测试
- 设计是最重要的
- 任何设计都有时效性