在日常数据库运维中,我们常遇到数据库实例占用较大内存的情况,此类情况多为有会话SQL使用了较大内存导致,本文将介绍如何监控和查找此类SQL语句。
达梦数据库内存占用可以简单的分为缓冲区和内存池,分别提供系统视图V$BUFFERPOOL和V$MEM_POOL进行监控。
缓冲缓冲区包括数据缓冲区、日志缓冲区、字典缓冲区和SQL缓冲区。数据缓冲区是数据页写入磁盘之前以及从磁盘上读取数据页之后,数据页所存储的地方,分为四种类别,分别为:BUFFER、RECYCLE、FAST 、KEEP;
类别 | 用途 | 淘汰机制 | 对应INI参数 |
BUFFER | 默认缓冲区,普通数据页 | 正常淘汰 | BUFFER,MAX_BUFFER |
RECYCLE | 临时表数据页 | 正常淘汰 | RECYCLE |
FAST | 数据页、回滚页 | 常驻缓冲区 | FAST_POOL_PAGES |
KEEP | 普通数据页 | 很少淘汰 | KEEP |
-
日志缓冲区用于存放重做日志的内存缓冲区,由参数RLOG_BUF_SIZE进行控制;
-
字典缓冲区主要用于存储一些数据字典信息,由参数DICT_BUF_SIZE控制,如果对分区数较多的水平分区表进行访问,需要调大该参数值;
-
SQL缓冲区主要存储包,执行计划,结果集缓存等信息,对应参数为CACHE_POOL_SIZE,缓冲区使用不会超过INI配置大小。
内存池
DM的内存池包括共享内存池和一些运行时内存池。
-
共享内存池:是 DM Server 在启动时从操作系统申请一大片内存供系统运行时使用,避免运行期间频繁的进行系统调用降低系统运行效率,提供参数MEMORY_POOL设置大小和MEMORY_TARGET参数设置上限;
-
运行时内存池:为DM 的一些功能模块在运行时使用的自己运行时内存池,这些运行时内存池是从操作系统申请一片内存作为本功能模块的内存池来使用,如会话内存池、虚拟机内存池等。
查看内存池情况
下面举例进行介绍一个会话使用的内存池情况,我们使用DISQL工具连接数据库,查看此会话内存池情况,SQL语句:
SELECT
A.CREATOR ,
B.SQL_TEXT ,
A.NAME ,
A.TOTAL_SIZE/1024/1024 TOTAL_M,
A.DATA_SIZE /1024/1024 DATA_SIZE_M
FROM
V$MEM_POOL A,
V$SESSIONS B
WHERE
A.CREATOR = B.THRD_ID AND B.APPNAME='DIsql.exe';
通过执行结果我们可以发现,每创建一个会话系统就会产生一个SESSION运行池,下面使用DISQL执行一个语句查询结果:
可以发现在执行语句后此会话多了一个VM池,会话执行过程中根据会话类型还会生成其他内存池,但会话创建线程号固定,所以我们可以使用如下SQL获取会话执行时总使用内存:
SELECT
A.CREATOR ,
B.SQL_TEXT ,
SUM(A.TOTAL_SIZE)/1024/1024 TOTAL_M,
SUM(A.DATA_SIZE) /1024/1024 DATA_SIZE_M
FROM
V$MEM_POOL A,
V$SESSIONS B
WHERE
A.CREATOR = B.THRD_ID
AND B.APPNAME ='DIsql.exe'
GROUP BY
A.CREATOR,
B.SQL_TEXT
ORDER BY
TOTAL_M DESC;
下面我们使用DISQL工具执行一个两个大表的HASH连接语句,然后查看内存使用情况,语句计划如下:
执行过程中内存使用情况:
可以看出此会话在执行过程中一共使用了116M内存,如果此类SQL语句并发过多,数据库实例占用内存会非常大。
上面介绍了SQL运行过程中我们怎样去查看会话使用内存大小,但是如果SQL已经执行结束,我们怎样去定位SQL使用内存情况呢?
达梦数据库提供了V$SQL_STAT和V$SQL_STAT_HISTORY系统视图对语句级资源监控,需要调整参数ENABLE_MONITOR=1,才开始监控。V$SQL_STAT视图提供监控项生成的条件阀值,SP_SET_SQL_STAT_THRESHOLD()设置监控阀值,超过阀值才开始监控;
V$SQL_STAT_HISTORY视图单机最大行数为 10000。我们可以根据此视图对正在执行的语句和执行后的语句进行监控,可以使用下面的语句找出使用大内存的SQL:
SELECT SF_GET_SESSION_SQL(SESSID),MAX_MEM_USED,SQL_TXT FROM V$SQL_STAT ORDER BY MAX_MEM_USED DESC;
达梦数据库还提供了V$LARGE_MEM_SQLS和V$SYSTEM_LARGE_MEM_SQLS视图对大内存sql语句进行监控,通过INI参数LARGE_MEM_THRESHOLD进行设置阈值,一条sql语句使用的内存值超过此参数配置,就会记录到V$LARGE_MEM_SQLS中,此视图保留最近的1000条sql语句,通过如下语句可以对大内存sql进行排序:
SELECT * FROM V$LARGE_MEM_SQLS ORDER BY MEM_USED_BY_K DESC;
V$SYSTEM_LARGE_MEM_SQLS视图则存放的是系统中使用内存最多的 20 条 sql 语句。
通过上面的介绍,日常中我们可以通过实时查询V$MEM_POOL和V$SQL_STAT统计正在执行的SQL使用内存大小,也可以通过视图V$SQL_STAT_HISTORY和V$LARGE_MEM_SQLS等进行数据库系统运行过程中的大内存SQL进行监控和排查;在定位到具体SQL语句后我们可以在测试环境进行重现,实时的捕获其用到的内存情况,最后可以通过对SQL进行针对优化,消除HASH、排序等操作来减少SQL的内存使用。