导读:数据库管理系统(DBMS)是内存申请与释放最频繁的软件之一。如果每次内存操作都直接调用操作系统函数,效率会非常低。因此,达梦 DM8 实现了自有的内存管理体系。本文带你完整梳理 DM8 的内存结构——内存池、缓冲区、排序区、哈希区,并附上关键 INI 参数与动态性能视图,帮助你理解、监控和调优数据库内存。
DBMS 加入自己的内存管理,通常能带来三大好处:
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 的内存使用情况。
共享内存池是 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
除了共享内存池,DM Server 的一些功能模块在运行时还会使用自己的运行时内存池——从操作系统申请一片内存作为本功能模块的内存池,如会话内存池、虚拟机内存池等。
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(已分配大小)——这几个字段可以帮你判断内存池是否频繁扩展、是否接近上限。
数据缓冲区是 DM Server 在将数据页写入磁盘之前、以及从磁盘上读取数据页之后,数据页所存储的地方。这是 DM Server 至关重要的内存区域:
三条链管理数据页:系统启动时,首先根据配置的数据缓冲区大小向操作系统申请一片连续内存,并按数据页大小格式化,置入自由链:
| 链 | 用途 |
|---|---|
| 自由链(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),各缓冲区的空闲页数反映了当前的内存压力。
日志缓冲区用于存放重做日志(Redo Log)。系统运行过程中产生的日志并不会立即写入磁盘,而是先放到日志缓冲区——避免直接的磁盘 IO 影响系统性能。
为什么不让重做日志直接用数据缓冲区? 主要基于以下三个原因:
相关参数:
| 参数 | 说明 | 取值范围 |
|---|---|---|
RLOG_BUF_SIZE |
单个日志缓冲区大小(以日志页个数为单位) | 1 ~ 20480 |
RLOG_POOL_SIZE |
最大日志缓冲区大小 | 1 ~ 4096(MB) |
建库、初始化时可以手动指定这些参数,具体可参考《DM8 dminit 使用手册》。
字典缓冲区主要存储数据字典信息:模式信息、表信息、列信息、触发器信息等。
每次对数据库的操作都会涉及数据字典信息,其访问效率直接影响到操作效率。例如执行查询语句,就需要相应的表信息、列信息——这些字典信息如果在缓冲区里,直接获取即可;否则需要 IO 才能读取。
DM8 将部分数据字典信息加载到缓冲区中,并采用 LRU 算法进行控制:
相关参数:
| 参数 | 说明 | 默认值 |
|---|---|---|
DICT_BUF_SIZE |
字典缓冲区大小 | 50MB |
调优提示:如果实际应用中涉及分区数较多的水平分区表(例如上千个分区),需要适当调大
DICT_BUF_SIZE。
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)**而设定的缓冲区。在进行哈希连接时,系统会对参与连接的数据量进行计算:
相关参数:
| 参数 | 说明 |
|---|---|
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 参数当前配置值 |
MEMORY_POOL,缺省 500MB)集中管理小片内存的申请/释放,避免频繁系统调用;各功能模块还有自己的运行时内存池(会话、虚拟机等)。HJ_BUF_SIZE)服务于具体执行计划,数据量大时 DM8 会以外存哈希等方式降级处理,保证可用性。理解这些内存区域和参数,是进行 DM8 性能调优的基础——先看 V$MEM_POOL 和 V$BUFFERPOOL,再对症下药调整 INI 参数,是内存调优的标准姿势。
参考资料:达梦数据库官方文档、DM8 动态性能视图手册、DM8 dminit 使用手册
文章
阅读量
获赞
