2026-10-31  ·  工具

达梦 SQL 日志怎么读:把日志里的 ? 还原成真实参数

工具

📋 想照着敲?这篇有 交互操作版——步骤卡片导航、命令一键复制,现场对着敲更顺手:打开交互操作版 →

本文讲的工具是 dmsqlq,自研,单文件,开源之前先放二进制。下面每条命令、每个输出都是本机实跑取的,没改写、没补全。性能数字标了样本来源,你可以自己复核。

日志里那句 where fbill_id = ?,到底在执行什么

客户说"早上那条单子查不出来",你去翻 SQL 日志,看到的是这个:

[SEL] SELECT * FROM t_rim_invoice WHERE fbill_id = ? AND status = ?  EXECTIME: 18.4(ms)

两个问号。fbill_id 是什么、status 是几,这行本身都没写。

DM 把这两个值记在另一行:紧跟着的 PARAMS(SEQNO, TYPE, DATA),靠时间戳和会话/语句句柄跟语句配对。

2026-09-10 09:00:00.000 (EP[0]{sess:0x7f100a,user:SYSDBA,stmt:0x2010,...}) PARAMS(SEQNO, TYPE, DATA)={(1, VARCHAR, 'dac000000'),(2, INT, 0)}
2026-09-10 09:00:00.000 (EP[0]{sess:0x7f100a,user:SYSDBA,stmt:0x2010,...}) [SEL] SELECT * FROM t_rim_invoice WHERE fbill_id = ? AND status = ?  EXECTIME: 18.4(ms)

所以能不能还原,只看两件事:采集侧有没有把 PARAMS 行记下来;工具在参数值本身就带 ? 的时候,还敢不敢继续往下填。第二件是很多工具翻车的地方,后面讲 DMLOG 那一节会说到。

先把它拿到手

单文件,免安装,不需要运行时。不连库、不建表、不联网,只读日志、只写结果文件。install 做的事就是把二进制放进你的用户目录并修 PATH,不动 /usr;--remove 撤得干净。

平台包大小
Windows x64dmsqlq-V2.37-windows-x64.zip2.2 MB
Linux x86_64dmsqlq-V2.37-linux-x64.zip2.1 MB
Linux arm64(鲲鹏/飞腾)dmsqlq-V2.37-linux-arm64.zip1.9 MB

下完先对一遍校验值,十秒的事,能挡住中间人替换安装包——企业网里真发生过。

# Linux / macOS:进入解压后的 V2.37 目录
sha256sum -c CHECKSUMS.txt
# Windows PowerShell:和 CHECKSUMS.txt 里对应那一行的值比
Get-FileHash .\dmsqlq-V2.37-windows-x64.zip -Algorithm SHA256

公司网络拦 gitee,或者下载慢得离谱,去 issue 说一声,我换个地方给你。

下载页:gitee.com/jiangchuang/dm-tools(只放编译好的包,不放源码;dmkit 也在这)

四条命令,从「上不了手」到「能交付」

第四条只是同一个命令换了个参数。命令里的目录改成你自己的,其余照抄。

第 1 步:先把日志目录找出来,别背路径

网上教程大多写 /opt/dmdbms/data/DAMENG/log。这串是某次安装的默认值,不是固定值——装的时候数据目录可以指到任何地方,实例名也可以不叫 DAMENG。我这台的数据目录在 /dmdata/DAMENG,照着教程敲那行,得到的是 No such file。

更要紧的一点:日志压根不在数据目录下。我这台的日志在 /home/dmdba/dmdbms/log,是安装目录下的 log。数据目录和日志目录是两回事,别拿一个推另一个。

所以别猜,先问实例自己要。最省事是看进程:

ps -ef | grep dmserver | grep -v grep

输出里 path= 后面那串就是 dm.ini 的完整路径,它的父目录是实例目录:

dmdba  105734  1  0 10:03 ?  00:00:03 /home/dmdba/dmdbms/bin/dmserver path=/dmdata/DAMENG/dm.ini -noconsole

这条路不用连库。客户端连不上、口令也忘了的时候,它照样能动。

能连库的话直接查更快:

select para_value from v$dm_ini where para_name = 'SYSTEM_PATH';

返回 /dmdata/DAMENG,这就是实例目录。参数名是 SYSTEM_PATH,不是 PATH——v$dm_ini 里没有叫 PATH 的参数,有些教程写 para_name = 'PATH',跑出来 0 行。

日志到底落哪儿:查 sqllog.ini,别猜

实例目录下有个 sqllog.ini,SQL 日志写到哪里由里面的 FILE_PATH 决定。最快是连库直接查,不用登服务器翻文件:

select mode_name, para_name, para_value, is_default
  from v$dm_sqllog_ini where para_name like '%PATH%';

我这台的返回值:

MODE_NAME      PARA_NAME  PARA_VALUE  IS_DEFAULT
<DEFAULT>      FILE_PATH  ../log      Y
SLOG_ALL       FILE_PATH  ../log      Y
SLOG_ERROR     FILE_PATH  ../log      Y
SLOG_DDL       FILE_PATH  ../log      Y
SLOG_LONG_SQL  FILE_PATH  ../log      Y

五行对应五个配置段:一个全局加四个模式。最后那列 IS_DEFAULT = Y 说明全是默认值,没人改过。

../log 是相对路径,按 bin 目录解析,落到 /home/dmdba/dmdbms/log,也就是安装目录/log。它不是相对 sqllog.ini 所在的实例目录:按「实例目录/log」去翻是空的,我这台连那个目录都没建。

这个目录确实存在,里面放着 dm_DMSERVER_*.log 这类事件日志。但 dmsql_*.log 我没见它生成过,因为这台实例的 SQL 日志从来没真正打开过(原因见下),所以落点这一句是按 FILE_PATH 推算的,不是我亲眼看到文件在那儿。

要挪位置就把 FILE_PATH 改成绝对路径,比如 /data/dmlog。改完在库里执行一句,让内存重新读文件,不用重启:

call sp_refresh_svr_log_config();

实测返回 DMSQL executed successfully。这一句管的是「日志已经开着、你改了配置」,刷一下就换新路径;本来就没开的,刷了也不会凭空长出日志来。

两个视图名字像,查的东西不是一个:

V$DM_SQLLOG_INI 读磁盘上那份 sqllog.ini,不挑 SVR_LOG 状态,任何时候都查得到。
V$DM_SQLLOG_CONFIG 读内存里已经生效的那份。能查到它的时候,拿它跟 INI 对一遍,就知道你改完 sqllog.ini 到底刷进内存没有,这是它比 INI 多出来的用处。

但这台实例上它查不出东西,我试了三种状态:SVR_LOG = 0 时 0 行;动态改成 1(按 sqllog.ini 记)再 sp_refresh_svr_log_config(),还是 0 行;改成 2(详细模式)再刷,仍然 0 行。我猜是动态改参数不会让日志子系统重新初始化,得重启实例才真正加载。这一点我没重启验证,所以只是猜测。

还有更要紧的一层:两个视图给的 FILE_PATH 都是 ../log 这种相对值。就算 CONFIG 里有内容,也拿不到绝对路径,还是得知道 bin 目录在哪。想过这一关,别指望查视图,用前面那条 ps 命令。

这个目录里躺着好几种日志,名字像,内容完全不是一回事:

文件名是什么
dmsql_*.log要的就是这个——SQL 日志,带语句、耗时、参数
dm_*.log实例事件日志(启停、切换、报错),没有 SQL
dmtrc_*.log跟踪日志,另一套开关

一个 dmsql_*.log 都没有?多半是 SQL 日志压根没开。这个开关分两层,连上库查一句就见分晓:

select para_name, para_value from v$dm_ini
 where para_name in ('SVR_LOG', 'SVR_LOG_NAME');

我这台的返回值:

SVR_LOG        0
SVR_LOG_NAME   SLOG_ALL

SVR_LOG = 0 就是采集没开。这时候 dm_*.log 里只有启停和报错,一条 SQL 都不会有——不是工具读不出来,是压根没写进去。SVR_LOG_NAME 指向 sqllog.ini 里的 [SLOG_ALL] 那一段,具体采哪些位号、路径写哪儿,都在那一段里。

我这台的 sqllog.ini 在实例目录下(/dmdata/DAMENG/sqllog.ini),不在 bin 下。找不到就 find / -name sqllog.ini 2>/dev/null,或者干脆问库:

select para_value from v$dm_ini where para_name = 'CONFIG_PATH';

返回的目录就是实例目录,sqllog.ini 在那儿等着。

第 2 步:先扫一眼,不出文件

dmsqlq /home/dmdba/dmdbms/log -S

-S 大写是「只打到屏幕」,小写 -s 会额外生成一份 HTML 报告并用浏览器打开。实际输出(样例日志,600 条语句):

dmsqlq 2.37 统计报告   2026-10-31 00:45:14
────────────────────────────── 概览 ──────────────────────────────
  ★ 头号问题:累计耗时最高的是一类语句(600 次 / 累计 18.03s,
    占语句总耗时的 89.2%)—— 从它开始优化收益最大。
  日志文件         1 个(0.2 MB)
  SQL 事件         686 条
  参数还原         600 成功 / 86 待还原  (87.46%)
  扫描耗时         7ms → 36 MB/s
  日志时段         2026-09-10 09:00:00 → 09:09:59(跨度 10.0 分钟)
────────────── 优先优化推荐 Top2(按影响占比排序) ───────────────
    1 [优先] 影响占比 89.2%  次数 600  平均 30ms  累计 18.03s
      问题信号:SELECT * 取全字段(直接查基表)
      建议动作:只取需要的列 —— 覆盖索引时才可能免回表
      语句样例:SELECT * FROM t_rim_invoice WHERE fbill_id = 'dac000000' AND status = 0

注意它排的是累计耗时占比,不是单次最慢。一天只跑一次的 8 秒慢查询,不该排在每分钟 60 次、每次 200ms 的语句前面——后者一天耗掉的小时数才是真的。

第 3 步:把 ? 换成真实值,导出能直接执行的 SQL

dmsqlq /home/dmdba/dmdbms/log -o out.sql

out.sql 里长这样:

-- 2026-09-10 09:00:00 · [SEL] · 0.1ms · SYSDBA, · trxid:3816438, · SAMPLE
SELECT * FROM t_rim_invoice WHERE fbill_id = 'dac000000' AND status = 0;

-- 2026-09-10 09:00:00 · [UPD] · 0.5ms · SYSDBA, · trxid:3816438, · SAMPLE · /*未找到匹配参数: 占位符2个*/
update ACCOUNTS set BALANCE = BALANCE + ? where ACCT_ID = ?;

两条对照着看:第一条参数填好了,可以直接贴进 disql;第二条工具自己承认没找到参数,没有编个值糊上去。

「没还原」和「还原错了」是两种后果。前者你知道要手工补;后者你会拿着一条假 SQL 去复现一个根本不存在的现场,结论错得还很自信。所以还原不了的语句原样留 ?,注释头里写清占位符个数。

第 4 步:只要慢的,出交付清单

dmsqlq /home/dmdba/dmdbms/log -m 1000 -B 20 -o slow.sql

-m 1000 是耗时下限(毫秒),-B 20 是最多取 20 条。实际输出(样例取最慢 3 条):

-- 2026-09-10 09:09:59 · [SEL] · 60ms · SYSDBA, · trxid:3816637, · SAMPLE
SELECT * FROM t_rim_invoice WHERE fbill_id = 'dac000599' AND status = 5;

-- 2026-09-10 09:09:58 · [SEL] · 59.9ms · SYSDBA, · trxid:3816637, · SAMPLE
SELECT * FROM t_rim_invoice WHERE fbill_id = 'dac000198' AND status = 0;

要发给开发商或客户当优化清单,加 -e 交付_202609.xlsx 直接出 Excel,已经按累计耗时降序排好优先级,省掉你在 Excel 里手工排序那一小时。

它到底能扛多大

数字来自工具仓库的现网实测记录,样本、版本、结果都列出来:

样本实测结果说明
单文件 1.03 GB 现网日志
334 万条记录 / 92 万 SQL 事件
2.26 s
≈ 455 MB/s(单线程)
输出 46.8 万条可执行 SQL;参数还原成功率 97.8%。热数据单文件实测 549 MB/s
7 个日志 7.3 GB(冷盘) -j 1 → 99 MB/s
-j 4 → 157 MB/s
-j 8 → 146 MB/s
并发甜点在 4;到 8 已经撞上磁盘读带宽,再加没用
13.9 GB 全量(14 个来源) 锁等待 1,446 次
最长 1.71 s
顺带给出被争抢最狠的对象(表 10175:1,156 次,占全部等待 80%),拿 table id 反查字典即可定位

这活吃 I/O,不吃 CPU,否则单线程跑不到 549 MB/s。在外面再套一层 rg 之类的东西也不会更快:花钱的是磁盘读和 gzip 解压,不是文本匹配。

在库服务器上跑,建议 -j 2~4,别开满。省下的那两秒,不够抵你抢数据库实例 CPU 惹出来的麻烦。

报告能不能信,看这三个地方

一、先看采集缺口,「查不出来」的第一嫌疑

日志里显示「锁等待 0 次」,是真没锁竞争吗?大概率是没采集到。工具会把这件事挑明,不让你误判:

  采集缺口   缺位号 29:本批日志无事务/锁事件行(TRX: / DLCK / LOCK_TID 全为 0)
             → 「锁等待」「长事务」「TPS」是没采集到,不是没发生

判据很硬:29 位号一旦开启,事务事件行必然大量出现,不可能恰好是 0。要这个维度,就在 sqllog.ini 的 SQL_TRACE_MASK 里打开 29 重采;短期替代是在库上查 V$TRXWAIT / V$LOCK。

它还会顺手做一份采集配置体检:缺 28 就没有参数行(还原率直接归零)、缺 27 没有原始语句、缺 23 没有报错语句。位号记不住没关系,报告会直接告诉你缺哪个。

二、还原不了的,它明说,不装

/*未找到匹配参数: 占位符2个*/ 这行注释就是自检点。看到它,说明这批日志的 PARAMS 行缺失或被截断,不是工具坏了。回去查采集配置(位号 28),或者确认日志有没有被跨文件截断。

三、排序口径是「累计」,不是「单次最慢」

要回答「哪条 SQL 最拖垮系统」,累计耗时才是答案;要回答「哪条 SQL 最慢」,用 -m 卡耗时下限。两个问题不一样,别拿一个答案去回另一个。

和官方 DMLOG 怎么选

DMLOG 是这条路上的先行者,从零到一把「SQL 日志能分析」这件事做成了能用的东西。后来者包括 dmsqlq,都是在它提出的思路和口径上往前走的。下面只讲形态差异,不是谁替代谁。

维度官方 DMLOG 8.183dmsqlq
运行方式要一个 DM 分析库(32K 页)+ dmlog.properties + JDBC 连接单个二进制,dmsqlq . 就完事
结果落地在被分析的库里 DROP / CREATE 6 张分析表只写 SQL 文本文件,不落库
参数值本身含 ?整条放弃(同一批现网日志实测还原率 10.9%)继续还原(同批 97.8%)
参数值里带逗号会静默切掉前缀,仍标记为成功实测 14.9 万条含逗号/含引号的值全部完整

怎么选:要长期建库做趋势分析、本来就有 analys 库,DMLOG 那套仍然合适;要临时拿一份现网日志、几分钟出结论,而且绝不能在生产库上建表(尤其不能出现 LOG_COMMIT 同名被 DROP 的风险),用不落库这一支。

这次没有对 DMLOG 做计时实测,所以不引用任何耗时对比,只比有实测支撑的维度。

三种用法

现场救火,只有一台能连的机器

把日志目录整个拷出来,或者直接在库机上跑 dmsqlq 目录 -S,三十秒看结论。这时候最怕的是「为了分析先建个库」——现网不允许,也没时间。

给客户交优化清单

-m 200 -B 50 -e 交付.xlsx,按累计耗时排好序,附上每条的真实参数。客户拿着这份清单能自己去改索引、改 SQL,不用你再口头解释「那个时间段那条语句」。

长期观察,日志堆了几十 GB

直接喂目录或压缩包,-j 4。它按文件并行,压缩包内的条目也并行。这一点手工脚本很难做对,因为 gzip 本身是串行流,能重叠的只有「解压」和「解析」。

常见问题

单个大日志,开 -j 30 会快很多吗?

不会。并发只作用于多个文件或压缩包内的多个条目;单个大文件开满核也没用(实测 -j 1 与 -j 30 同速)。

它会不会改我的库?要不要装 Java / .NET?

都不会,都不用。单文件、零依赖,不连数据库、不建表、不联网。你可以把它拷到一台完全隔离的机器上跑,只要有日志文件。

记不住参数怎么办?

直接敲 dmsqlq 不带参数,就是交互向导:五问(日志在哪 / 要什么结果 / 时间范围 / 耗时下限 / 操作类型),每一步回车就是推荐值,最后把等效命令行打印出来,下次照着敲。TAB 补全首次交互运行时自动装好,选项和路径都能补。

为什么报告里有些语句没有 EXECTIME?

说明这条语句在日志里没有执行完成的行(采集期间实例重启、或语句还在跑)。这类不计入耗时统计,但会出现在事件计数里,看着「条数对不上」是正常的。

Windows 上用,路径要怎么写?

反斜杠和正斜杠都认:dmsqlq D:\dmsql_log -s 和 dmsqlq D:/dmsql_log -s 等价。路径里有空格就加引号。

能不能只处理某一段时间?

能,--from / --to 给时间范围(YYYY-MM-DD HH24:MI:SS)。只关心某类操作就加 --ops SEL(或多选 SEL,UPD)。

最后

它只解决一个问题:日志里那句话到底在执行什么,三分钟内给你一个能执行的答案,而不是让你在几百万行里手工捞参数。

做不到的也说清楚:它不替你判断该加什么索引,也不判断这条 SQL 业务上该不该存在。报告给的是证据和优先级,判断还是人做。

用着有问题、或者你手上的日志它读不动,提个 issue,把 --version 的输出和报错原文贴上就够定位。这类问题基本都能修,修完别人也能用。

← 返回目录