本专栏是对CMU15445的笔记的翻译,原文地址: https:// 15445.courses.cs.cmu.edu /fall2020/notes/04-storage2.pdf
1 数据表示
元组里的数据本质上就是字节数组,DBMS知道如何去解释这些字节到真正的属性值。数据表示模式是DBMS如何通过字节去存储值。
有5种高层数据类型可以存储在元组中:整数、浮点数、固定精度数字、变长数据、日期/时间。
Integers(整数)
大多数DBMS使用IEEE-754标准的C/C++类型去编码整数,这些值是定长的。
例子:INTEGER, BIGINT, SMALLINT, TINYINT
Variable Precision Numbers(浮点数)
这些不精确的、精度变化的数字(浮点数)使用IEEE-754标准的C/C++类型去编码,这些值也是定长的。
操作浮点数的速度比操作固定精度的数字的速度要快,因为CPU可以直接对浮点数直接进行操作。然而,由于数字表示是不精确的,所以在计算的时候会出现误差。
例子:FLOAT, REAL
Fixed-Point Precision Numbers(固定精度数字)
这些是具有任意精度和小数位数的数字类型。它们通常以精确的,可变长度的二进制表示(像字符串一样)存储,另外还会存储元数据,这些元数据告诉系统数据的长度和小数点的位置。
当数据精确性要求很高的时候可以使用这种类型,但DBMS会花费更高的代价去进行计算。
例子:NUMERIC, DECIMAL
Variable-Length Data(变长数据)
他们表示任意长度的数据类型,他们通常在头部存储字符串的长度,以便跳转到下一个值,同时可能还包含数据的校验和。
大多数DBMS不允许一个元组大小超过单个页大小。有些则将数据存储在一个特别的”溢出“页上,并在元组上存储这个页的引用信息。
也有一些系统会存储大数据在额外的文件上,并在元组中记录文件指针。例如,如果数据库存储图片信息,DBMS会直接将图片存储在额外的文件中,而不是让它们在数据库中占用大量空间。这样做的缺点是DBMS无法操纵这个文件的内容,因此没有持久性和事务的保证。
例子:VARCHAR, VARBINARY, TEXT, BLOB
Dates and Times(日期和时间)
日期/时间的表示因系统的不同而不同。从unix时代开始,时间通常表示为单位时间(微/毫)秒(时间戳)。
例子:TIME, DATE, TIMESTAMP
System Catalogs(系统目录)
为了让DBMS解析元组,它需要维护一个内部的目录去告诉数据库的一些元信息。元信息包含数据库拥有哪些表和列以及他们的类型和值的顺序等信息。
大多数DBMS以表的形式在内部存储他们的目录,他们使用特殊的代码”引导“这些目录表。
2 工作类型
数据库系统有许多不同的工作类型,工作类型指的是系统处理的请求的一般类型。这个课程将会专注于2个类型:在线事务处理(OLTP),在线分析处理(OLAP)。
OLTP: Online Transaction Processing(在线事务处理)
OLTP工作类型的特点是快速、短时间运行的操作,一次操作单个实体的简单查询和重复查询。
OLTP工作类型的一个例子是Amazon storefront。用户可以添加商品到购物车,可以下单购买,但是这些操作只影响一个账户。
OLAP: Online Analytical Processing(在线分析处理)
OLAP工作类型的特点是长时间、复杂的查询,对数据库大量数据的读取。在OLAP工作类型中,数据库系统专注于分析,并从OLTP数据库中获取新数据(一般为同步链路)。
OLAP工作类型的一个例子是Amazon对某些地理位置计算一个月内购买最多的5件商品。
HTAP: Hybrid Transaction + Analytical Processing(混合事务分析处理)
最近流行的一种新型工作类型是HTAP,它类似于在同一个数据库上同时执行OLTP和OLAP的组合。
3 存储模型
在页中存储元组有很多种方式,到目前为止,我们假设n维存储模型。
N-Ary Storage Model(NSM n维存储模型)
在n维存储模型中,DBMS将一个元组的所有属性连续的存储在单个页中,所以NSM又称为“行存”。这种方法是OLTP工作类型的理想选择,因为在OLTP场景下,数据是大量插入的,事务只操作单一的实体。DBMS只需要单次获取就能获取一个元组的所有属性。
优点:
- 快速插入、更新和删除。
- 对需要整个元组的查询友好。
缺点:
- 对大范围的扫描和查找一部分属性不友好,因为在查询中可能会获取不必要的数据来污染缓冲池。
Decomposition Storage Model(DSM 分解存储模型)
在分解存储模型中,DBMS将一个单独的属性(列)连续的存在一个块中。因此,这也被称为“列存”。该模型非常适合许多具有只读查询的OLAP工作类型,OLAP经常对一部分属性进行大范围扫描。
优点:
- 减少查询过程中浪费的数据,因为DBMS只读取查询所需的数据(制度去查询所需的属性)。
- 由于对同一属性的所有值连续存储,因此可以获得更好的压缩性能(或使用特定的压缩)。
缺点:
- 由于每个元组被存在不同的地方,因此对文件的点查、插入、更新和删除不友好。
为了将列存的元组组合回去,一般有2种常见的方法:
大多数使用的方法是固定长度的偏移。假设每个属性都是固定长度的,DBMS可以计算出每个元组中每个属性的偏移,然后当想要一个特定元组的属性的时候,它知道如何去跳转到某个文件某个位置。为了容纳可变长度的字段,系统可以填充字段来达到相同长度或者使用固定长度的字典来映射值(将超出长度的值存到另外的文件中并用字典记录偏移)。
另一个小众的方式是使用嵌入式元组id。对每个在列中的属性,DBMS同时存储一个元组id(例如主键)。系统会存储一个映射告诉如何找到每个属性id所对应的位置。但这个方法会浪费很多的存储空间,因为每个属性都会存储一个元组id。