简介:BenchmarkSQL 是一套开源的数据库性能基准测试工具,这份资源为适配达梦数据库的定制版本。它面向数据库管理员、运维工程师和性能测试人员,主要解决达梦数据库缺乏标准化压测手段的问题,可在接近真实业务的读写混合场景中评估事务吞吐量、响应延迟等指标,也为不同数据库间的横向选型对比提供了统一口径。压缩包为 zip 格式,仅 3.77MB,共 94 个文件,包含 Java 源码与编译后 class、可直接运行的 jar 包、SQL 建表与存储过程脚本、Shell 启动脚本、properties 参数配置、XML 构建文件等,覆盖 BenchmarkSQL 从环境构建、数据装载、压测执行到结果汇总的完整链路。其中专门为达梦数据库准备了独立配置和 SQL 定义,使用者只需按实际环境调整主机、端口与账号信息即可开始测试。已有 799 人浏览学习,适合需要快速搭建达梦基准测试环境、做数据库对比评估或希望深入研究 BenchmarkSQL 工作机制的技术人员。
1. BenchmarkSQL 达梦版是干什么的:从一次信创压测说起
信创项目里最头疼的不是选型,而是数据库换掉之后,原来的压测方案全都作废。PostgreSQL、MySQL 时代我习惯用 BenchmarkSQL 跑 TPC-C 负载,但项目切到达梦数据库之后,这套工具直接用不了——JDBC 驱动不认、建表语句报错、脚本目录里连达梦的方言文件都没有。BenchmarkSQL 作为数据库测试工具,本身不挑数据库,前提是有人把驱动和 SQL 方言层适配好。所谓“支持达梦数据库版”,就是把 BenchmarkSQL 的 JDBC 连接、建表、数据装载、事务混合脚本全部改成达梦能听懂的语言,让同一套 TPC-C 模型能稳定跑在 DM 上。这篇笔记就是围绕这个适配版展开,讲清楚原理、落地步骤、常见翻车点和结果验证方法,适合正在做达梦适配、需要拿出可信压测数据的开发和 DBA 看。
2. 为什么 BenchmarkSQL 要专门适配达梦:TPC-C 模型与 JDBC 层的三道坎
2.1 TPC-C 负载模型与 BenchmarkSQL 的组成:它不只是“压一压”
BenchmarkSQL 的本质是 TPC-C 标准的实现。TPC-C 模拟的是一个批发商的订单处理系统,包含仓库、区域、客户、订单、订单行等数据表,以及五种事务:新订单(New Order)、支付(Payment)、订单状态查询(Order Status)、发货(Delivery)、库存查询(Stock Level)。这些事务不是均匀分布,而是按比例混合,比如大约 45% 是新订单、43% 是支付。这样做的目的是让测试负载贴近真实业务系统,而不是单纯地塞几条 SELECT 或 UPDATE 去考验数据库。
BenchmarkSQL 主要由三部分组成。第一部分是 Java 程序,负责解析参数、分配终端(Terminal)、按固定比例发起事务、统计结果;第二部分是 SQL 脚本组,包括建表脚本(如 sqlTableCreates.sql)、建索引脚本、删除表脚本、装载存储过程;第三部分是驱动层,通过 JDBC 访问目标数据库。它之所以在 PG、MySQL、Oracle 上都能跑,是因为这三部分里只有 SQL 脚本和 JDBC URL 是数据库相关的,Java 的调度逻辑是通用的。理解了这一点,就能明白“支持达梦数据库版”大概率做了什么:保留 Java 压测调度核心,把 JDBC 驱动换成达梦的,把 SQL 脚本改成达梦方言。
很多人在第一次接触 BenchmarkSQL 时有个误解:以为它只是一个像 SysBench 那样的全自动低代码工具,运行一个命令就能出报告。实际上,BenchmarkSQL 需要仔细配置 warehouse 数量、终端数、运行时长、事务隔离级别,并且要先手动执行建表和装载数据的步骤。它给的不是“一键压测”,而是一套可以审计的测试流程。这个区别在达梦适配版里尤其重要——如果你拿原版文档去套达梦版,可能在建表阶段就卡住了。
2.2 达梦数据库的 JDBC 驱动与 SQL 方言:适配的关键在“翻译”而不是重写
达梦数据库的 JDBC 驱动是独立的 jar 包,驱动类名是 dm.jdbc.driver.DmDriver,连接 URL 的典型格式是 jdbc:dm://192.168.1.10:5236。端口默认 5236,这一点和 MySQL 的 3306、PG 的 5432 完全不同。把驱动放入 BenchmarkSQL 的 lib 目录后,还需要在配置文件中显式指定驱动类名和 URL。仅这一步,就足以让原版 BenchmarkSQL 翻车——因为原版的 driver 配置默认是 org.postgresql.Driver 或 com.mysql.cj.jdbc.Driver。
比驱动更麻烦的是 SQL 方言。达梦在语法上兼容 Oracle 的很多特征,但又保留了自己的特性。举几个常见差异:
建表自增主键。MySQL 用 AUTO_INCREMENT,PostgreSQL 用 SERIAL 或 IDENTITY,达梦通常用 IDENTITY(1,1),也可以借助序列加触发器。BenchmarkSQL 的原版建表脚本是 PostgreSQL、MySQL、Oracle 各一份,达梦版必须在这些脚本基础上改写,否则执行到 CREATE TABLE 就会报语法错误。
数据类型命名。达梦能识别 VARCHAR2 和 VARCHAR,但某些版本里 VARCHAR2 的语义更接近 Oracle 的变长字符串,如果脚本里大量用 TEXT,达梦可能需要改成 CLOB 或直接使用 VARCHAR 长度上限。
函数和关键字。随机数生成、日期加减等操作,不同数据库差异很大。达梦虽然兼容 Oracle 函数,但要求函数名后不能省略空括号,有些 Oracle 语法还需要改写。这些细碎差异如果不逐项处理,数据装载阶段大概率会卡住。
所谓“适配版”,并不是把整个 BenchmarkSQL 重写一遍,而是打一套“翻译补丁”:JDBC 驱动换掉、连接 URL 换掉、建表和装载的 SQL 脚本换成达梦方言、dml 脚本里的关键函数换成达梦等价写法。理解了这一点,你就能判断手里的适配版质量如何——看 SQL 脚本目录有没有单独的达梦脚本,而不是只看 Java 代码是否加了“dm”选项。
2.3 选型理由:为什么用适配版而不是 SysBench 或自定义脚本
有人会问:既然适配这么麻烦,为什么不直接用 SysBench,或者自己写一套 Java/Python 压测脚本?这个问题我在实际项目里被问过很多次。SysBench 的强项是 OLTP 读写在单表或多表上的性能测试,但它的负载模型是简单混合事务,和真实业务订单流程差得很远,跑出来的数据在汇报时很难让人信服。自定义脚本更灵活,但要复现 TPC-C 的事务比例、事务隔离级别、热数据分布,开发量和调优周期都非常可观。我自己曾为了复现一个订单模型写了将近一千行 Python,最后发现并发控制不够严谨,结果没人敢用。
BenchmarkSQL 适配版的价值在于它保留了 TPC-C 的完整事务模型,并且经过了原版在多数据库上的大量验证,适配者只需要聚焦达梦相关的语法差异,而不是重新发明一套压测轮子。审计和价值认可度远高于自写脚本。从投入产出比看,哪怕你要花一周时间去调适配版,也比花一个月去写脚本再花两周去验证要划算得多。
当然,选型的前提是手里的适配版是可用的。如果只是把原版 BenchmarkSQL 的 README 改了个标题、加了个达梦的 README,但 SQL 脚本没有按达梦改写,那这版就是伪适配。拿到源码后,第一件事不是编译,而是检查 sql/databases/ 目录下是否存在达梦专属子目录,以及 lib 里面有没有 dm 的驱动 jar。这一步能筛掉一半以上的“假适配版”。
3. 把 BenchmarkSQL 达梦版跑起来:从 JDBC 驱动到第一个 TPC-C 报告
3.1 环境准备:JDK、脚本目录结构与 lib 目录的驱动引入
先说环境。BenchmarkSQL 本质是 Java 程序,JDK 1.8 及以上都能跑,但建议用 1.8 而不是最新版本,因为部分旧版脚本对 JDK 17 以上的模块化有兼容问题。操作系统方面,Linux 上是常态,本文以 CentOS 7 系为例。达梦数据库这边,确认版本是 DM8 或以上,并且达梦的实例已启动、端口可达。
拿到适配版源码后,先看目录结构。一个完整的 BenchmarkSQL 目录通常包含这些内容:
- benchmarksql/ 源码目录(含 Java 类)
- lib/ 第三方依赖驱动与运行时长所需的 jar
- runBenchmark.sh 主测试入口
- runDatabaseBuild.sh 建库建表与装载数据入口
- runDatabaseDestroy.sh 清理入口
- props/ 存放配置文件的模板目录
- sql/ 存放各数据库方言 SQL 脚本的子目录
原版里 sql/ 下面有 sql.common、sql.postgres、sql.mysql 等子目录,达梦适配版最常见的改动就是新增 sql/dm 或者在 sql.common 里加了达梦分支。你可以用以下命令快速确认有没有达梦驱动和脚本:
# 进入适配版根目录 cd benchmarksql # 检查 lib 下是否有达梦 JDBC 驱动 ls -l lib | grep -i dm # 检查 SQL 脚本目录中是否有达梦相关子目录 find sql -type d | grep -i dm如果没有看到 dm 驱动的 jar,需要把达梦安装目录下自带的 DmJdbcDriver18.jar(版本号因人而异,也可能是 dm8 开头的 jar)复制到 lib 目录。这一步之后,先不要急着跑测试,先验证驱动能被 JVM 正确加载:
java -cp lib/DmJdbcDriver18.jar dm.jdbc.driver.DmDriver正常情况会打印出驱动类的基本信息,说明 jar 没问题。如果报 ClassNotFoundException,说明驱动 jar 版本不完整或者类名不对。
接下来修改脚本权限,并准备一个专门的运行用户,不推荐用 root 跑压测,避免满目红色提示干扰诊断。用 oracle 用户或单独的 dbtest 用户比较合适。
3.2 配置 benchmark.properties:达梦连接的关键参数与解释
BenchmarkSQL 的配置主文件是 benchmark.properties。原版默认只有 PG 和 MySQL 的示例,达梦版会额外提供一个 props/dm.properties 之类的模板。如果没有模板,自己按以下内容创建一个即可。我一般这样配置:
# 数据库类型:dm(达梦) db=dm driver=dm.jdbc.driver.DmDriver conn=jdbc:dm://192.168.1.10:5236 # 达梦会话参数 user=SYSDBA password=SYSDBA_PASSWORD # TPC-C 负载规模 warehouses=10 terminals=20 runMins=10 # 装载数据时并发度 loadWorkers=4 # 终端运行时思考时间 timeOfTxn=10 # 结果输出目录 resultDir=./my_result_%tY%tm%td_%tH%tM%tS # 事务相关 isolation=TRANSACTION_READ_COMMITTED对每一项做个说明。db=dm 是适配版新增的数据库类型标识,如果你的适配版没有这个值,需要检查源码里是否有对应的方言加载逻辑。driver 就是达梦的 JDBC 驱动类名。conn 的格式必须是 jdbc:dm://后跟 IP 和端口,很多人把端口漏了或者写成 3306,这是最常见的连接失败原因。user/password 用达梦的管理员或可用的业务账号,注意 SYSDBA 的默认密码在安装时设置,不一定是你熟悉的。
warehouses 是仓库数,决定了总数据量,一般建议至少 10 起步,用于压力测试但不想数据集太大时 10 足够。terminals 是并发模拟终端数,可以理解为同时有多少个虚拟用户在提交事务,这个数直接决定并发压力。runMins 是运行分钟数,建议正式压测不低于 10 分钟,太短的话热数据分布还没稳定。isolation 我建议先设成 READ_COMMITTED,因为达梦默认事务隔离级别是读已提交,如果你在配置里写了 SERIALIZABLE 但达梦没有真正启用,事务并发时会产生大量阻塞,误以为是数据库性能差。
配置完成后,建议用 grep 检查一遍关键项:
grep -E "^(db|driver|conn|warehouses|terminals)" benchmark.properties确认 driver 和 conn 没有因为我手滑打错字。这一步花不了一分钟,却能省掉后面各种黑匣子排查时间。
3.3 建表与装载数据:跑 runDatabaseBuild 之前,先看懂三组 SQL 脚本
现在进入建表和装载阶段。运行 runDatabaseBuild.sh 之前,先搞清楚它会执行什么。常见做法是,脚本会依次读取 sql/common 下的公共脚本和 sql/dm 下的达梦专用脚本,执行建库、建表、建索引、装载存储过程的动作。如果你用的适配版没有 sql/dm 目录,说明这版适配不完整,不建议继续用它做正式测试。
用一个具体的达梦建表脚本来举例,这是整个适配里最容易出问题的地方。原版 PG 脚本里仓库表是这样写的:
CREATE TABLE warehouse ( w_id SERIAL PRIMARY KEY, w_ytd DECIMAL(12,2), w_tax DECIMAL(4,2) );SERIAL 在达梦里不被识别。适配后的达梦脚本一般会改成:
CREATE TABLE warehouse ( w_id INT IDENTITY(1,1) PRIMARY KEY, w_ytd DECIMAL(12,2), w_tax DECIMAL(4,2) );关键差异是 IDENTITY(1,1) 替代了 SERIAL。这是因为达梦兼容 Oracle 的 IDENTITY 语法但不支持 PG 的 SERIAL 关键字。如果你拿到适配版后手动改脚本,要注意达梦的 IDENTITY 在 CREATE TABLE 语句里使用时有严格的位置要求,一般跟在数据类型之后、约束之前。
装载数据这一步更值得注意。BenchmarkSQL 会用存储过程生成数据,达梦版要么提供达梦方言的装载存储过程,要么通过 JDBC 批处理方式插入。我倾向于检查 sql/dm 下有没有以 load 开头的脚本,如果没有,说明装载逻辑是 Java 侧通过 JDBC 插入,这种情况下 JDBC 驱动的批量插入参数就很重要。达梦的 JDBC 驱动默认批量插入可能需要显式开启 rewriteBatchedStatements 之类的参数,具体哪个参数以达梦官方文档为准,但在 props 的 conn URL 里预留参数位是明智的。
执行下面的命令开始建表与装载:
./runDatabaseBuild.sh props/dm.properties如果脚本在跑的过程中没有明显报错,并且日志末尾出现类似 “Data loaded successfully” 的信息,说明建表和装载都通过了。如果中途报错,不要急着重跑,先去看日志里是 SQL 语法错误还是连接错误。SQL 语法错误说明脚本没适配干净;连接错误则需要回查 benchmark.properties。
装载完成后,可以进到达梦数据库里粗查一下数据量,避免后面压测时遇到 INVALID INDEX 之类的诡异问题。我用达梦自带的 disql 连上去,执行如下命令:
SELECT COUNT(*) FROM warehouse;返回的数量应当等于配置的 warehouses 数。如果你配置了 10 个仓库,这个表应该精确返回 10 行。如果返回 0 或报错,说明建表后装载数据失败,需要回头看 runDatabaseBuild 的日志。
3.4 执行测试并解读输出:runBenchmark 与 result 目录里的报告字段
建表装载没问题后,就可以正式压测了。执行:
./runBenchmark.sh props/dm.properties这个命令会拉起配置的 terminals 数量的 Java 终端,按 TPC-C 事务比例跑 runMins 分钟,结束后把结果写入 resultDir 指定的目录。测试过程中日志会持续打印事务执行情况,比如新订单事务的平均响应时间、每分钟事务数(TPM)。不要盯着实时输出看细节,更容易漏掉关键错误。我一般会等测试结束,进入它生成的目录里看完整报告。
结果目录通常是一个带时间戳的文件夹,里面包含一个 result.txt 和若干审计文件。result.txt 里最关键的是这个指标:
Measured tpmC (NewOrders per minute) = 2537.45 Measured tpmTotal = 5012.89tpmC 是每分钟新订单事务数,也是 TPC-C 标准的权威指标;tpmTotal 是所有事务的总数。看报告时不要只看 tpmC,还要看有没有 NULL、死锁。如果你的适配版在 result.txt 里通篇都是 NULL 值和 0,那说明事务提交逻辑有问题,不是压测结果。
测试结束后,还要做一次清理,否则下次建表会由于表已存在而失败:
./runDatabaseDestroy.sh props/dm.properties这个命令会删除测试相关的表和序列。如果跑完压测不清理,下一次 runDatabaseBuild 会非常难堪。当然,确认达梦实例里没有其他人在用这套测试库的前提下,清理是安全的。如果还要调参重测,建议按 5.1 里的做法先 destroy 再 build,避免数据残留影响结果。
4. 达梦适配的避坑清单:连接、建表、并发三类典型翻车记录
4.1 ClassNotFoundException 与连接超时:JDBC 驱动路径与 URL 格式
现象:执行 runDatabaseBuild.sh 时,日志里抛出“java.lang.ClassNotFoundException: dm.jdbc.driver.DmDriver”,或者报连接超时(Connection timed out)。
原因:适配版源码里封装了达梦驱动,但实际的 dm JDBC jar 没有被放入 lib 目录。还有一类原因是 JDK 版本太新,导致驱动 jar 加载时被模块化边界挡住。连接超时则大概率是 URL 格式写错或端口不通。
解决:先把达梦自带的驱动 jar(文件名叫 DmJdbcDriver18.jar 或版本号类似)复制到 lib 目录,确认路径无误。如果 JDK 太新,可以切回 JDK 1.8。连接方面,在达梦服务器本地执行命令验证端口开放情况。我在一个项目里遇到过达梦装好了但防火墙没放行 5236 端口,导致远端连不上,本地却正常,这个问题不看网络配置很难发现。注意,连接 URL 里不要写多余的反斜杠或空格,避免字符集问题。
4.2 建表语法报错:VARCHAR 与 VARCHAR2、自增主键的达梦写法
现象:runDatabaseBuild 阶段 CREATE TABLE 语句报错,比如“语法分析出错”或“关键字 IDENTITY 无法识别”。日志会指到具体的行号,但很多人第一反应是去改 Java 代码,这是走偏了。
原因:原版 BenchmarkSQL 的建表脚本基于 PG 或 MySQL 方言,里面可能有 SERIAL、AUTO_INCREMENT、TEXT 类型。达梦不完全兼容这些写法,或者是适配版的 SQL 脚本里换错了关键字。
解决:直接查看 sql/dm 下的建表脚本,逐条对比原版脚本。看见 SERIAL 就换成 IDENTITY(1,1);TEXT 换成 VARCHAR 或 CLOB;如果存在布尔类型,换成 TINYINT 或 NUMBER(1)。改完之后,重新执行脚本之前,先手工跑一段 SQL 确认语法正确。另外注意,达梦里的关键字如 PERCENT、COMMENT 在某些场景有特殊含义,字段名不要设置成这些词。改完脚本后不要忘记执行 runDatabaseDestroy 清理,残留表会导致后续执行时重新命名冲突。
4.3 并发一高就锁等待:达梦的会话数、锁超时与 UDATA 空间
现象:terminals 数调到 50 以上,压测日志频繁出现“资源繁忙”“事务等待超时”的错误,TPM 数值不升反降,甚至直接掉到几百。
原因:BenchmarkSQL 的终端发起的事务密集度很高,达梦的默认锁等待时间可能很短,或者数据库的会话数上线不够,也可能是 UDATA 表空间不足以支撑大量并发时的 undo 数据。
解决:分三步处理。第一步,调大达梦的会话并发参数,比如 MAXSESSIONS、MAX_SESSION_STATEMENTS 等,具体以达梦版本为准。第二步,把锁等待超时时间调大,或用 ALTER SYSTEM 调整死锁检测间隔。第三步,检查 UDATA 表空间大小,如果剩余空间不足,扩展数据文件。还有一点容易被忽略:达梦的隔离级别是否真的生效。BenchmarkSQL 在 props 里写一个隔离级别,但数据库端没开启对应隔离,可能只是表现上一致,实际锁行为完全不同。配置完达梦参数后,重跑前先用 runDatabaseDestroy 清一次库,排除旧数据干扰。我在一个项目里把这几个参数都调了之后,TPM 从 800 涨到 4000 多,差别非常大。
4.4 结果集为 NULL 或 TPM 偏低:隔离级别与自动提交的副作用
现象:压测跑完了,result.txt 里的 tpmC 是 0 或所有字段都是 NULL,看着像程序没执行成功,但日志又没有报错。
原因:BenchmarkSQL 的 Java 代码里关于事务提交位置的设计依赖数据库的自动提交开关。如果达梦 JDBC 驱动的默认行为是自动提交,但压测事务里包含了必须手动提交的多语句事务,那么事务的完整性就被破坏了,统计结果就会异常。另外,隔离级别设置不当也会导致读不到未提交数据或频繁重试,拉低 TPM。
解决:在 benchmark.properties 里把隔离级别明确设置为上层业务常用的级别。我在达梦上常用 TRANSACTION_READ_COMMITTED,如果你的适配版带额外的 conn 参数,需要检查是否支持类似 reWriteBatchedInserts 的批量插入开关。开启批量写入参数后,装载数据的速度更快,事务提交的数量也能对上。改完配置后,建议先用 2 分钟做一次短时测试,确认 result.txt 里的值不为 NULL,再跑正式时长。这个验证动作非常值得做,能避免压测跑了一小时后才发现结果无效的后悔药场景。
5. 验证结果真实性的三个技巧:不止是看着 TPM 数字好看
5.1 多次运行取中位数:手工统计与短时 smoke test
跑一次压测就出报告,很容易受到数据库缓存、后台任务、网络波动的干扰,得出的 TPM 可能远高于实际水平。我通常先做一轮短时压测验证脚本能跑通,再连续做三轮正式压测,每次时长相同、terminals 相同,取 TPM 的中位数作为汇报值。这不是统计学洁癖,而是数据库压测本身就有随机性,第一轮结果往往会因为索引尚未装载进缓存、统计信息未收集而偏低,如果直接取第一次,大概率会被业务方当场质疑。短时 smoke test 用 2 分钟,正式测试至少 10 分钟,批次之间先 destroy 再 build,让每次的数据分布一致。
5.2 结合系统指标判断瓶颈:TOP、IOSTAT 与达梦监控
只盯着 BenchmarkSQL 的 result.txt 是不够的。当 TPM 不符合预期时,你需要判断瓶颈究竟是并发配置太低,还是数据库服务器本身资源不够。我习惯在压测时另开一个终端,每隔几秒运行一次 top 和 iostat,记录 CPU、内存、磁盘利用率。如果 CPU 已经 100% 但 TPM 还是上不去,说明在 CPU 层面遇到瓶颈;如果磁盘 util 长期接近 100% 而 CPU 空闲很多,那问题就在 IO。达梦自带的监控工具能看活动会话数和锁等待情况,压测时把这些数据同步抓下来,出现锁风暴时能直接定位到具体会话。
5.3 调参进阶:从 warehouse 数量到驱动批量参数的配合
参数调整不是拍脑袋。基准是 warehouse 数决定数据规模,terminals 数决定并发压力。增大 warehouses 会让数据量扩大、索引高度增高,但 TPM 可能会下降,因为单表扫描变慢;增大 terminals 会提升并发争用,但过了临界点后 TPM 会掉头向下。我一般用“先固定 warehouses,再逐步加 terminals”的方法,分别测试 10、20、30、40 个终端的曲线,找到拐点。达梦驱动侧还有批量抓取参数可调,像 fetchSize 和 batchSize 会影响数据装载阶段的效率,进而影响压测稳态的建立。以前我图省事,只用默认参数跑一遍就上报结果,后来被业务方拿真实业务数据一对比,差距太大,才明白参数调优是压测过程的一部分,不是可有可无的玄学。如果你也是在信创场景下提交报告,希望这些经验能让你少走一段弯路,帮到你。
本文还有配套的精品资源,点击获取