注册
达梦DM8内存结构详解:内存池、缓冲区、排序区与哈希区
专栏/技术分享/ 文章详情 /

达梦DM8内存结构详解:内存池、缓冲区、排序区与哈希区

DM_WJH 2026/08/21 227 1 0
摘要

导读:数据库管理系统(DBMS)是内存申请与释放最频繁的软件之一。如果每次内存操作都直接调用操作系统函数,效率会非常低。因此,达梦 DM8 实现了自有的内存管理体系。本文带你完整梳理 DM8 的内存结构——内存池、缓冲区、排序区、哈希区,并附上关键 INI 参数与动态性能视图,帮助你理解、监控和调优数据库内存。


一、为什么数据库要自己管理内存?

DBMS 加入自己的内存管理,通常能带来三大好处:

  1. 申请、释放内存效率更高——在自管内存池中分配小片内存,避免频繁系统调用;
  2. 能够有效地了解内存的使用情况——通过动态视图实时掌握各区域内存状态;
  3. 易于发现内存泄露和内存写越界的问题——自管内存可加入校验机制(如 CHK_MAGIC / CHK_LEAK)。

DM 数据库管理系统的内存结构主要包括:内存池、缓冲区、排序区、哈希区等。系统按子模块的不同功能对内存进行划分,并采用了不同的管理模式。


二、内存结构总览

┌──────────────────────────────────────────────────────────┐
│                    DM Server 内存结构                       │
├──────────────────────────────────────────────────────────┤
│  ① 内存池(Memory Pool)                                   │
│     ├── 共享内存池(MEMORY_POOL / MEMORY_TARGET)          │
│     └── 运行时内存池(会话内存池、虚拟机内存池等)           │
├──────────────────────────────────────────────────────────┤
│  ② 缓冲区(Buffer)                                        │
│     ├── 数据缓冲区(NORMAL / KEEP / FAST / RECYCLE)       │
│     ├── 日志缓冲区(RLOG_BUF_SIZE / RLOG_POOL_SIZE)       │
│     ├── 字典缓冲区(DICT_BUF_SIZE)                        │
│     └── SQL 缓冲区(USE_PLN_POOL / CACHE_POOL_SIZE)       │
├──────────────────────────────────────────────────────────┤
│  ③ 排序区(SORT_BUF_SIZE)                                 │
├──────────────────────────────────────────────────────────┤
│  ④ 哈希区(HJ_BUF_SIZE / HJ_BUF_GLOBAL_SIZE)              │
└──────────────────────────────────────────────────────────┘

其中,内存池与缓冲区是基础,排序区与哈希区服务于具体执行计划(ORDER BY、HASH JOIN 等)。


三、内存池

DM Server 的内存池包括共享内存池其他一些运行时内存池

动态视图 V$MEM_POOL 详细记录了当前系统中所有内存池的状态,可通过查询该视图掌握 DM Server 的内存使用情况。

3.1 共享内存池

共享内存池是 DM Server 启动时从操作系统申请的一大片内存

为什么需要它? 在运行期间,系统经常需要申请与释放小片内存。如果直接向操作系统申请和释放,需要发出系统调用,可能引起线程切换,降低系统运行效率。因此 DM 采用共享内存池的方式:

  • 一次向操作系统申请一片较大内存,作为共享内存池;
  • 运行过程中需要小片内存时,直接在池内申请;
  • 用完后再释放,即归还给共享内存池。

相关参数(在 dm.ini 配置文件中设置):

参数 说明 缺省值
MEMORY_POOL 共享内存池大小 500MB
MEMORY_EXTENT_SIZE 运行时内存不足时,共享内存池每次扩展的大小 32(单位:页)
MEMORY_TARGET 共享内存池扩展到超过该值后,空闲时会收缩到的大小 15000(单位:MB)

共享内存池并不是"固定不变"的:运行时所需内存大于配置值,共享内存池可自动扩展;扩展到超过 MEMORY_TARGET 后,空闲时会自动收缩。

查看实际配置:

SQL> select para_name, para_value, para_type from v$dm_ini 2 where para_name in ('MEMORY_POOL','MEMORY_TARGET','MEMORY_EXTENT_SIZE'); 行号 PARA_NAME PARA_VALUE PARA_TYPE ---- ----------------- ---------- --------- 1 MEMORY_POOL 500 IN FILE 2 MEMORY_TARGET 15000 SYS 3 MEMORY_EXTENT_SIZE 32 IN FILE

3.2 运行时内存池

除了共享内存池,DM Server 的一些功能模块在运行时还会使用自己的运行时内存池——从操作系统申请一片内存作为本功能模块的内存池,如会话内存池、虚拟机内存池等。

3.3 V$MEM_POOL 动态视图

SQL> desc V$MEM_POOL; 行号 NAME TYPE$ NULLABLE 说明 ---- ------------------ ------------ --------- ------------------------------- 1 ADDR BIGINT Y 2 NAME VARCHAR(128) Y 内存池名称 3 IS_SHARED CHAR(1) Y 是否共享 4 CHK_MAGIC CHAR(1) Y 5 CHK_LEAK CHAR(1) Y 6 IS_OVERFLOW CHAR(1) Y 7 IS_DSA_ITEM CHAR(1) Y 8 ORG_SIZE BIGINT Y 初始大小 9 TOTAL_SIZE BIGINT Y 当前总大小(字节) 10 RESERVED_SIZE BIGINT Y 分配出去的大小 11 DATA_SIZE BIGINT Y 12 EXTEND_SIZE BIGINT Y 13 TARGET_SIZE BIGINT Y 14 EXTEND_LEN INTEGER Y 15 N_ALLOC INTEGER Y 16 N_EXTEND_NORMAL INTEGER Y 17 N_EXTEND_EXCLUSIVE INTEGER Y 18 N_FREE INTEGER Y 19 MAX_EXTEND_SIZE BIGINT Y 20 MIN_EXTEND_SIZE BIGINT Y 21 FILE_NAME VARCHAR(256) Y 22 FILE_LINE INTEGER Y 23 CREATOR INTEGER Y 24 EXTEND_MODE CHAR(1) Y 25 PEAK_SIZE BIGINT Y 26 PARENT BIGINT Y

重点关注ORG_SIZE(初始大小)、TOTAL_SIZE(当前总大小)、PEAK_SIZE(峰值)、RESERVED_SIZE(已分配大小)——这几个字段可以帮你判断内存池是否频繁扩展、是否接近上限。


四、缓冲区

4.1 数据缓冲区(Buffer Pool)

数据缓冲区是 DM Server 在将数据页写入磁盘之前、以及从磁盘上读取数据页之后,数据页所存储的地方。这是 DM Server 至关重要的内存区域

  • 设得太小 → 缓冲页命中率低,磁盘 IO 频繁;
  • 设得太大 → 操作系统内存本身不够用。

三条链管理数据页:系统启动时,首先根据配置的数据缓冲区大小向操作系统申请一片连续内存,并按数据页大小格式化,置入自由链

用途
自由链(FREE) 存放目前尚未使用的内存数据页
LRU 链 存放已被使用的内存数据页(包括未修改和已修改)
脏链(DIRTY) 存放已被修改过的内存数据页

淘汰机制:LRU 链按"最近是否被使用"对数据页排序。当自由链被用完时,从 LRU 链中淘汰最近未使用的数据页——能够较大程度地保证被淘汰的页近期不会被用到,减少 IO。

热点页保护:系统运行过程中通常存在一部分"非常热"(反复被访问)的数据页,将它们一直留在缓冲区中对性能有好处。数据缓冲区为此开辟了特定区域存放热点页,保证这些页不参与一般的淘汰机制。

① 四种缓冲区类型

类型 说明
NORMAL 系统处理数据页的默认缓冲区(BUFFER 即 NORMAL);用户可在建/改表空间时指定表空间属于 NORMAL 或 KEEP
KEEP 数据页很少或几乎不淘汰,适合需要经常驻留内存的应用数据
FAST 根据用户指定的 FAST_POOL_PAGES 大小由系统自动管理
RECYCLE 临时表空间使用

② 读多页优化

一次性读取多页可以减少 I/O 次数,从而提高数据的查询、修改效率。主要由参数 MULTI_PAGE_GET_NUM 控制每次读取的页数。

③ 实际监控查询

SQL> select name, 2 N_PAGES as 页数, 3 FREE as 空闲页数, 4 N_DISCARD64 as 淘汰页数, 5 N_PAGES * (select sf_get_page_size())/1024/1024 as 缓冲区大小_MB 6 from v$bufferpool 7 where name in ('NORMAL','KEEP','RECYCLE','FAST'); 行号 NAME 页数 空闲页数 淘汰页数 缓冲区大小_MB ---- ------- ----------- ---------- ---------- ------------- 1 KEEP 512 512 0 8 2 RECYCLE 3200 3018 0 50 3 FAST 3000 1154 0 46 4 NORMAL 26789 26784 0 418 5 NORMAL 26789 26784 0 418 ...

从结果可以直观看出:NORMAL 缓冲区最大(约 418MB),KEEP 较小(8MB),各缓冲区的空闲页数反映了当前的内存压力。

4.2 日志缓冲区

日志缓冲区用于存放重做日志(Redo Log)。系统运行过程中产生的日志并不会立即写入磁盘,而是先放到日志缓冲区——避免直接的磁盘 IO 影响系统性能。

为什么不让重做日志直接用数据缓冲区? 主要基于以下三个原因:

  1. 重做日志的格式同数据页完全不一样,无法进行统一管理;
  2. 重做日志具备连续写的特点
  3. 在逻辑上,写重做日志比数据页 IO 优先级更高

相关参数

参数 说明 取值范围
RLOG_BUF_SIZE 单个日志缓冲区大小(以日志页个数为单位) 1 ~ 20480
RLOG_POOL_SIZE 最大日志缓冲区大小 1 ~ 4096(MB)

建库、初始化时可以手动指定这些参数,具体可参考《DM8 dminit 使用手册》。

4.3 字典缓冲区

字典缓冲区主要存储数据字典信息:模式信息、表信息、列信息、触发器信息等。

每次对数据库的操作都会涉及数据字典信息,其访问效率直接影响到操作效率。例如执行查询语句,就需要相应的表信息、列信息——这些字典信息如果在缓冲区里,直接获取即可;否则需要 IO 才能读取

DM8 将部分数据字典信息加载到缓冲区中,并采用 LRU 算法进行控制:

  • 缓冲区太大 → 浪费宝贵的内存空间;
  • 缓冲区太小 → 频繁淘汰,影响访问效率。

相关参数

参数 说明 默认值
DICT_BUF_SIZE 字典缓冲区大小 50MB

调优提示:如果实际应用中涉及分区数较多的水平分区表(例如上千个分区),需要适当调大 DICT_BUF_SIZE

4.4 SQL 缓冲区

SQL 缓冲区提供执行 SQL 语句过程中所需的内存,包括计划、SQL 语句和结果集缓存

很多应用都存在反复执行相同 SQL 的情况,此时可以用缓冲区保存这些语句和它们的执行计划,实现计划重用——加快 SQL 执行效率,但同时也会增加内存压力。

相关参数

参数 说明
USE_PLN_POOL 指定为非 0 时启动计划重用;为 0 时禁止计划重用
CACHE_POOL_SIZE 改变 SQL 缓冲区大小,默认值为 0MB
RS_CAN_CACHE 是否开启结果集缓存(若开启,需保证 USE_PLN_POOL 非 0)
CLT_CACHE_TABLES 设置哪些表的结果集需要缓存

客户端结果集缓存:客户端结果集也可以缓存,需要在配置文件 dm_svc.conf 中设置:

ENABLE_RS_CACHE = (1) -- 表示启用缓存 RS_CACHE_SIZE = (100) -- 缓存区的大小为100MB,可配置为1-65535 RS_REFRESH_FREQ = (30) -- 每30秒检查缓存的有效性,如果失效,自动重查;0表示不检查

五、排序区

当用户执行 SQL 语句时,常常需要进行排序(ORDER BY、DISTINCT、GROUP BY、索引构建等),所使用的内存就是排序缓冲区提供的。

  • 在每次排序过程中,都首先申请内存,排序结束后再释放内存

相关参数

参数 说明 建议值
SORT_BUF_SIZE 排序缓冲区大小 建议使用默认值 20MB

六、哈希区

DM8 提供了为**哈希连接(HASH JOIN)**而设定的缓冲区。在进行哈希连接时,系统会对参与连接的数据量进行计算:

  • 如果计算出的数据量大小超过哈希缓冲区大小 → 使用 DM8 创新的外存哈希方式
  • 如果没有超过哈希缓冲区大小 → 实际上还是使用内存池来进行哈希操作。

相关参数

参数 说明
HJ_BUF_SIZE 单个 HASH 连接操作符的数据总缓存大小(MB),必须小于 HJ_BUF_GLOBAL_SIZE
HJ_BUF_GLOBAL_SIZE 所有哈希连接操作符可用的总缓存大小(MB)

七、关键参数速查表

内存区域 参数 默认值/建议 说明
共享内存池 MEMORY_POOL 500MB 共享内存池初始大小
共享内存池 MEMORY_EXTENT_SIZE 32 内存池每次扩展大小
共享内存池 MEMORY_TARGET 15000MB 超过后空闲时收缩到的目标值
数据缓冲区 BUFFER / FAST_POOL_PAGES NORMAL / FAST 缓冲区大小
数据缓冲区 MULTI_PAGE_GET_NUM 每次读多页的页数,减少 IO
日志缓冲区 RLOG_BUF_SIZE 1~20480 单个日志缓冲区大小(页)
日志缓冲区 RLOG_POOL_SIZE 1~4096MB 最大日志缓冲区大小
字典缓冲区 DICT_BUF_SIZE 50MB 数据字典缓存,分区多时需调大
SQL 缓冲区 USE_PLN_POOL 非0启用 计划重用开关
SQL 缓冲区 CACHE_POOL_SIZE 0MB SQL 缓冲区大小
SQL 缓冲区 RS_CAN_CACHE 结果集缓存开关(需 USE_PLN_POOL 非0)
排序区 SORT_BUF_SIZE 20MB 排序缓冲区大小(建议默认)
哈希区 HJ_BUF_SIZE < HJ_BUF_GLOBAL_SIZE 单个 HASH 连接缓存大小

配套监控视图

视图 用途
V$MEM_POOL 查看所有内存池状态(初始/当前/峰值大小)
V$BUFFERPOOL 查看各数据缓冲区页数、空闲页数、淘汰页数
V$DM_INI 查看 INI 参数当前配置值

八、总结

  1. 内存池:共享内存池(MEMORY_POOL,缺省 500MB)集中管理小片内存的申请/释放,避免频繁系统调用;各功能模块还有自己的运行时内存池(会话、虚拟机等)。
  2. 缓冲区是性能的核心:
    • 数据缓冲区用自由链 / LRU 链 / 脏链三条链管理数据页,按 NORMAL / KEEP / FAST / RECYCLE 四种类型差异化缓存;
    • 日志缓冲区单独设立,承载连续写、高优先级的重做日志;
    • 字典缓冲区(默认 50MB)缓存元数据,分区多的表需调大;
    • SQL 缓冲区实现计划重用与结果集缓存。
  3. 排序区(默认 20MB)与哈希区HJ_BUF_SIZE)服务于具体执行计划,数据量大时 DM8 会以外存哈希等方式降级处理,保证可用性。

理解这些内存区域和参数,是进行 DM8 性能调优的基础——先看 V$MEM_POOLV$BUFFERPOOL,再对症下药调整 INI 参数,是内存调优的标准姿势。


参考资料:达梦数据库官方文档、DM8 动态性能视图手册、DM8 dminit 使用手册

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服