CMU 15-445 数据库课程第三课文字版 - 存储1(下)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: CMU 15-445 数据库课程第三课文字版 - 存储1(下)

4. 页布局(Page Layout)


image.png


每个页都有页头(Header),在 Header 中一般包含:

  • 页大小
  • 校验和(CheckSum):这个可能会用来检查是否有未完成的写入(例如写一半就宕机了)
  • DBMS 版本:创建这个页的数据库管理系统的版本,这个一般用于向前兼容使用,比如在某个版本后页布局发生了变化,我们可以通过这个 DBMS 版本让这个页的解析走不同的分支。
  • 压缩相关信息(Compression Information):如果对页面做了压缩,需要标注一些信息,例如使用的算法,是 lz4 还是 gzip 等等。
  • 事务可见性相关信息(Transaction Visibility):对于实现事务可见性需要的一些信息,例如是哪个事务修改了这个页的内容,以及修改后的内容在当前时间点对于谁可见等等。

页需要是自包含的,即关于如何解释和理解页内容,所需要的所有信息都必须存储在页本身中。这样,即使丢失任何一页,也不会影响其他任何一页的解析和使用。如果你把元数据存储与元组数据分开存储在不同的页,如果元数据页丢失或者损坏了,那么元组数据页也就无法解析了。这种自包含的设计,对于容灾更好


image.png


在页内部,我们有两种方式存储元组信息:

  • 面向元组存储(Tuple-oriented):即页中存储元组的数据
  • 面向日志存储(Log-oriented):即存储修改元组的日志而不是元组数据本身

首先我们来看看面向元组的存储方式设计,首先看一个很糟糕的设计


image.png


假设所有元组的字节长度都是一样的,那么实现方式比较简单,基本就是在头维护一个元组数量(这样我们就能直接跳转到要插入下一个元组的文件位置偏移,如果元组大小不一样,那么这里维护的就是要插入的文件位置偏移),如果有新的元组插入,则根据元组数量计算出要插入的位置插入然后更新头部计数。当需要删除一个元组的时候,假设删除的是 Tuple 2:


image.png


我们可以把 Tuple 2 本来占用的空间标记为未使用,而不是将 Tuple 2 之后的所有元组数据都向前移动。但是这带来了其他的问题,即存储碎片:

  • 我想再插入新的数据的时候,假设所有元组的字节长度都是一样的,我可以插入到原来 Tuple 2 的位置,但是我怎么知道这个位置有空闲的空间呢?这样就需要引入额外的记录
  • 如果元组的字节长度不一样呢?就更麻烦了

所以这种设计很不好,没人会这么做。一般采用槽页(Slotted Pages)这种设计:


image.png


这种设计被大部分数据库所采用,虽然在细节上有些不同,但是大致是这么个结构。在开头还是前面提到的页头,之后跟着两种存储结构

  • 槽数组(slot array):从前向后写,在这个数组中的元素记录所有元组在文件中的起始位置偏移。槽数组可以解耦元组位置与外部访问,相当于前面提到的间接层。我们可能在页内部移动元组(比如更新元组导致元组长度改变会标记删除原始元组在最后追加新的元组数据),通过这个槽数组外部就可以不关心这个位置变化了。
  • 实际元组数据从后向前写

思考下:我们是否可以在这一页中存储来自于不同表的数据呢?实际上没有人这么做,首先是需要额外的元数据记录每个元组所属的表,然后是表数据访问一般具有局部性,即我们访问表的某一条数据,那么之后这个表这个记录他周围的数据也可能稍后会访问到,把他们放在同一页里面一起读取效率更高,如果在一页中混合了不同表的数据就丧失了这个局部性。

还有就是如果一个元祖或者一个元祖的某个属性数据大小超过一页的大小,那我们应该怎么做?这个下节课会讲到。这节课还是假设某个元组的数据只会存在于单页上。


5. 元组结构(Tuple Layout)


元组其实就是一个字节序列,DBMS 负责解析这个字节序列。


image.png


每个元组都有一个头,包含元组的元数据,例如:

  • 元组的长度
  • 可见性信息(Visibility info):例如是哪个事务那个查询最后修改的这个元组,其他事务或者查询根据这个信息以及事务隔离级别设置来决定是否能看到这个元组。
  • NULL 位图(NULL BitMap):通过位图标记哪些列是 NULL 值

我们一般不将模式信息(例如有哪些属性列,列是什么格式的数据,是否可以为 NULL 等等)存储在每个元组的头部,这样会冗余太多数据造成存储浪费并且一页内包含更少的数据导致更新与读取效率下降。


image.png


然后是元组数据,我们通常按照创建表语句中的属性顺序去存储元组数据,大部分系统是这么做的。有的系统会对于属性进行重排序,让它能更适应内存对齐(例如 8 字节对齐)增加访问效率(内存与磁盘存储访问一般都是内存对齐的访问)。

DBMS 的其它层,如何在这种存储结构下定位一个元组的数据呢


image.png


一般所有元组都会被分配一个唯一 ID,这个 ID 中会直接或者间接包页 ID 信息和槽(或者偏移量)信息,直接包含即从 ID 中直接就可以看出页 ID 以及槽信息,间接包含则是需要解码或者查询另一个元数据表来解析出页 ID 以及槽信息。可能还会包含文件位置信息用于定位去哪个目录或者文件位置去寻找页目录定位页 ID 对应的文件位置偏移量等等。这样,我们可以通过页 ID 查询页目录找出页对应的文件以及偏移量,根据槽信息读取页中的槽数组找到元组的位置进行读取。

相关文章
|
4月前
|
存储 关系型数据库 MySQL
MySQL——数据库备份上传到阿里云OSS存储
MySQL——数据库备份上传到阿里云OSS存储
173 0
|
2月前
|
存储 关系型数据库 MySQL
PACS系统 中 dicom 文件在mysql 8.0 数据库中的 存储和读取(pydicom 库使用)
PACS系统 中 dicom 文件在mysql 8.0 数据库中的 存储和读取(pydicom 库使用)
34 2
|
3月前
|
SQL 关系型数据库 MySQL
学成在线笔记+踩坑(3)——【内容模块】课程分类查询、课程增改删、课程计划增删改查,统一异常处理+JSR303校验
课程分类查询、课程新增、统一异常处理、统一封装结果类、JSR303校验、修改课程、查询课程计划、新增/修改课程计划
学成在线笔记+踩坑(3)——【内容模块】课程分类查询、课程增改删、课程计划增删改查,统一异常处理+JSR303校验
|
3月前
|
前端开发 应用服务中间件 API
|
3月前
|
存储 SQL 专有云
支持配置审计日志的存储数据库
审计日志作为企业监管平台的重要依据,同时也是“等保三级”认证的必要考察项之一。Dataphin V4.3版本支持设置平台日志的存储数据源,帮助用户快速获取审计日志,同时介绍了不同部署模式的Dataphin如何查看审计日志的方法。
117 5
|
3月前
|
存储 NoSQL 关系型数据库
可以存储文件的数据库有哪些?
可以存储文件的数据库有哪些?
128 6
|
3月前
|
存储 NoSQL 关系型数据库
可以存储文件的数据库有哪些?
可以存储文件的数据库有哪些?
507 0
|
4月前
|
存储 缓存 负载均衡
带你认识DM 共享存储数据库集群
带你认识DM 共享存储数据库集群
82 3
|
4月前
|
存储 C# 关系型数据库
“云端融合:WPF应用无缝对接Azure与AWS——从Blob存储到RDS数据库,全面解析跨平台云服务集成的最佳实践”
【8月更文挑战第31天】本文探讨了如何将Windows Presentation Foundation(WPF)应用与Microsoft Azure和Amazon Web Services(AWS)两大主流云平台无缝集成。通过具体示例代码展示了如何利用Azure Blob Storage存储非结构化数据、Azure Cosmos DB进行分布式数据库操作;同时介绍了如何借助Amazon S3实现大规模数据存储及通过Amazon RDS简化数据库管理。这不仅提升了WPF应用的可扩展性和可用性,还降低了基础设施成本。
88 0
|
4月前
|
存储 小程序 关系型数据库
原生小程序 获取手机号并进行存储到mysql数据库
原生小程序 获取手机号并进行存储到mysql数据库

热门文章

最新文章

下一篇
无影云桌面