首页 > IT职业 > > 关系型数据库存储管理
关系型数据库依赖于《大型共享数据库的数据关系模型》建立了数据模型,而为了能够在现在计算机系统上能够正确、高效的运行,关系型数据库做了大量的工作。本章将会结合之前的《I/O的5分钟法则》和《存储器系统》进行介绍。
现代商业数据库应用中,主要有两种基本类型的DBMS存储管理器:
根据《存储器系统》的学习,我们能够知道程序的局部性原理。而数据库管理系统更需要充分考虑局部性原理,来提高其性能。
而根据《存储器系统》的学习,我们能够知道存储器的层次模型,这里主要使用到硬盘以及主存两层存储结构:

下面将通过对磁盘和主存的空间局部性以及时间局部性进行介绍。
数据库的数据存储方式和块设备的存储方式是不相同的。能够更好的利用数据库中的数据逻辑组织方式进行存储,这将会大大提高数据库的性能。而对于DBMS来说,控制数据空间局部性的最好的方式就是直接存储到“原始”磁盘设备中,也就是裸设备,从而绕过文件系统。裸设备地址通常对应于存储位置的物理临近性,可以使数据库到达性能峰值。大多数商业数据库支持裸设备,例如Oracle和DB2。
这样做虽然有最优的性能,但带来了一些问题:
裸设备访问的一种替代方式是,由DBMS在操作系统的文件管理中创建一个非常大的文件,然后采用数据在文件中的地址偏移量来定位数据。这个文件在本质上可以视为磁盘页面上的一个线性阵列。这可以避免裸设备访问的一些问题,并且仍然能够提供相当好的性能。在大多数流行的文件系统中,如果你分配一个非常大的文件到一个空白磁盘上,文件的地址将会和存储位置的临近性非常吻合。因此,这是一个裸设备访问的很好的近似方法,而且不需要直接访问裸设备接口。大多数虚拟化存储系统在设计上,都会把文件中临近的地址放置到邻近的物理位置中。因此,随着时间的推移,使用大文件而不是裸设备的相对控制代价,已经变得越来越不明显了。
而有的DBMS,如PostgreSQL使用了小文件作为存储管理组织方式。最初这样设计的目的是避免不同操作系统文件大小的限制,提高可移植性;其次减少编码复杂度,更多地调用文件系统接口,比如错误机制、资源限制等。但是其空间的局部性利用较差。尤其是数据库行为的不可控,会带来数据逻辑位置与物理位置临近性相差极大,从而造成性能下降。
同样的,为了实现更好的时间局部性,大多数数据库商业厂商还支持自定义调整页面大小的功能(可供选择的页面尺寸应该是一个文件系统或者裸设备所使用的页面尺寸的倍数[1]),使其能够更好的适合预期的工作负载。DB2和Oracle支持此功能。而其他厂商基本不支持此功能,因为这会带来相当大的管理成本、编码复杂度。
为了更好地性能,DBMS将会对磁盘上的数据进行cache。几乎所有的DBMS都具有自己的buffer。而且所有的数据修改也都是在主存进行修改的。
为了减少不必要的CPU消耗,硬盘中的块会直接拷贝到主存内,不会发生格式的变化。其次,固定大小格式的页,也有助于减少通用技术导致的外部碎片和压缩方面的内存管理复杂度。
为了提高主存的空间局部性,一般数据库都会在数据库启动时,开辟一块比较大的、连续的内存区域。其次,会根据不同用途的数据进行分块存储。尽可能地在使用数据时,调用邻近的数据。之前提到的硬盘空间局部性应用时,有两种存储管理器,使用裸设备以及通过文件系统完成存储管理。一般的数据库存储模型(以PostgreSQL为例)为数据库buffer层、文件系统cache层以及硬盘或磁盘,如下图:

由于数据库写入时,需要先经过文件系统cache层,然后写入磁盘或硬盘。这样其实就有一个延迟。这就造成了以下三个问题:
为了保证主存的时间局部性,操作系统经常使用页面替换机制,比如LRU和CLOCK,在许多数据库访问模式下面都表现得非常糟糕。研究人员提出了各种替代方案,比如,一些方案试图利用查询执行计划信息来调整替换策略。今天,大多数系统使用简单的增强LRU方案来进行全表扫描。一个出现在研究文献中并且已经运用到商业系统中的方案是LRU-2。商业系统中使用的另一种机制是,根据页面类型来确定替换策略,例如,B+-树的根节点的替换策略,可能和堆文件中的页面替换策略不同。
而最近的硬件发展形式,使得非常大的buffer成为可能。现在已经有许多内存数据库诞生,能够提供非常高的性能改善,比如我们常用的12306余票查询系统。当然大缓存池在非内存数据库中虽然提供性能改善的方案,但是同时也带来了一定问题,比如重启恢复速度以及高效的检查点。

检查点机制,由于数据库的写操作非常复杂,难以简单的判断写顺序。所以造成了非常多的随机写操作,而如果我们遇到写请求就直接进行磁盘写入,那将会带来非常大的性能损耗。所以一般关系型数据库都提供了检查点机制,以此将随机写变为尽可能地集中写入。就像我们的红绿灯。

索引,一般数据库中的表经常会以一个或几个字段作为查询条件。所以可以以其中一个或几个字段作为索引键。将这部分数据库按照一定格式进行组织,提高查询效率。这大大提高了空间局部性的利用。

使用LLVM对查询计划进行即时编译(JIT),提高cache的空间局部性利用率。LLVM在对查询计划进行汇编级优化,可以将数据集中推送到CPU Cache内,提高cache利用率。
其次,LLVM对程序指令进行优化,减少虚函数调用以及冗余逻辑的指令,从而使得指令的局部性变好,提高程序性能。

列式存储,现在有些业务中,存在大量列的表,但是用的时候仅仅只用一定的列进行读取。如果按照行式存储,那么每次读取都会读取大量无效的数据列,造成不必要的性能损失。而列存恰恰能够解决此问题。
其次还有许多方案可以提供局部性的使用,比如流式数据库(只保留结果),比如更加高效的页替换方式(利用AI进行预测页的变化,提供预读、后写机制),比如新的压缩方式(我接触过两种压缩方案,一个使用FPGA对数据压缩的方式,一种是压缩后检索的算法),AI压缩等等,这里就不再列举。
看过《存储器系统》的都能知道,不同种类的存储器有着自己的发展趋势:

从上图,可以看到,机械硬盘或磁盘近几年的发展趋于平稳,机械硬盘有机械臂,而机械臂的旋转速度,他和摩尔定律是有差别的。我这里有一组数据,磁盘密度18个月翻一番,带宽增长速度与磁盘密度成平方根的关系(与旋转速度成线性关系)。但是机械臂的移动速度增长率较低,约为每年7%。借鉴L1,L2,L3的发展,DRAM和磁盘的差距越来越大,那么势必需要有新的存储硬件来填补磁盘和DRAM之间的空隙,所以SSD诞生了,且有渐渐取代磁盘的趋势(未来磁盘可能作为原有的网络硬盘一样,只处理冷数据或者备份数据)。现在SSD还在迅速发展,短时间内,还不会被取代。虽然SSD的性能相比磁盘有很大提升,但是我们能够看到SSD和DRAM还是有较大的差距,而Intel现在推出了持久化内存的设备,能够填补SSD到DRAM之间的空隙。

而大部门DBMS都是基于磁盘进行设计的,所以应对现有的SSD或者持久化内存都需要做出一定变化。这将是数据库开发者未来前进的方向之一。
甚至在未来,随着上面变化趋势的间隙逐渐拉开距离,硬件的成本降低,还会有新的硬件进行填补。那么如何让数据库快速适应这种变化,也需要进行提前应对。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31509949/viewspace-3120597/ ,如需转载,请注明出处,否则将追究法律责任。