项目名称: dmtop
项目定位: 达梦数据库本机实时性能诊断 TUI
支持平台: Linux amd64 / arm64
开源协议: MIT License
Gitee: https://gitee.com/sun-ying1119/dmtop
GitHub: https://github.com/greatfinish/dmtop
本文功能以当前
main分支为准;可执行文件版本和支持内容以 Releases 页面说明为准。
数据库“变慢”只是一个现象,不是一个诊断结论。
面对突发性能问题,DBA 通常先登录数据库服务器,用 top、vmstat、iostat、sar 判断 CPU、内存、磁盘和网络是否异常;再进入数据库查询 V$SESSIONS、V$SYSSTAT、V$TRX、V$TRXWAIT 和 V$SQL_STAT。如果发现达梦进程中的某个线程 CPU 很高,还要继续把 Linux TID 映射到数据库 SID,再从会话追到 SQL、存储过程内部语句、执行计划或阻塞者。
每一个命令都有价值,真正困难的是这些证据分散在不同终端、不同采样时刻和不同统计口径中。问题持续时间越短,DBA 越容易在切换命令和拼接字段的过程中错过现场。
dmtop 想做的事情很明确:
不建设另一套监控平台,而是把当前故障需要的 Linux 和 DM8 证据放进同一个终端,让 DBA 更快地从“数据库慢”走到“哪台设备、哪个线程、哪个会话、哪条 SQL 或哪条阻塞链”。
一次常见的现场排查可能从下面这些命令开始:
top -H -p $(pgrep -o dmserver) vmstat 1 iostat -x 1 sar -n DEV 1
随后进入数据库继续查询:
SELECT * FROM V$SESSIONS;
SELECT * FROM V$SYSSTAT;
SELECT * FROM V$TRX;
SELECT * FROM V$TRXWAIT;
SELECT * FROM V$SQL_STAT;
这些数据还需要人工关联:
Linux dm_sql_thd
↓ TID
V$SESSIONS.THRD_ID
↓ SID / SQL_TEXT_ID
当前 SQL、完整 SQL、执行计划
↓ TRX_ID / WAIT_FOR_ID
阻塞者、等待者、锁对象
问题不在于 DBA 不会使用这些命令,而在于故障现场需要更快地建立关联。操作系统看到的是线程和设备,数据库看到的是会话、事务和 SQL;只有把两部分放在同一采样窗口中,才能形成可靠的因果判断。
DEM、Exporter/Prometheus、性能快照和 AWR 类报告适合长期监控、趋势分析、告警和历史回溯。它们解决的是“过去一段时间发生了什么”。
dmtop 解决的是另一个问题:
我已经登录故障主机,现在最应该先看什么?
因此,dmtop 有意保持轻量:
disql;这也是选择 TUI 的原因。它保留了命令行工具启动快、资源占用低、适合 SSH 终端的特点,同时能持续刷新、排序、选中和下钻,不必把每次查询结果复制到另一个窗口再分析。
dmtop 将 Linux /proc 与 DM8 动态视图组织成同一份实时证据快照,集中回答六个问题:
它的诊断链可以概括为:
Linux /proc DM8 dynamic views
CPU / memory / disk / network V$SESSIONS / V$SYSSTAT / V$TRXWAIT / ...
| |
+----------------+-----------------+
|
v
Interval Snapshot
|
+----------------+----------------+
| | |
v v v
OS DB PROCESS
|
+-------------+-------------+
| |
v v
SQL Detail LOCK CHAIN
首行展示实例模式、状态、数据库名、实例名、数据库运行时间、实例数量和归档状态。
在单机、主备和多环境并存的系统中,先确认当前连接的是哪个实例,比任何性能指标都重要。诊断对象一旦看错,后续数字再精确也没有意义。
OS 区域直接读取本机 /proc,展示:
这部分先回答“数据库慢是不是主机资源造成的”。例如,CPU 很低但磁盘 util 和 await 同时升高,排查方向就不应该继续停留在 SQL CPU 上。
DB 区域采用相邻采样计算速率,主要包含:
| 指标 | 诊断意义 |
|---|---|
| sessions / active / idle | 当前连接与活动会话规模 |
| rw trx / trx waits | 有 DML、持锁或阻塞证据的事务,以及实时事务等待关系 |
| STMT/s | 数据库全局语句吞吐,能够反映存储过程内部静态 SQL |
| CURSOR/s | 当前采样区间可见游标执行速率,不冒充全局 QPS |
| TPS / UCPS | 事务与用户提交速率 |
| LIO / PRD / PWR / REDO | 逻辑读、物理读写和 Redo 压力 |
| PARSE / HARD / HARD% / PERR | 解析、硬解析比例和解析错误 |
| PLANHIT | 计划缓存辅助证据;口径矛盾时降级为 N/A |
| SYNC / LOCKMS/s / DEADLOCK | 单次提交同步延迟、区间锁等待时间和新增死锁 |
速率指标在首帧显示 warming up,数据源失败显示 N/A,当前状态不适用显示 -。dmtop 不会把未知数据伪装成精确的零。
PROCESS 最多显示 20 个用户会话,按当前采样区间 CPU 从高到低排列。主要字段包括:
SID TID %CPU AGE STATE USERNAME SQL_TEXT_ID
CLNT_IP CLNT_HOST APPNAME SQL_TEXT
TID 来自 V$SESSIONS.THRD_ID,可以直接和下面的 Linux 结果对应:
top -H -p $(pgrep -o dmserver)
选中会话按 Enter,可以查看三层 SQL:
V$SESSIONS.SQL_TEXT:客户端提交的 SQL 或 CALL;CUR_SQLSTR:当前正在执行的内部 SQL;SF_GET_SESSION_SQL(SID):会话完整 SQL。按 x 输入 SQL_TEXT_ID,可以继续查看完整 SQL 和执行计划。
dmtop 将 SQL 证据拆成三种语义:
EXEC/s、LIO/s、LIO/EX、HARD/s 和 CPU%,用于定位当前负载;?,用于发现未使用绑定变量的 SQL 模板。例如:
SELECT * FROM T_ORDER WHERE ORDER_ID = 10001;
SELECT * FROM T_ORDER WHERE ORDER_ID = 10002;
会归并为:
SELECT * FROM T_ORDER WHERE ORDER_ID = ?
模板面板展示 VARIANTS/s、HARD/s、EXEC/s 和 CPU%,并关联 USER、APPNAME、CLNT_HOST 与 CLNT_IP。
dmtop 基于 V$TRXWAIT.WAIT_FOR_ID 展开阻塞关系:
ROOT BLOCKER --[TID/T_LOCK_TEST]--> WAITER
多级阻塞按照 ROOT BLOCKER -> WAITER 展示,并关联双方 SID、TID、用户、锁类型、锁模式、对象和等待时长。DDL 锁可以显示为 OBJECT/X。没有阻塞时,LOCK CHAIN 不占主界面空间。
确认异常会话确实需要处理时,可以按 k 输入数据库 SID。工具会重新展示会话证据并要求二次确认,然后调用 SP_CLOSE_SESSION(SID)。这里使用的是数据库 SID,不是 Linux TID;不建议直接对达梦线程执行 kill -9。
业务响应变慢,但服务器总 CPU 只有 12% 左右。单看总 CPU,容易误判为“CPU 不高”。
第一步,看 OS 区域:
cpus: 8
CPU user: 12.5%
8 核主机上,一个线程占满单核时,整机 CPU 大约就是 100% / 8 = 12.5%。总 CPU 不高,不代表没有单线程瓶颈。
第二步,看 PROCESS:
TID 2249281 %CPU 100.0 ACTIVE AGE 2m
红色 %CPU 表明该达梦线程已经接近占满一个核心。SID、TID、用户、客户端和 SQL 已经在同一行,不再需要人工映射。
第三步,按 Enter 查看:
CLIENT_SQL CALL RIS.P_CPU_BURN(...)
CURRENT_SQL SELECT SUM(...) FROM ...
FULL_SQL CALL RIS.P_CPU_BURN(...)
客户端看到的是存储过程调用,真正消耗 CPU 的是 CURRENT_SQL。必要时按 x 查看完整 SQL 和执行计划。
OS 单核压力
+ PROCESS TID 100% CPU
+ ACTIVE AGE 持续增长
+ CUR_SQLSTR 指向计算型 SQL
= CPU 型长 SQL
数据库逻辑读快速增长,但 SQL RT 中看不到相同数量的游标执行。业务可能把大量 SQL 封装在存储过程中,或者游标生命周期短于采样间隔。
先比较 DB 区域的两个指标:
STMT/s 33000
CURSOR/s 0
LIO/s 198000
STMT/s 来自 V$SYSSTAT 的全局语句计数,可以观察存储过程内部语句;CURSOR/s 只表示采样区间可见游标的执行变化。两者差距很大时,dmtop 会提示:
INTERNAL SQL - STMT 33K/s, visible cursor executions 0/s
然后沿 PROCESS 找到高 CPU 或 ACTIVE 会话,按 Enter 查看 CUR_SQLSTR。如果相关游标能够跨采样保留,再进入 SQL RT 查看:
EXEC/s:执行频率;LIO/s:总逻辑读压力;LIO/EX:单次执行成本;CPU%:对应会话线程 CPU。EXEC/s 高、LIO/EX 低 → 高频低成本 SQL,重点看调用次数
EXEC/s 低、LIO/EX 高 → 低频重 SQL,重点看执行计划和访问路径
SQL 结构完全相同,只是条件中的数字或字符串不同。数据库需要反复解析新文本,CPU 消耗上升,计划缓存效率下降。
先看 DB 区域:
PARSE/s 21000
HARD/s 20900
HARD% 99.5%
PERR/s 0
高 HARD/s 和接近 100% 的 HARD% 表明大部分解析都产生了硬解析。随后按 p 进入 SQL PATTERN:
VARIANTS/s HARD/s EXEC/s USER APPNAME CLNT_HOST SQL_PATTERN
20.9K 20.9K ... RIS app.jar cluster01 WHERE ID = ?
这组证据能够回答三个关键问题:
当模板变体与全局硬解析风暴一致时,界面会给出 LITERAL SQL 提示。部分 DM8 版本的 plan total count 不能覆盖所有动态 SQL;如果 PLANHIT 与 HARD/s 明显矛盾,dmtop 会显示 N/A,避免用一个看似精确的数字误导判断。
某个 ACTIVE 会话持续很久。只看执行时间,无法判断它在使用 CPU、等待磁盘,还是被锁阻塞。
持续超过阈值的请求会出现带证据的提示:
LONG SQL - SID ... TID ... age 2m, CPU 99.5%, WAIT -, CUR_SQL SELECT ...
诊断时组合判断:
| 证据 | 更可能的方向 |
|---|---|
%CPU 高、WAIT 为空 |
CPU 计算、函数运算、低效连接或大规模扫描 |
%CPU 低、磁盘 await 高、PRD/PWR 高 |
存储 I/O 等待 |
| BLOCKER 非空、LOCK CHAIN 有记录 | 行锁或 DDL 锁等待 |
| ACTIVE AGE 长但 CUR_SQLSTR 变化 | 一个长存储过程中依次执行多条内部 SQL |
AGE 对 ACTIVE 会话表示当前请求年龄,即当前时间减 LAST_RECV_TIME。对于存储过程,它表示整个 CALL 的持续时间;内部单条语句要以实时 CUR_SQLSTR 为准。
应用执行了 DML 后没有及时提交,连接已经空闲,但事务仍保留修改或锁。普通会话列表容易把它看成一个没有负载的 IDLE 连接。
DB 区域先观察:
rw trx 1
PROCESS 中会话显示:
STATE IDLE-TX AGE >=12m TRX_ID ... DML_CNT 1 LOCK_CNT 3
持续达到阈值后会出现:
LONG TX - SID ... TX ... age >=12m, DML 1, locks 3, SQL UPDATE ...
这里的 >=12m 是 dmtop 连续观察到该事务的时间下限。DM8 当前动态视图没有提供可跨版本依赖的精确事务开始时间,因此工具不会把观测下限冒充真实事务年龄。
部分 DM8 版本会为只读空闲会话保留 V$TRX 行。dmtop 不会仅凭 TRX_ID != 0 就标记 IDLE-TX;只有存在 DML、持锁或参与阻塞链的证据时,才计入 rw trx 并展示事务年龄,避免把普通只读连接误报成长事务。
一个会话持锁,后续会话依次等待。数据库表面上可能只有少数 ACTIVE 会话,但业务请求已经排队。
先看 DB 区域:
trx waits 4
LOCKMS/s 2180
其中 trx waits 是当前捕获的事务等待关系;LOCKMS/s 是 V$SYSSTAT 的区间锁等待毫秒率,两者不是同一个口径。
再看 LOCK CHAIN:
ROOT SID 101 TID 2001 APP
--[TID/T_ORDER 35s]--> SID 102 TID 2002 APP
--[TID/T_ORDER 12s]--> SID 103 TID 2003 APP
DDL 锁可能显示为:
--[OBJECT/X T_DDL_LOCK]-->
处理顺序应该是:
k 重新核实目标 SID 并二次确认。业务提交耗时升高。问题可能来自数据库写入、Redo 刷盘、本地磁盘延迟,或者主备同步链路。
先看 OS:
Disk util 95%
await 18ms
WIO/s 1200
WMB/s 85
iowait 22%
再看 DB:
PWR/s 1100
REDO/s 80M
SYNC 35ms
判断路径如下:
OS util/await 高 + DB PWR/REDO 高
→ 数据库写压力正在推高本地磁盘延迟
DB SYNC 高 + 本地 await 低
→ 继续检查日志路径、刷盘机制或同步主备链路
OS await 高 + DB PRD/PWR 低
→ 检查同机其他进程、其他文件系统或共享存储负载
当提交同步延迟达到诊断阈值时,dmtop 会给出 COMMIT LATENCY 提示,并同时展示 SYNC 与最热磁盘 await,提示不会脱离证据单独下结论。
如果 dmtop 连接远程数据库,数据库指标来自远端实例,而 /proc 反映的却是本机,OS 和 DB 证据会发生错配。
因此,dmtop 的产品边界是本机快速诊断:把二进制放在达梦数据库服务器上运行,确保主机、线程、会话和 SQL 属于同一台机器。跨主机集中监控、长期趋势、告警、巡检报表和历史回放,应继续交给 DEM、Exporter/Prometheus 等持续监控体系。
dmtop 不是这些平台的替代品,而是 DBA 登录故障主机后用于快速收拢现场证据的第一把工具。
不同 DM8 补丁版本的动态视图和字段可能存在差异。dmtop 启动时会通过:
V$DYNAMIC_TABLES
V$DYNAMIC_TABLE_COLUMNS
检测目标实例具备哪些视图和字段,再选择兼容查询。缺少可选字段时只对单项能力降级,不会因为一个字段不存在而让整个 PROCESS 区域消失。
监控 SQL 使用会话 ID 与 /*dmtop*/ 标记双重排除自身;连接池最多使用一条连接,每轮采样复用同一批结果派生摘要、PROCESS 与 SQL 指标,尽量降低诊断工具对被诊断系统的影响。
发布版提供 Linux amd64 和 arm64 压缩包。它不依赖 disql、Go 工具链或外部 Agent。
下载地址:
安装发布包:
tar -xzf dmtop-v0.2.2-linux-amd64.tar.gz
cd dmtop-v0.2.2-linux-amd64
chmod +x dmtop
sudo install -m 0755 dmtop /usr/local/bin/dmtop
默认连接本机 5236 端口:
dmtop SYSDBA
指定非默认端口:
dmtop SYSDBA@127.0.0.1:5237
程序会隐藏密码输入,不需要把密码写进命令行、shell history 或进程列表。
常用交互键:
| 按键 | 操作 |
|---|---|
m |
返回 PROCESS |
s / S |
打开 SQL RT / SQL CUM |
p / 5 |
打开 SQL PATTERN |
Enter |
查看选中会话或 SQL 的详细证据 |
x |
输入 SQL_TEXT_ID,查看完整 SQL 和执行计划 |
k |
输入数据库 SID,核实并关闭会话 |
e |
查看参数、规模和环境信息 |
f |
冻结或恢复刷新 |
h |
查看帮助 |
q |
返回或退出 |
dmtop 使用 MIT License 开源。达梦原生 Go 驱动由用户从自己的 DM 安装目录或官方下载包单独提供,不包含在项目 MIT 授权范围内;下载预编译发布包的用户不需要额外安装驱动。
不同 DM8 版本、补丁和业务负载会带来不同的诊断现场。欢迎提交 Issue、字段兼容信息和真实故障案例,让这个工具逐步覆盖更多达梦数据库排障路径。
dmtop 不追求把所有数据库管理功能塞进一个终端。它只想把性能故障中最容易分散的证据提前关联好,让 DBA 少切换几个窗口、少拼接几段 SQL,更快地找到下一步应该检查和处理的对象。
文章
阅读量
获赞
