数据库开发(3) 数据表的物理实现
2023-08-09 14:53:19 # NJU # 数据库开发

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 分表解决的问题

  1. 分表后单表的并发能⼒提⾼了,磁盘I/O性能也提⾼了,写操作效率提⾼了
  2. 数据分布在不同的⽂件,磁盘I/O性能提⾼
  3. 读写锁影响的数据量变小
  4. 插⼊数据库需要重新建立索引的数据减少
  5. 分表的实现⽅式(复杂)
    • 需要业务系统配合迁移升级,⼯作量较⼤

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)数值。
  • 其特征是各个节点⽆需协调,按时间⼤致有序,且整个集群各个节点不重复。

image-20230315112840218

3.8 Holy Simplicity

除了堆⽂件之外的任何存储⽅法,都会带来复杂性

除了单库单表之外任何的存储⽅式,都会带来复杂性

选错存储⽅式会带来⼤幅度的性能降低

总结 :

  1. 测试,测试,测试
  2. 设计是最重要的
  3. 任何设计都有时效性