CMU 15-445 -- 存储篇 - 02

news2024/11/23 12:13:44

CMU 15-445 -- 存储篇 - 02

  • 引言
  • Database Storage
    • Disk Manager 简介
      • 计算机存储体系
      • 为什么不使用 OS 自带的磁盘管理模块
      • 磁盘管理模块的核心问题
      • 在文件中表示数据库
        • File Storage
        • Database Pages
          • Heap File Organization
            • Page Layout
            • Data Layout
            • Tuple Layout
            • Tuple Storage
          • Data Representation
        • System Catalogs
      • OLTP & OLAP
      • Data Storage Models


引言

本系列为 CMU 15-445 Fall 2022 Database Systems 数据库系统 [卡内基梅隆] 课程重点知识点摘录,附加个人拙见,同样借助CMU 15-445课程内容来完成MIT 6.830 lab内容。


Database Storage

Disk Manager 简介

传统的 DBMS 架构都属于 disk-oriented architecture,即假设数据主要存储在非易失的磁盘(non-volatile disk)上。于是 DBMS 中一般都有磁盘管理模块(disk manager),它主要负责数据在非易失与易失(volatile)的存储器之间的移动。

这里需要理解两点:

  • 为什么需要将数据在不同的存储器之间移动?
  • 为什么要自己来做数据移动的管理,而非利用 OS 自带的磁盘管理模块?

计算机存储体系

在这里插入图片描述
在这里插入图片描述
磁盘管理模块的存在就是为了同时获得易失性存储器的性能和非易失性存储器的容量,让 DBMS 的数据看起来像在内存中一样。

为什么不使用 OS 自带的磁盘管理模块

OS 为开发者提供了如 mmap 这样的系统调用,使开发者能够依赖 OS 自动管理数据在内外存之间的移动,那么 DBMS 为什么要重复造这样的轮子?主要原因在于,OS 的磁盘管理模块并没有、也不可能会有 DBMS 中的领域知识,因此 DBMS 比 OS 拥有更多、更充分的知识来决定数据移动的时机和数量,具体包括:

  • 将 dirty pages 按正确地顺序写到磁盘
  • 根据具体情况预获取数据
  • 定制化缓存置换(buffer replacement)策略

磁盘管理模块的核心问题

DBMS 的磁盘管理模块主要解决两个问题:

  1. (本节)如何使用磁盘文件来表示数据库的数据(元数据、索引、数据表等)

  2. 如何管理数据在内存与磁盘之间的移动


在文件中表示数据库

本节大纲

  • File Storage
  • Page Layout
  • Tuple Layout
  • Data Representation
  • System Catalogs
  • Storage Models

File Storage

DBMS 通常将自己的所有数据作为一个或多个文件存储在磁盘中,而 OS 只当它们是普通文件,并不知道如何解读这些文件。虽然 DBMS 自己造了磁盘管理模块,但 DBMS 一般不会自己造文件系统,主要原因如下:

  • 通过 DIY 文件系统获得的性能提升在 10% - 15% 之间
  • 使用 DIY 文件系统将使得 DBMS 的可移植性大大下降

综合考虑,这不值得。


Database Pages

OS 的文件系统通常将文件切分成 pages 进行管理,DBMS 也不例外。通常 page 是固定大小的一块数据,每个 page 内部可能存储着 tuples、meta-data、indexes 以及 logs 等等,大多数 DBMS 不会把不同类型数据存储在同一个 page 上。每个 page 带着一个唯一的 id,DBMS 使用一个 indirection layer 将 page id 与数据实际存储的物理位置关联起来。

注意:有几个不同的 page 概念需要分清楚

  • Hardware Page:通常大小为 4KB
  • OS Page: 通常大小为 4KB
  • Database Page:(1-16KB)

不同 DBMS 管理 pages 的方式不同,主要分为以下几种:

  • Heap File Organization
  • Sequential/Sorted File Organization
  • Hashing File Organization

Heap File Organization

heap file 指的是一个无序的 pages 集合,pages 管理模块需要记录哪些 pages 已经被使用,而哪些 pages 尚未被使用。那么具体如何来记录和管理呢?主要有以下两种方法 Linked List 和 Page Directory。

Linked List (双向链表)

  • pages 管理模块维护一个 header page,后者维护两个 page 列表:
  • free page list
  • data page list

如下图所示:
在这里插入图片描述

Page Directory(页目录)

  • pages 管理模块维护着一些特殊的 pages(directory pages),它们负责记录 data pages 的使用情况,DBMS 需要保证 directory pages 与 data pages 同步。
Page Layout
  • 每个 page 被分为两个部分:header 和 data,如下图所示:

在这里插入图片描述
header 中通常包含以下信息:

  • Page Size
  • Checksum
  • DBMS Version
  • Transaction Visibility
  • Compression Information
Data Layout
  • data 中记录着真正存储的数据,数据记录的形式主要有两种:
    • Tuple-oriented:记录数据本身
    • Log-structured:记录数据的操作日志

Tuple Oriented

  • Strawman Idea: 在 header 中记录 tuple 的个数,然后不断的往下 append 即可,如下图所示:
    在这里插入图片描述

这种方法有明显的两个缺点:

  • 一旦出现删除操作,每次插入就需要遍历一遍,寻找空位,否则就会出现空间浪费
  • 无法处理变长的数据记录(tuple)

为了解决这两个问题,就产生了 slotted pages。

  • Slotted Pages, 如下图所示,header 中的 slot array 记录每个 slot 的信息,如大小、位移等

在这里插入图片描述

  • 新增记录时:在 slot array 中新增一条记录,记录着tuple的入口地址。slot array 与 data 从 page 的两端向中间生长,二者相遇时,就认为这个 page 已经满了
  • 删除记录时:假设删除 tuple #3,可以将 slot array 中的第三条记录删除,并将 tuple #4 及其以后的数据都都向下移动,填补 tuple #3 的空位。而这些细节对于 page 的使用者来说是透明的
  • 处理定长和变长 tuple 数据都游刃有余

目前大部分 DBMS 都采用这种结构的 pages。


Log Structured

log-structured 只存储日志记录,如下图所示:
在这里插入图片描述
每次记录新的操作日志即可,增删改的操作都很快,但有得必有失,在查询场景下,就需要遍历 page 信息来生成数据才能返回查询结果。为了加快查询效率,通常会对操作日志在记录 id 上建立索引,如下图所示:
在这里插入图片描述
当然,定期压缩日志也是不可或缺的
在这里插入图片描述


Tuple Layout

上节讨论了 page 的 layout 可以分成 header 与 data 两部分,而 data 部分又分为 tuple-oriented 和 log structured 两种,那么在 tuple-oriented 的 layout 中,DMBS 如何存储 tuple 本身呢?

由于 tuple 本身还有别的元信息,如:

  • Visibility Info (concurrency control):即 tuple 粒度的权限和并发控制
  • Bit Map for NULL values

因此不难猜到,tuple 中还可以分为 header 和 data 两部分,如下图所示:
在这里插入图片描述

通常 DBMS 会按照你在建表时候指定的顺序(并不绝对)来存储 tuple 的 attribute data,如下图所示:
在这里插入图片描述
有时候,为了提高操作性能,DBMS 会在存储层面上将有关联的表的数据预先 join 起来,称作 denormalize,如下图所示:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
如果表 bar 与表 foo 经常需要被 join 起来,那么二者可以在存储阶段就预先 join 到一起,这么做当然有利有弊:

  • 利:减少 I/O
  • 弊:更新操作复杂化

在 DBMS 层面上,由于它需要跟踪每一个 tuple,因此通常会给每个 tuple 赋予一个唯一的标识符(record identifier),通常这个标识符由 page_id + offset/slot 组成,有时候也会包含文件信息。这属于 DBMS 实现的细节,虽然它是唯一的,但 DBMS 可能随时修改它,因此 DBMS 上层的应用不应该依赖于它去实现自己的功能。


Tuple Storage

在文件中,一个 tuple 无非就是一串字节,而如何解读这些字节中隐含的数据类型和数据本身,就是 DBMS 的工作。DBMS 的 catelogs 保存着数据表的 schema 信息,有了这些信息,DBMS 就能够解读 tuple 数据。


Data Representation

数据库支持的数据类型主要包含:

类型实现
INTEGER/BIGINT/SMALLINT/TINYINTC/C++ Representation
FLOAT/REAL vs. NUMERIC/DECIMALIEEE-754 Standard / Fixed-point Decimals
VARCHAR/VARBINARY/TEXT/BLOBHeader with length, followed by data bytes
TIME/DATE/TIMESTAMP32/64-bit integer of (micro) seconds since Unix epoch

FLOAT/REAL/DOUBLE vs. NUMERIC/DECIMAL

float, real, double 类型的数字按照 IEEE-754 标准存储,它们都是 fixed-precision,在 range 和 precision 上作了取舍,无法保证精确度要求很高的计算的正确性,如:

#include <stdio.h>

int main(int argc, char* argv[]) {
    float x = 0.1;
    float y = 0.2;
    printf("x+y = %.20f\n", x+y)
    printf("0.3 = %.20f\n", 0.3)
}

// =>
// x+y = 0.30000001192092895508
// 0.3 = 0.29999999999999998890

如果希望允许数据精确到任意精度(arbitrary precision),则可以使用 numeric/decimal 类型类存储,它们就像 VARCHAR 一般,长度不定,以 Postgres 的 NUMERIC 为例,它的实际数据结构如下所示:

typedef unsigned char NumericDigit;
typedef struct {
    int ndigits;           // # of Digits
    int weight;            // Weight of 1st Digit
    int scale;             // Scale Factor
    int sign;              // Positive/Negative/NaN
    NumericDigit * digits; // Digit Storage
} numeric;

Large Values

大部分 DBMSs 不允许一个 tuple 中的数据超过一个 page 大小,如果想要存储这样的 large values,DBMS 通常会使用 overflow/TOAST page:
在这里插入图片描述


External Value Storage:

  • 一些 DBMSs 甚至允许你在外部存储二进制大文件,即 BLOB,但 DBMSs 一般不会负责管理外部文件,没有 durability protections 和 transaction protections,而且数据库的 dump 操作不会对外部文件起作用,转移数据时需要单独处理。

System Catalogs

除了数据本身,DBMS 还需要存储数据的元数据,即数据字典,它们包括:

  • Table, columns, indexes, views
  • Users, permissions
  • Internal statistics

几乎所有 DBMSs 都将这些元数据也存储在一个特定的数据库中,它们本身也会被存储为 table、tuple。根据 SQL-92 标准,你可以通过 INFORMATION_SCHEMA 数据库来查询这些数据库的元信息,但一般 DBMSs 都会提供更便捷的命令来查询这些信息,示例如下:

# sql92
SELECT *
  FROM INFORMATION_SCHEMA.TABLES
 WHERE table_catalog = '<db name>';
 
SELECT *
  FROM INFORMATION_SCHEMA.TABLES
 WHERE table_name = 'student';

# postgress
\d;
\d student; 

# mysql
SHOW TABLES;
DESCRIBE student;

# sqllite
.tables;
.schema student;

OLTP & OLAP

数据库的应用场景大体可以用两个维度来描述:操作复杂度和读写分布,如下图所示:
在这里插入图片描述

坐标轴左下角是 OLTP(On-line Transaction Processing),OLTP 场景包含简单的读写语句,且每个语句都只操作数据库中的一小部分数据,举例如下:

SELECT P.*, R.*
  FROM pages AS P
 INNER JOIN revisions AS R
    ON P.latest = R.revID
 WHERE P.pageID = ?;
 
UPDATE useracct
   SET lastLogin = NOW(),
       hostname = ?
 WHERE userID = ?
 
 INSERT INTO revisions
 VALUES (?,?...,?)

在坐标轴右上角是 OLAP(On-line Analytical Processing),OLAP 主要处理复杂的,需要检索大量数据并聚合的操作,举例如下:

SELECT COUNT(U.lastLogin)
       EXTRACT (month FROM U.lastLogin) AS month
  FROM useracct AS U
 WHERE U.hostname LIKE '%.gov'
 GROUP BY EXTRACT(month FROM U.lastLogin);

通常 OLAP 操作的就是 OLTP 应用搜集的数据


Data Storage Models

Relational Data Model 将数据的 attributes 组合成 tuple,将结构相似的 tuple 组合成 relation,但它并没有指定这些 relation 中的 tuple,以及 tuple 的 attributes 的存储方式。一个 tuple 的所有 attributes 并不需要都存储在同一个 page 中,它们的实际存储方式可以根据数据库应用场景优化,如 OLTP 和 OLAP。

目前常见的 Data Storage Models 包括:

  • 行存储:N-ary Storage Model (NSM)
  • 列存储:Decomposition Storage Model (DSM)

NSM

NSM 将一个 tuple 的所有 attributes 在 page 中连续地存储,这种存储方式非常适合 OLTP 场景,如下图所示:
在这里插入图片描述
DBMS 针对一些常用 attributes 建立 Index,如例子中的 userID,一个查询语句通过 Index 找到相应的 tuples,返回查询结果,流程如下:
在这里插入图片描述
但对于一个典型的 OLAP 查询,如下图所示:
在这里插入图片描述
尽管整个查询只涉及到 tuple 的 hostname 与 lastLogin 两个 attributes,但查询过程中仍然需要读取 tuple 的所有 attributes。

总结一下,NSM 的优缺点如下:

  • Advantages
    • 高效插入、更新、删除,涉及表中小部分 tuples
    • 有利于需要整个 tuple (所有 attributes)的查询
  • Disadvantages
    • 不利于需要检索表内大部分 tuples,或者只需要一小部分 attributes 的查询

DSM

DSM 将所有 tuples 的单个 attribute 连续地存储在一个 page 中,这种存储方式特别适用于 OLAP 场景,如下图所示:

在这里插入图片描述
这时候,就可以优雅地处理 OLAP 查询浪费 I/O 的问题:
在这里插入图片描述
由于 DSM 把 attributes 分开存储,也引入了新的问题,比如:

如何跟踪每个 tuple 的不同 attributes?可能的解决方案有:

  1. Fixed-length Offsets:每个 attribute 都是定长的,直接靠 offset 来跟踪(常用)
  2. Embedded Tuple Ids:在每个 attribute 前面都加上 tupleID

如下图所示:

在这里插入图片描述
总结一下,DSM 的优缺点如下:

  • Advantages
    • 减少 I/O 操作
    • 更好的查询处理和数据压缩支持
  • Disadvantages
    • 涉及少量 tuples、多数 attributes 的查询低效

对应课程文档–上
对应课程文档-- 下


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/703221.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows Update当前无法检查更新怎么办?

当进行Windows更新或升级时&#xff0c;可能会提示“Windows Update当前无法检查更新&#xff0c;因为未运行服务。您可能需要重新启动计算机”。而当重启也无法解决问题时&#xff0c;我们该怎么办呢&#xff1f;下面我们就来了解一下。 1、删除Software Distribution文件夹中…

Hyperledger Fabric交易流程分析

1、交易流程 客户端利用受支持的SDK(Golang、Java、Node、Python)提供的API构建交易提案请求&#xff0c;将交易事务提案打包成为一个正确的格式。交易提案包含如下要素&#xff1a; ①channelID:通道信息。 ②chaincodelD:要调用的链码信息。 ③timestamp:时间戳。 ④sign:客户…

百度智能车竞赛丝绸之路2——手柄控制

百度智能车竞赛丝绸之路1——智能车设计与编程实现控制 百度智能车竞赛丝绸之路2——手柄控制 一、机器人设计 二、实现原理 本教程使用Python的Serial库和Struct二进制数据解析库去实现Xbox手柄百度大脑学习开发板&#xff08;上位机&#xff09;和机器人控制器&#xff08;…

9小时通关 黑马新教程发布,含重磅项目~

随着测试行业的蓬勃发展&#xff0c;对从业者的要求越来越高&#xff0c;自动化测试已经成为软件测试中一个重要组成部分&#xff0c;广泛应用于各行各业。甚至&#xff0c;在圈子中还流传着这样一句话&#xff1a;学好测试自动化&#xff0c;年薪30万不在话下&#xff01; 今…

Qt读写文件

一、界面 项目文件结构 样例文件 中芯国际近期做出了两个重要改变&#xff1a;第一个是调整财报披露方式&#xff0c;不再公布芯片制程的营收占比&#xff0c;而只公布晶圆尺寸的营收占比&#xff1b;第二个是撤消14nm工艺的官方展示&#xff0c;只有28nm、40nm及以上的芯片工…

LeNet基础

目录 1.LeNet简介 1.1基本介绍 1.2网络结构 2.LetNet在pytorch中的使用 2.1首先定义模型 2.2初始化数据集&#xff0c;初始化模型&#xff0c;同时训练数据。 2.3 训练结果​编辑 2.4绘制曲线 1.LeNet简介 1.1基本介绍 LeNet&#xff08;LeNet-5&#xff09;是历史上第…

磁盘阵列(RAID)

什么是磁盘阵列 磁盘阵列&#xff08;RAID&#xff09;是一种将多个物理硬盘组合成一个逻辑存储单元的技术。这种技术可以提高数据存储的可靠性、性能或容量&#xff0c;并且可以在某些情况下提供备份和灾难恢复功能。 RAID技术可以通过在多个硬盘之间分配数据来提高性能。例…

事务处理相关

目录 步骤1.创建一个数据表 步骤2:创建项目导入jar包 步骤3:根据表创建模型类 步骤5:创建Service接口和实现类 步骤6:添加jdbc.properties文件 步骤7:创建JdbcConfig配置类 步骤8:创建MybatisConfig配置类 步骤9:创建SpringConfig配置类 步骤10:编写测试类 开启事务 1…

电磁阀原理精髓

一、引用 电磁阀在液/气路系统中&#xff0c;用来实现液路的通断或液流方向的改变&#xff0c;它一般具有一个可以在线圈电磁力驱动下滑动的阀芯&#xff0c;阀芯在不同的位置时&#xff0c;电磁阀的通路也就不同。 阀芯在线圈不通电时处在甲位置&#xff0c;在线圈通电时处在…

算法与数据结构-链表

文章目录 链表和数组的区别常见的链表类型单链表循环链表双向链表 总结 链表和数组的区别 相比数组&#xff0c;链表是一种稍微复杂一点的数据结构。对于初学者来说&#xff0c;掌握起来也要比数组稍难一些。这两个非常基础、非常常用的数据结构&#xff0c;我们常常会放到一块…

Python基础 - global nonlocal

global global作为全局变量的标识符&#xff0c;修饰变量后标识该变量是全局变量 global关键字可以用在任何地方&#xff0c;包括最上层函数中和嵌套函数中 实例1&#xff1a;如下代码&#xff0c;定义了两个x&#xff0c;并且赋值不同 直接调用print(x) 打印的是全局变量x的…

号外!MyEclipse 2023.1.1已发布,更好支持Vue框架

MyEclipse 2023.1.1是之前发布的2023.1.0的一个小错误修复版本&#xff0c;如果您已经安装了MyEclipse 2023&#xff0c;只需检查产品中的更新 (Help > Check for Updates…) 就可以选择这个新版本。或者&#xff0c;下载我们更新的离线安装程序来安装2023.1.1。 MyEclipse…

C# WPF应用使用visual studio的安装程序类的一些坑

重写installer实现自定义安装程序时&#xff0c;项目类型要选择 类库(.NET Framework) 否则会出现命名空间System.Configuration不存在Install的报错 有些可能想实现安装完自动启动应用的功能&#xff0c;就需要获取installer安装路径 var s Context.Parameters["assem…

【Java】网络编程与Socket套接字、UDP编程和TCP编程实现客户端和服务端通信

网络编程客户端和服务器Socket套接字流套接字TCP数据报套接字UDP对比TCP与UDP UDP编程DatagramSocket构造方法:普通方法&#xff1a; DatagramPacket构造方法:普通方法&#xff1a; 实现 TCP编程ServerSocket构造方法普通方法 Socket构造方法普通方法 实现 网络编程 为什么需要…

MyBatis-Plus 实现PostgreSQL数据库jsonb类型的保存

文章目录 在 handle 包下新建Jsonb处理类方式一方式二 PostgreSQL jsonb类型示例新建数据库表含有jsonb类型创建实体类创建Control 发起请求 在 handle 包下新建Jsonb处理类 方式一 import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFea…

低代码开发平台到底省掉了哪些成本?可能大家一直错了

低代码到底是否真正可以降低研发成本&#xff1f;是否每个团队都适合&#xff1f;如果能降低&#xff0c;到底是降低的什么成本&#xff1f;其实我觉得这个是我们每个技术交付团队应该在使用任何产品之前都要考虑的问题。 在我们考虑低代码是否能降低成本的问题前&#xff0c;…

【Python】一文带你学会数据结构中的字典、集合

作者主页&#xff1a;爱笑的男孩。的博客_CSDN博客-深度学习,活动,python领域博主爱笑的男孩。擅长深度学习,活动,python,等方面的知识,爱笑的男孩。关注算法,python,计算机视觉,图像处理,深度学习,pytorch,神经网络,opencv领域.https://blog.csdn.net/Code_and516?typeblog个…

一步一步学OAK之九:通过OAK相机实现视频帧旋转

目录 Setup 1: 创建文件Setup 2: 安装依赖Setup 3: 导入需要的包Setup 4: 定义变量Setup 5: 定义旋转矩形的四个顶点坐标Setup 6: 创建pipelineSetup 7: 创建节点Setup 8: 设置属性Setup 9: 建立链接Setup 10: 连接设备并启动管道Setup 11: 创建与DepthAI设备通信的输入队列和输…

C#核心知识回顾——2.拓展方法、运算符重载、分部类、里氏替换

1.拓展方法 为现有非静态变量类型添加新方法 1.提升程序拓展性 2.不需要再对象中重新写方法 3.不需要继承来添加方法 4.为别人封装的类型写额外的方法 特点&#xff1a; 1.一定是写在静态类中 2.一定是个静态函数 3.第一个参数为拓展目标 4.第一个参数用this修饰 /// <sum…

element table表格支持添加编辑校验

实现效果&#xff1a; 将table表格与form表单结合使用 &#xff08;用el-form外层包裹el-table结合rules进行校验&#xff09; 代码实现 <template><div><el-card class"box-card" shadow"never"><div><el-buttonsize"m…