目录
[2.1.1 共享内存池](#2.1.1 共享内存池)
[2.1.2 运行时内存池](#2.1.2 运行时内存池)
[2.3.排序区(sort area)](#2.3.排序区(sort area))
[2.4.哈希区("虚拟哈希缓冲区" + "外存哈希"机制)](#2.4.哈希区(“虚拟哈希缓冲区” + “外存哈希”机制))
一、达梦数据库的内存结构概述
数据库管理系统是一种对内存申请和释放操作频率很高的软件,达梦官方对内存管理专门加入了自己的通用内存管理系统(DBMS-DataBase Memory System),这就带来了如下好处:
1.申请、释放内存效率更高
2.能够有效地了解内存的使用情况
3.易于发现内存泄露和内存写越界的问题
达梦数据库 管理系统的内存结构主要包括:内存池、缓冲区、排序区、哈希区等。根据系统中子模块的不同功能,对内存进行了上述划分,并采用了不同的管理模式。

如上图所示,达梦数据库属于单进程(主进程dmserver)+ 多线程(checkpoint线程、I/O线程、监听线程、日志写线程、mal线程、purge线程、audit flush线程、调度线程、task线程、worker线程、DB/UTHR线程等)的架构模式。
达梦数据库中的核心进程和线程(理论+实验)学习-CSDN博客
二、DM内存结构的组成
2.1.内存池
DMServer的内存池包括共享内存池和其他一些运行时内存池。
动态视图V$MEM_POOL详细记录了当前系统中所有的内存池的状态,可通过查询这个动态视图掌握DMServer的内存使用情况。
sql命令:select name,sum(total_size) from v$mem_pool group by name;

内存池又分为共享内存池和运行时内存池。
2.1.1 共享内存池
共享内存池是DMServer在启动时从操作系统申请的一大片内存。
在DMServer的运行期间,经常会申请与释放小片内存,而向操作系统申请和释放内存时需要发出系统调用,此时可能会引起线程切换,降低系统运行效率。采用共享内存池则可一次向操作系统申请一片较大内存,即为内存池,当系统在运行过程中需要申请内存时,可在共享内存池内进行申请,当用完该内存时,再释放掉,即归还给共享内存池。
达梦数据库系统管理员可以通过DMServer的配置文件(dm.ini)来对共享内存池的大小进行设置,共享池的参数为MEMORY_POOL,该配置默认为500M。如果在运行时所需内存大于配置值,共享内存池也可进行自动扩展,INI参数MEMORY_EXTENT_SIZE指定了共享内存池每次扩展的大小,参数MEMORY_TARGET则指定了共享内存池扩展到超过该值后,空闲时会收缩到的大小。
命令查看:

2.1.2 运行时内存池
关键:理解为"干活时"临时申请的内存。
除了共享内存池,达梦数据库的一些功能模块在运行时还会使用自己的运行时内存池。这些运行时内存池是从操作系统申请一片内存作为本功能模块的内存池来使用, 如会话内存池、虚拟机内存池等。
2.2.缓冲区
2.2.1.数据缓冲区
**数据缓冲区是DMServer在将数据页写入磁盘之前以及从磁盘上读取数据页之后, 数据页所存储的地方。**这是DMServer至关重要的内存区域之一,将其设定得太小,会导致缓冲页命中率低,磁盘IO频繁;将其设定得太大,又会导致操作系统内存本身不够用。
**系统启动时:**根据配置的数据缓冲区大小向操作系统申请一片连续内存并将其按数据页大小进行格式化,并置入自由链中。
数据缓冲区存在三条链来管理被缓冲的数据页:
1)一条是自由链:用于存放目前尚未使用的内存数据页;
2)一条是LRU链:用于存放已被使用的内存数据页(包括未修改和已修改)
3) 一条是脏链:用于存放已被修改过的内存数据页。
LRU链对系统当前使用的页按其最近是否被使用的顺序进行了排序。这样当数据缓冲区中的自由链被用完时,从LRU链中淘汰部分最近未使用的数据页,能够较大程度地保证被淘汰的数据页在最近不会被用到,减少IO。
LRU 是 Least Recently Used 的缩写,中文意思是最近最少使用。
它是一种非常经典的缓存淘汰算法 ,其核心思想是:如果数据最近被访问过,那么将来被访问的概率也更高;如果一个数据长时间没有被访问,那么它未来被访问的概率相对较低。
在系统运行过程中,通常存在一部分非常热(反复被访问)的数据页,将它们一直留在缓冲区中,对系统性能会有好处。对于这部分数据页,数据缓冲区开辟了一个特定的区域用于存放它们,以保证这些页不参与一般的淘汰机制,可以一直留在数据缓冲区中。
1)类别
DMServer中有四种类型的数据缓冲区,分别是NORMAL、KEEP、FAST和RECYCLE。其中,用户可以在创建表空间或修改表空间时,指定表空间属于NORMAL或KEEP缓冲区。RECYCLE缓冲区供临时表空间使用,FAST缓冲区根据用户指定的FAST_POOL_PAGES大小由系统自动进行管理,用户不能指定使用RECYCLE和FAST缓冲区的表或表空间。
总结:
|-----------|-------------------------------------------------|
| 缓冲区类型 | 说明 |
| NORMAL | 主要是提供给系统处理的一些数据页,没有特定指定缓存区的情况下,默认缓存区为NORMAL。 |
| KEEP | 对缓存区中的数据页很少或几乎不怎么淘汰出去,主要用于数据页需要经常处在内存中的应用(热点数据) |
| FAST | 根据用户指定的FAST_POOL_PAGES大小由系统自动进行管理 |
| RECYCLE | 供临时表空间进行使用 |
DMServer提供了可以更改这些缓冲区大小的参数,用户可以根据自己应用需求情况,指定dm.ini文件中(括号中为默认值):
BUFFER(100MB);
KEEP(8MB);
RECYCLE(64MB);
FAST_POOL_PAGES(3000),这些值分别对应是 NORMAL缓冲区大小、KEEP缓冲区大小、RECYCLE缓冲区大小、FAST缓冲区数据页总数。
2)读多页
在需要进行大量 I/O 的应用当中,达梦数据库之前版本的策略是每次只读取一页。如果知道用户需要读取表的大量数据,当读取到第一页时,可以猜测用户可能需要读取这页的下一页,在这种情况下,一次性读取多页就可以减少I/O 次数,从而提高了数据的查询、修改效率。
DMServer提供了可以读取多页的参数,用户可以指定这些参数来调整数据库运行效率的最佳状态。在达梦数据库配置文件dm.ini 中,可以指定参数MULTI_PAGE_GET_NUM 大小(默认值为1页),来控制每次读取的页数。
如果用户没有设置较适合的参数MULTI_PAGE_GET_NUM值大小,有时可能会给用户带来更差的效果。 如果MULTI_PAGE_GET_NUM太大,每次读取的页可能大多都不是以后所用到的数据页,这样不仅会增加I/O的读取,而且每次都会做一些无用的I/O,所以系统管理员需要衡量好自己应用需求,给出最佳方案。
2.2.2.日志缓冲区
日志缓冲区是用于存放重做日志的内存缓冲区。为了避免由于直接的磁盘IO而使系统性能受到影响 ,系统在运行过程中产生的**日志并不会立即被写入磁盘,而是和数据页一样,先将其放置到日志缓冲区中。**那么为何不在数据缓冲区中缓存重做日志而要单独设立日志缓冲区呢?主要是基于以下原因:
-
重做日志的格式同数据页完全不一样,无法进行统一管理;
-
重做日志具备连续写的特点;
-
在逻辑上,写重做日志比数据页IO优先级更高(日志优先原则)。
DMServer提供了参数RLOG_BUF_SIZE对日志缓冲区大小进行控制,日志缓冲区所占用的内存是从共享内存池中申请的 ,单位为页数量,且大小必须为2的N次方,否则采用系统默认大小1024页,默认的页是8KB。
sql命令:select para_name,para_value from v$dm_ini where para_name='RLOG_BUF_SIZE';

2.2.3.字典缓冲区
字典缓冲区主要存储一些数据字典信息,如模式(Schema)信息、表信息、列信息、触发器信息等。每次对数据库的操作都会涉及到数据字典信息,访问数据字典信息的效率直接影响到相应的操作效率,如进行查询语句,就需要相应的表信息、列信息等,这些字典信息如果都在缓冲区里,则直接从缓冲区中获取即可,否则需要I/O才能读取到这些信息。
达梦8采用的是将部分数据字典信息加载到缓冲区中,并采用LRU算法进行字典信息的控制。缓冲区大小设置问题, 如果太大,会浪费宝贵的内存空间,如果太小,可能会频繁的进行淘汰,该缓冲区配置参数为DICT_BUF_SIZE,默认的配置大小为5M。
达梦8采用缓冲部分字典对象,会影响效率吗?
数据字典信息访问存在热点现像,并不是所有的字典信息都会被频繁的访问,所以按需加载字典信息并不会影响到实际的运行效率。但是如果在实际应用中涉及对分区数较多的水平分区表访问,例如上千个分区,那么就需要适当调大DICT_BUF_SIZE参数值。
sql命令:select para_name,para_value from v$dm_ini where para_name='DICT_BUF_SIZE';

2.2.4.SQL缓冲区
SQL缓冲区提供在执行SQL语句过程中所需要的内存,包括计划、SQL 语句和结果集缓存。
很多应用当中都存在反复执行相同SQL语句的情况,此时可以使用缓冲区保存这些语句和它们的执行计划,这就是计划重用。这样带来的好处是加快了SQL语句执行效率,但同时给内存也增加了压力。
DMServer在配置文件 dm.ini 提供了参数来支持是否需要计划重用,参数为USE_PLN_POOL;
为非0时,则启动计划重用;
为0时禁止计划重用。
达梦同时还提供了参数CACHE_POOL_SIZE(单位为MB),来改变SQL缓冲区大小,系统管理员可以设置该值以满足应用需求,默认值为20M。
结果集缓存包括SQL查询结果集缓存和 DMSQL程序函数结果集缓存,在 INI 参数文件中同时设置参数RS_CAN_CACHE=1 且 USE_PLN_POOL 非 0 时 达梦数据库服务器才会缓存结果集。
sql命令:select para_name,para_value from v$dm_ini where para_name in ('USE_PLN_POOL','CACHE_POOL_SIZE');

DM还提供了一些手动设置结果集缓存的方法。客户端结果集也可以缓存,但需要在配置文件dm_svc.conf 中设置参数:
ENABLE_RS_CACHE = (1) //表示启用缓存;
RS_CACHE_SIZE = (100) //表示缓存区的大小为 100M, 可配置为 1-65535
RS_REFRESH_FREQ = (30) //表示每 30 秒检查缓存的有效性,如果失效,自动重查; 0表示不检查。
同时在服务器端使用INI参数文件中的CLT_CACHE_TABLES参数设置哪些表的结果集需要缓存。 另外,FIRST_ROWS参数表示当查询的结果达到该行数时,就返回结果,不再继续查询,除非用户向服务器发一个FETCH命令。这个参数也用于客户端缓存的配置,仅当结果集的行数不超过FIRST_ROWS时,该结果集才可能被客户端缓存。
2.3.排序区(sort area)
排序缓冲区提供数据排序所需要的内存空间。当用户执行SQL语句时,常常需要进行排序,所使用的内存就是排序缓冲区提供的。 在每次排序过程中,都首先申请内存,排序结束后再释放内存(排序前申请 -> 排序后释放)。
DMServer提供了参数来指定排序缓冲区的大小,参数SORT_BUF_SIZE在达梦配置文件 dm.ini中,系统管理员可以设置其大小以满足需求,由于该值是由系统内部排序算法和排序数据结构决定,建议使用默认值20M(官网说明)。
例如:实际参数配置中的截图

命令查询:

2.4.哈希区("虚拟哈希缓冲区 " + "外存哈希"机制)
达梦8版本提供了为哈希连接而设定的缓冲区,不过该缓冲区是个虚拟缓冲区。 之所以说是虚拟缓冲,是因为系统没有真正创建特定属于哈希缓冲区的内存,而是在进行哈希连接时,对排序的数据量进行了计算。如果计算出的数据量大小超过了哈希缓冲区的大小,则使用达梦8创新的外存哈希(即使用磁盘计算)方式 ;如果没有超过 哈希缓冲区的大小,实际 上还是使用内存池来进行哈希操作。
这算是DMServer的一个精妙设计------不提前划分固定内存,而是按需使用、智能降级。
我们可以把哈希连接看作仓库整理货物:
-
内存池(Memory Pool) :仓库里的大通铺,所有工作(排序、哈希、缓存)都共享这块区域。
-
HJ_BUF_SIZE(哈希缓冲区设置) :是一个管理界限,而不是一堵实体的墙。它决定了一次哈希操作"最多能占大通铺的几成位置"。
-
真正干活时 :如果哈希操作发现需要占的位置没超过 HJ_BUF_SIZE,就去大通铺正常干活(内存哈希)。
-
如果超过了 :达梦不会强行挤占空间导致崩溃,而是自动切换到一种更慢但能完成任务的模式------外存哈希。
DMServer在 dm.ini中提供了参数HJ_BUF_SIZE来进行控制,由于该值的大小可能会限制哈希连接的效率,所以建议保持默认值,或设置为更大的值。
sql命令:select para_name,para_value from v$dm_ini where para_name = 'HJ_BUF_SIZE';

除了提供HJ_BUF_SIZE参数外,DMServer还提供了创建哈希表个数的初始化参数,其中,HAGR_HASH_SIZE表示处理聚集函数时创建哈希表的个数,建议保持默认值100000。
