注册
DM存储结构、数据结构与内存结构学习心得
专栏/技术分享/ 文章详情 /

DM存储结构、数据结构与内存结构学习心得

夜未央丶 2023/08/03 1844 2 0
摘要

前言

为了方便日后DM数据库问题排查和性能调优等工作,稿主学习了DM存储结构、数据结构、内存结构设计,本文是稿主结合官网和自身理解总结的学习心得

存储结构

DM的数据文件为*.DBF,如下图

图片122.png

DM的存储结构分为数据库、表空间、段、簇、页等,它们的关系如下图
图片4.png

数据库由一个或多个表空间组成;
每个表空间由一个或多个数据文件组成;
每个数据文件由一个或多个簇组成;
段是簇的上级逻辑单元,一个段可以跨多个数据文件;
簇由磁盘上连续的页组成,一个簇总是在一个数据文件中;
页是数据库中最小的分配单元,也是数据库中使用的最小的 IO 单元。

以下存储设计上几个关键的知识要点

几个系统表空间

1.SYSTEM 表空间存放了有关 DM 数据库的字典信息,用户不能在 SYSTEM 表空间创建表和索引。SYSTEM 表空间又称为系统表空间。
2.ROLL 表空间完全由 DM 数据库自动维护,用户无需干预。该表空间用来存放事务运行过程中执行 DML 操作之前的值,从而为访问该表的其他用户提供表数据的读一致性视图。
3.MAIN 表空间在初始化库的时候,就会自动创建一个大小为 128M 的数据文件 MAIN.DBF,以及一个 HMAIN 目录作为 HUGE 数据文件路径,因此 MAIN 表空间为混合表空间。在创建用户时,如果没有指定默认表空间,则系统自动指定 MAIN 表空间为用户默认的表空间。
4.TEMP 表空间完全由 DM 数据库自动维护。当用户的 SQL 语句需要磁盘空间来完成某个操作时,DM 数据库会从 TEMP 表空间分配临时段。如创建索引、无法在内存中完成的排序操作、SQL 语句中间结果集以及用户创建的临时表等都会使用到 TEMP 表空间。

记录

DM 规定每条记录的总长度不能超过页面大小的一半。

数据页

需要注意一个重要的参数FILLFACTOR, 该值在创建表/索引时可以指定也可以修改数据库参数DEFAULT_FILLFACTOR 指定默认值。

FILLFACTOR 指定插入数据时数据页的充满程度,取值范围从 0 到
100。默认值为 0,等价于 100,表示全满填充,未充满的空间可供页内的数据更新时使用。插入数据时填充比例的值越低,可由新数据使用的空间就越多;更新数据时填充比例的值越大,更新导致出现的页分裂的几率越大;
update 和upsert 场景需要特别注意这个参数!!!!!

数据簇

一个簇是连续的 16 或者 32 个数据页。
分配簇
当 DM 数据库的表空间为新的簇分配空闲空间时,首先在表空间按文件从小到大的顺序在各个数据文件中查找可用的空闲簇(即删除数据/索引后被释放的簇),找到后进行分配;如果各数据文件都没有空闲簇,则在各数据文件中查找空闲空间足够的,将需要的空间先进行格式化,然后进行分配;如果各文件的空闲空间也不够,则选一个数据文件进行扩充。
释放簇
当用户删除了表中所有记录时,DM 数据库仍然会为该表保留 1-2 个簇供后续使用。若用户使用 DROP 语句来删除表/索引对象,则此表/索引对应的段以及段中包含的簇全部收回,并供存储于此表空间的其他模式对象使用。

段可以包含来自不同文件的簇,即一个段可以跨越不同的文件。由于簇的数量是按需分配的,数据段中的不同簇在磁盘上不一定连续。

临时段

临时表空间(TEMP表空间)包含的段。可以为临时表空间规划独立的磁盘,段可以包含来自不同文件的簇。
除了临时表外,SQL执行的中间结果很可能用到临时段。如排序,如果排序无法在内存中完成,就需要用到临时段

回滚段

回滚表空间(ROLL表空间)包含的段。回滚段中保存了用于恢复数据库操作的信息。

问题思考

1.为什么需要簇和段?有数据页就不行了吗
簇:有了簇后 写入数据时可以一次性分配多个数据叶,减少配分次数。
段:段可以包含来自不同文件的簇,不同文件可以落到不同磁盘上,这样可以提升IO能力

2.回滚表空间的大小是否有上限?是否存在大事务或者大量小事务导未提交致回滚空间被撑满的风险?
新事务复用旧的空间。可以通过配置文件限制回滚空间大小

数据结构

DM支持B树、堆、列存、位图等方式存储数据

B 树数据

行存储数据,也是应用最广泛的存储形式,其数据是按 B+ 树索引组织的。普通表、分区表、B+ 树索引的物理存储格式都是 B 树。
一个 B 树包含两个段,一个内节点段,存放内节点数据;一个叶子段,存放叶子节点数据。其 B+ 树的逻辑关系由段内页面上的记录,通过文件指针来完成。
当表上没有指定聚集索引时,系统会自动产生一个唯一标识 rowid 作为 B+ 树的 key 来唯一标识一行。

堆表数据

堆表的数据是以挂链形式存储的,一般情况下,支持最多 128 个链表,一个链表在物理上就是一个段,堆表采用的是物理 rowid,在插入过程中,rowid 在事先已确定,并保证其唯一性,所以可以并发插入,插入效率很高,且由于 rowid 是即时生成,无需保存在物理磁盘上,也节省了空间。

列存储数据

数据按列方式组织存储,包含每个列对应的存放列数据的一系列数据文件,以及存放列数据控制信息的辅助表。读取列数据时,只需要顺序扫描列数据文件和辅助表数据。在某些特殊应用场景下,其效率要远远高于行存储。

位图索引

位图索引与 B 树索引不同,每个索引条目不是指向一行数据,而是指向多行数据。每个索引项保存的是一定范围内所有行与当前索引键值映射关系的位图。
数据文件中还有两类特殊的数据文件:ROLL 和 TEMP 文件。
1)ROLL 文件
ROLL 表空间的 dbf 文件,称为 ROLL 文件。ROLL 文件用于保存系统的回滚记录,提供事务回滚时的信息。回滚文件可被分为若干回滚段,每个事务的回滚页在回滚段中各自挂链,页内则顺序存放回滚记录。
2)TEMP 文件
TEMP.DBF 临时数据文件,临时文件可以在 dm.ini 中通过 TEMP_SIZE 配置大小。
当数据库查询的临时结果集过大,缓存已经不够用时,临时结果集就可以保存在 TEMP.DBF 文件中,供后续运算使用。系统中用户创建的临时表也存储在临时文件中。

内存结构

在内存管理这一块,DM实现了自己的内存管理机制,DM向操作系统申请一块大内存,然后把申请到的内存划分为内存池、缓冲池、排序区和哈希区等

内存池

共享内存池

达梦数据库大部分功能模块的内存是从共享内存池申请
注意几个要点:
1.通过dm.ini 的 MEMORY_POOL 修改内存池大小,默认为500M。
2.如果在运行时所需内存大于配置值共享内存池也可进行自动扩展,INI 参数 MEMORY_EXTENT_SIZE 指定了共享内存池每次扩展的大小
3.参数 MEMORY_TARGET 则指定了共享内存池扩展到超过该值后,空闲时会收缩到的大小。

独立内存池

少部分功能模块在运行时使用独立的内存池,如会话内存池、虚拟机内存池等。

缓冲池

数据缓冲区

数据缓冲区可以看作是数据库自身的mmap。
数据缓冲区存在三条链来管理被缓冲的数据页,
一条是“自由”链,用于存放目前尚未使用的内存数据页
一条是“LRU”链,用于存放已被使用的内存数据页(包括未修改和已修改)。即内存置换算法采用的是最近最少使用算法
还有一条即为“脏”链,用于存放已被修改过的内存数据页。

缓冲区类别

达梦数据库有四类缓冲区:分别是 NORMAL、KEEP、FAST 和 RECYCLE。其中用户创建表空间时可执行 NORMAL 或 KEEP 缓冲区。另外的KEEP、FAST缓冲区是系统表空间专用的。
默认缓冲区为 NORMAL;KEEP 缓冲区特性是对缓冲区中的数据页很少或几乎不怎么淘汰出去,用于保存最热的数据。

读多页机制

读多页机制跟磁盘预读机制是一样的。
MULTI_PAGE_GET_NUM 指定一次读会读多少个数据块。

日志缓冲区

日志缓冲区是用于存放重做日志的内存缓冲区。日志缓冲区所占用的内存是从共享内存池中申请的,单位为页数量。
RLOG_BUF_SIZE  控制大小

字典缓冲区

主要存储一些数据字典信息,如模式信息、表信息、列信息、触发器信息等

SQL 缓冲区

SQL 缓冲区提供在执行 SQL 语句过程中所需要的内存,包括执行计划、SQL 语句和结果集缓存。
修改 dm.ini 可开启缓存:
USE_PLN_POOL :是否开启执行计划缓存。当指定为非 0 时,则启动计划重用;为 0 时禁止计划重用。
CACHE_POOL_SIZE:指定缓冲区大小。默认值为 20M。
RS_CAN_CACHE :是否开启结果集缓存。(如开启,需要保证USE_PLN_POOL非0)
CLT_CACHE_TABLES:参数设置哪些表的结果集需要缓存

客户端结果集也可以缓存,但需要在配置文件 dm_svc.conf 中设置参数:
ENABLE_RS_CACHE = (1) //表示启用缓存;
RS_CACHE_SIZE = (100) //表示缓存区的大小为100M, 可配置为1-65535
RS_REFRESH_FREQ = (30) //表示每30秒检查缓存的有效性,如果失效,自动重查; 0表示不检查。
需要注意的是结果集不超过FIRST_ROWS 才可能被客户端缓存。

排序区

排序用到的内存。orderby ,distinct,group by 等。
SORT_BUF_SIZE修改大小,建议使用默认值2M。

哈希区

DM8 提供了为哈希连接而设定的缓冲区。
在进行哈希连接时,对排序的数据量进行了计算。如果计算出的数据量大小超过了哈希缓冲区的大小,则使用 DM8 创新的外存哈希方式;如果没有超过哈希缓冲区的大小,实际上还是使用内存池来进行哈希操作。
HJ_BUF_SIZE:单个 HASH 连接操作符的数据总缓存大小,单位 MB,必须小于 HJ_BUF_GLOBAL_SIZE。

问题思考

1.操作系统本身自带了数据缓冲区(mmap),为啥还要实现一遍?

  • OS的置换阈值不受我们控制,不灵活,比如无法控制大小,无法控制在什么实际回收。
  • 数据库的缓冲池可以看作是mmap的重新实现,自己实现一套可以随着版本更新去迭代优化。
  • 为了满足不同操作系统兼容性。

2.读多页参数 MULTI_PAGE_GET_NUM 跟 磁盘预读参数(at /sys/block/$dm/queue/read_ahead_kb)是否会相互影响?

  • 不会相互影响,以DM的为准
评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服