简介:本资源是专为达梦数据库性能评估定制的BenchmarkSQL 5.0开源测试工具包,面向数据库管理员、DBA、信创项目实施工程师及国产化替代选型技术人员,解决达梦数据库在高并发、混合负载场景下的基准性能验证与横向对比难题。压缩包共94个文件,含11个Java源码文件(支撑核心测试逻辑)、12个SQL脚本(覆盖TPC-C类事务模板及达梦适配语句)、8个Shell脚本(如runLoader.sh、runBenchmark.sh等自动化执行入口)、9个JAR依赖库(含log4j及达梦驱动相关jar),以及props.dm等关键配置文件,整体体积3.77MB,结构完整、开箱即用。已有800人学习下载,资源附带清晰的目录组织(含dameng专属配置目录、多数据库通用模块)和联系作者说明,可直接用于达梦环境部署、TPS/响应时间压测、性能瓶颈定位及与Oracle/PostgreSQL等主流数据库的实测对比分析。
1. BenchmarkSQL 达梦版:不是换个驱动就能跑通的数据库压测,而是要重调事务逻辑、适配方言、绕开锁死点的实战工程
你手头有一套达梦数据库集群,领导说“拿 BenchmarkSQL 跑个 TPCC 压测看看吞吐”,结果一上手就卡在java.sql.SQLException: ORA-00922: missing or invalid option——明明改了 JDBC URL,驱动也放对了位置,为什么连建表都报 Oracle 错误?这不是配置问题,是 BenchmarkSQL 默认脚本深度绑定 Oracle/PostgreSQL 语法和事务行为,而达梦虽兼容 Oracle 模式,但在序列生成、锁提示、批量插入返回值、甚至COMMIT WORK的语义上存在关键差异。这个“支持达梦数据库版”不是官方原生分支,而是社区或某厂商基于 v5.0 主干打的定制补丁包,它解决的不是“能不能连上”,而是“能不能按达梦的真实执行路径跑出可信的 tpmC”。适合正在做国产化替代选型、需要横向对比达梦与 PostgreSQL 在 OLTP 场景下真实事务处理能力的 DBA 和性能工程师——尤其当你发现用标准版 BenchmarkSQL 跑出来的达梦 tpmC 比实际业务慢 40%,那不是数据库慢,是你没踩对它的节奏。
2. 从零构建达梦版 BenchmarkSQL:源码编译、驱动注入与 schema 初始化三步闭环
BenchmarkSQL 达梦版不是下载即用的二进制包,它依赖对原始 Java 工程的定向改造。常见做法是基于 GitHub 上公开的benchmarksql-5.0主干(commita3f8b2c),打上达梦适配 patch 后本地编译。我一般会跳过 Maven 中央仓库拉取不可控的依赖,全程离线构建,确保环境纯净。
2.1 下载源码并应用达梦适配补丁
先确认你拿到的是带达梦支持的源码包(通常命名为benchmarksql-dm-patched-5.0.tar.gz或类似)。若只有原始 BenchmarkSQL,需手动集成关键修改点:src/client/jTPCC.java中的buildSQL()方法需替换达梦专用建表语句;src/client/jTPCCConnection.java需重写getSequenceNextVal()以适配达梦SELECT SEQ_NAME.NEXTVAL FROM DUAL;最关键是src/client/jTPCCStatement.java中所有INSERT ... RETURNING语句必须改为达梦支持的INSERT ...; SELECT LAST_INSERT_ID()模式(达梦不支持 RETURNING 子句)。
# 解压并进入源码目录 tar -xzf benchmarksql-dm-patched-5.0.tar.gz cd benchmarksql-5.0 # 确认补丁已生效:检查关键文件是否含达梦标识 grep -r "DAMENG\|dm.jdbc" src/client/ | head -5 # 应输出类似:src/client/jTPCCConnection.java: if (dbType.equals("dm")) { ...提示:不要跳过
grep验证。曾有团队因 patch 打错目录,导致编译后仍走 Oracle 分支,压测时大量ORA-00922报错却查不出根源。
2.2 注入达梦 JDBC 驱动并编译可执行包
达梦 JDBC 驱动DmJdbcDriver18.jar(对应达梦 8.1+)必须显式加入 classpath,且不能与旧版DmJdbcDriver17.jar混用。BenchmarkSQL 的run/目录下runDatabaseBuild.sh脚本默认只加载lib/*.jar,需手动将驱动拷入:
# 创建 lib 目录(若不存在) mkdir -p lib # 将达梦驱动放入(注意版本号必须匹配你的达梦服务端) cp /path/to/DmJdbcDriver18.jar lib/ # 编译(使用 JDK 1.8+,达梦驱动不兼容 JDK 11+ 的模块系统) ant -Ddb=dm clean build # 成功后生成 build/benchmarksql-5.0.jar编译成功的关键标志是build.xml中<property name="db" value="dm"/>被正确识别,且ant日志末尾出现BUILD SUCCESSFUL并提示Using database: dm。若报ClassNotFoundException: dm.jdbc.driver.DmDriver,90% 是驱动 jar 名称拼写错误(如多了一个1或少了个8),务必用jar -tf lib/DmJdbcDriver18.jar | head -3确认内部结构含dm/jdbc/driver/DmDriver.class。
2.3 初始化达梦 schema:绕开自动提交陷阱与权限校验
达梦默认开启AUTO COMMIT,而 BenchmarkSQL 的runDatabaseBuild.sh脚本假设数据库处于手动提交模式。直接运行会导致建表中途失败,因为达梦在 DDL 后隐式 commit,后续CREATE INDEX语句因连接状态异常而报Invalid state。解决方案是:先用达梦管理工具(如 DM Manager)手动创建空库 + 用户,再关闭该用户的自动提交:
-- 在达梦中执行(以 SYSDBA 登录) CREATE DATABASE tpcc_db DATAFILE 'D:\dmdata\tpcc\tpcc.dbf' SIZE 1024; CREATE USER tpcc_user IDENTIFIED BY "StrongPass123"; GRANT DBA TO tpcc_user; -- 关键:禁用自动提交(达梦特有) ALTER USER tpcc_user SET AUTOCOMMIT = OFF;然后执行初始化脚本:
# 修改 run/runDatabaseBuild.sh,指定达梦参数 export TERM=xterm ./runDatabaseBuild.sh -d dm -s 100 -c 100 -u tpcc_user -p StrongPass123 \ -h 192.168.1.100 -P 5236 -o ./output/tpcc_dm_build.log参数说明:
-d dm:强制使用达梦方言分支;-s 100:warehouse 数量,达梦单实例建议 ≤200,否则内存溢出;-c 100:并发连接数,达梦默认最大连接数为 1000,但 BenchmarkSQL 每个 worker 占 1 连接,需预留管理连接;-o:日志输出路径,必填,失败时第一排查点。
初始化成功标志是output/tpcc_dm_build.log末尾出现Done.且无ERROR行;若卡在Creating ITEM table...,大概率是用户权限不足或AUTOCOMMIT = OFF未生效。
3. 达梦专属配置调优:连接池、事务隔离与 SQL 重写三重适配
BenchmarkSQL 的props.dm配置文件不是简单改个 URL 就完事。达梦的连接池行为、事务快照机制、索引优化策略与 Oracle/PostgreSQL 存在本质差异。以下配置项必须手工校验,否则 tpmC 数据失真。
3.1 props.dm 核心参数解析与推荐值
达梦版 BenchmarkSQL 使用props.dm替代props.ora,其关键字段含义与调优逻辑如下表所示:
| 参数名 | 默认值 | 达梦适配建议值 | 为什么必须改 | 影响现象 |
|---|---|---|---|---|
db.driver | oracle.jdbc.driver.OracleDriver | dm.jdbc.driver.DmDriver | 驱动类名硬编码,不改则 ClassNotFound | 启动即报错 |
db.url | jdbc:oracle:thin:@localhost:1521:ORCL | jdbc:dm://192.168.1.100:5236/tpcc_db?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull | 达梦 URL 必须带?后缀参数,否则中文乱码、时间类型转换失败 | 插入数据时报Data truncation |
db.user | tpcc | tpcc_user | 用户名需与达梦中创建的一致,且该用户必须有CREATE TABLE,CREATE INDEX权限 | 建表阶段报Insufficient privileges |
warehouses | 10 | 50 | 达梦单节点对高并发 warehouse 的扩展性弱于 PostgreSQL,50 是稳定压测上限 | >100 时 JVM OOM 或达梦报Out of memory |
loadWorkers | 4 | 8 | 达梦批量加载效率低于 PostgreSQL,需更多线程分摊压力 | runDatabaseBuild.sh执行时间超 2 小时 |
terminals | 10 | 32 | 达梦默认连接等待超时为 60 秒,terminal 过少无法打满 CPU | tpmC 波动大,CPU 利用率 <40% |
注意:
props.dm中db.url的zeroDateTimeBehavior=convertToNull是达梦必需参数。达梦不支持0000-00-00日期字面量,而 BenchmarkSQL 的HISTORY表初始化含此值,不加该参数会导致建表失败。
3.2 达梦服务端关键参数联动调优
BenchmarkSQL 是客户端工具,但压测结果直接受达梦服务端配置制约。以下三项必须在达梦dm.ini中显式设置:
# dm.ini 关键配置(重启达梦服务生效) MEMORY_TARGET = 4096 # 单位 MB,建议 ≥4GB,达梦内存管理比 PostgreSQL 更敏感 MAX_SESSIONS = 2000 # 必须 ≥ BenchmarkSQL terminals + loadWorkers + 管理连接 ENABLE_MONITOR = 1 # 开启性能监控,便于后续用达梦性能分析器定位瓶颈特别提醒:达梦的MEMORY_TARGET不是硬限制,而是目标值。若设为2048但压测时物理内存不足,达梦会频繁触发内存回收,导致tpmC波动剧烈(标准差 >15%)。我一般会将该值设为物理内存的 60%,并用free -h实时监控。
3.3 SQL 重写:把 Oracle 风格语句翻译成达梦原生语法
BenchmarkSQL 的sql.common文件定义了所有核心 SQL,达梦版需重点修改三处:
- 序列取值:将
SELECT S_W_ID_SEQ.NEXTVAL FROM DUAL改为SELECT S_W_ID_SEQ.NEXTVAL FROM SYSOBJECTS WHERE ROWNUM=1(达梦DUAL表不支持NEXTVAL直接调用); - 分页查询:将
ORDER BY ... OFFSET ? ROWS FETCH NEXT ? ROWS ONLY改为ORDER BY ... LIMIT ?, ?(达梦 8.1+ 支持LIMIT,但不支持OFFSET ... FETCH); - 锁提示:删除所有
FOR UPDATE NOWAIT中的NOWAIT,达梦不支持该关键字,保留FOR UPDATE即可。
修改后需重新编译(ant clean build),否则改动不生效。验证方法:启动 BenchmarkSQL 前加-Ddebug=true参数,观察控制台输出的 SQL 是否含LIMIT和SYSOBJECTS。
4. 常见问题排查:达梦版 BenchmarkSQL 的 5 个典型翻车现场
达梦版 BenchmarkSQL 的报错往往不直接指向根因,而是表现为连锁反应。以下是我在多个模拟项目X 中踩过的 5 个高频坑,按「现象 → 原因 → 解决」结构整理,每一条都来自真实血泪经验。
4.1 现象:runLoader.sh执行到 85% 卡住,日志持续输出Waiting for loader threads to finish...
原因:达梦 JDBC 驱动在批量插入时默认启用rewriteBatchedStatements=true,但达梦服务端对该参数支持不完整,导致批量提交阻塞。
解决:在props.dm的db.url末尾添加&rewriteBatchedStatements=false,例如:jdbc:dm://...&rewriteBatchedStatements=false。实测关闭后加载速度下降 12%,但 100% 完成。
4.2 现象:压测中New Order事务成功率 <95%,大量Transaction rollback日志
原因:达梦默认事务隔离级别为READ COMMITTED,但 BenchmarkSQL 的New Order逻辑依赖REPEATABLE READ下的行锁行为。当两个 terminal 同时操作同一 warehouse 的 stock 表时,达梦升级为表级锁,引发死锁。
解决:在达梦中执行SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;,并在props.dm中增加db.isolation=4(4 对应TRANSACTION_REPEATABLE_READ)。
4.3 现象:runBenchmark.sh启动后立即报java.lang.NoClassDefFoundError: Could not initialize class dm.jdbc.driver.DmDriver
原因:JDK 版本不兼容。达梦 8.1 驱动仅支持 JDK 1.8,若系统默认 JDK 为 11 或 17,DmDriver的静态块会因模块系统限制而初始化失败。
解决:显式指定 JDK 1.8 路径:JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 ./runBenchmark.sh -d dm ...,并用java -version确认。
4.4 现象:压测 10 分钟后tpmC断崖式下跌至 0,达梦服务端日志出现Too many active sessions
原因:BenchmarkSQL 的terminals设置为 64,但达梦MAX_SESSIONS=1000被其他应用占用,剩余连接数不足。达梦不会拒绝新连接,而是让连接挂起,导致 BenchmarkSQL worker 线程无限等待。
解决:登录达梦执行SELECT COUNT(*) FROM V$SESSIONS;查看当前会话数;临时扩容MAX_SESSIONS至 2000,并在props.dm中将terminals降至 48,留足余量。
4.5 现象:result.txt中tPMCs数值为负数,如-2345
原因:达梦服务端时间被意外修改(如 NTP 同步偏差 >1 秒),导致 BenchmarkSQL 计算事务耗时出现负值。达梦的SYSDATE函数对系统时钟极其敏感。
解决:在达梦服务器执行timedatectl status确认 NTP 同步状态;若偏差 >500ms,运行sudo timedatectl set-ntp true并重启达梦服务。压测前务必校验SELECT SYSDATE FROM DUAL;与系统时间误差 <100ms。
5. 验证达梦压测结果可信度:用三组交叉指标锁定真实瓶颈
跑出一个tpmC=12500的数字不难,难的是确认这个数字反映的是达梦的真实 OLTP 能力,而非 BenchmarkSQL 自身或配置缺陷导致的假象。我坚持用以下三组交叉指标验证,缺一不可。
5.1 达梦服务端性能计数器 vs BenchmarkSQL 客户端统计
BenchmarkSQL 的result.txt只提供客户端视角的聚合数据,必须与达梦内置性能视图对齐。压测结束后立即执行:
-- 在达梦中查询(需 SYSDBA 权限) SELECT 'Physical Reads' AS metric, SUM(PHYSICAL_READS) AS value FROM V$SYSSTAT UNION ALL SELECT 'Logical Reads', SUM(LOGICAL_READS) FROM V$SYSSTAT UNION ALL SELECT 'Executions', SUM(EXECUTIONS) FROM V$SYSSTAT UNION ALL SELECT 'Parse Count', SUM(PARSE_COUNT) FROM V$SYSSTAT;将结果与result.txt中的Measured tpmC、Total Transactions、Total Executed SQLs做比例校验:
- 若
V$SYSSTAT中Executions是Total Executed SQLs的 1.8 倍,说明 BenchmarkSQL 统计漏掉了重试 SQL,结果虚高; - 若
Physical Reads占Logical Reads比例 >30%,说明达梦缓存命中率低,需检查BUFFER参数是否过小。
5.2 关键事务响应时间分布直方图
BenchmarkSQL 默认只输出平均响应时间(Average Latency (ms)),但达梦在高并发下会出现长尾延迟。我用runBenchmark.sh的-r参数生成详细日志:
./runBenchmark.sh -d dm -f props.dm -r 600 -l 300 -o ./output/tpcc_dm_run.log参数说明:
-r 600:预热 600 秒(达梦 JIT 编译需时间);-l 300:正式压测 300 秒;-o:输出详细日志。
然后用 Python 脚本解析tpcc_dm_run.log中的New Order响应时间,生成 P50/P90/P99 分布:
# parse_latency.py import re with open('./output/tpcc_dm_run.log') as f: lines = f.readlines() latencies = [] for line in lines: m = re.search(r'New Order.*?(\d+\.\d+) ms', line) if m: latencies.append(float(m.group(1))) latencies.sort() print(f"P50: {latencies[int(len(latencies)*0.5)]:.2f}ms") print(f"P90: {latencies[int(len(latencies)*0.9)]:.2f}ms") print(f"P99: {latencies[int(len(latencies)*0.99)]:.2f}ms")可信结果特征:P99 ≤ P50 × 3。若 P99 是 P50 的 10 倍(如 P50=12ms,P99=120ms),说明达梦存在锁竞争或 I/O 瓶颈,此时tpmC数值不可作为横向对比依据。
5.3 达梦锁等待链路追踪
当tpmC波动 >10% 或 P99 异常升高时,必须抓取达梦锁等待链。在压测进行中执行:
-- 查看当前阻塞链 SELECT BLOCKED_SESS_ID AS blocked, BLOCKING_SESS_ID AS blocker, SQL_TEXT AS blocked_sql FROM V$LOCK_WAIT A JOIN V$SESSIONS B ON A.BLOCKED_SESS_ID = B.SESSION_ID;若返回多行,说明存在锁级联。此时需结合V$SESSIONS查看blocker的STATE字段:
- 若为
ACTIVE且SQL_TEXT含UPDATE STOCK,是正常业务锁; - 若为
INACTIVE且SQL_TEXT为空,则是连接泄漏(BenchmarkSQL worker 未正确释放连接),需检查props.dm中db.maxConnections是否小于terminals。
最后说一句个人习惯:每次达梦压测前,我都会用dmrman工具做一次全库备份,不是怕数据丢,而是怕配置改错后无法回滚。BenchmarkSQL 达梦版不是玩具,它是国产数据库选型路上的一把标尺——标尺准不准,不在数字多大,而在你敢不敢把它拆开、调参、验证、再装回去。希望帮到你。
本文还有配套的精品资源,点击获取