数据库选型评审会上,最容易被问住的一句话不是"你们选了哪个库",而是"你们那个 HammerDB 的测试报告,TPM 到底怎么算出来的"。我见过太多团队把压测跑完、截图一贴,数字很漂亮,可一旦被追问仓库数多少、思考时间设没设、客户端是不是瓶颈,现场就答不上来了。HammerDB 是一个开源的数据库负载测试工具,支持 TPC-C 风格的 OLTP 负载和 TPROC-C、TPROC-H 这类分析型负载,能对 Oracle、SQL Server、DB2、MySQL、PostgreSQL、MariaDB 等主流引擎发起标准化压测;它解决的问题是"在没有商业压测工具预算的情况下,也能得到口径相对统一、可复现的数据库吞吐与延迟数据"。但这套工具最大的特点恰恰在于——它给你的是原始数据,不是结论。同一份结果,不同的人能读出完全相反的答案。这篇文章面向已经会用 HammerDB 建表加载、但卡在"结果怎么解读"这一步的读者,也照顾刚开始接触压测、想知道哪些坑不必自己踩一遍的朋友。下面这些内容,是我在实际跑过若干轮之后总结出来的口径统一方法、参数差异处理和误读排查清单。
1. HammerDB 到底在测什么,先把指标口径统一
在打开图形界面之前,有一件事必须先做:把指标的定义对齐。很多所谓的"数据库性能对比"之所以没有意义,不是因为工具不专业,而是因为两个团队嘴里说的"TPM"根本不是同一个东西。这一节把三个最容易混淆的概念拆开,顺便点出那个几乎所有人都会忽略的隐形天花板。
1.1 TPC-C 与 TPROC-C:一个是标准,一个是实现
TPC-C 是一套公开的 OLTP 基准规范,它定义了五类事务(新订单、支付、订单状态、发货、库存查询)、九张表的结构、事务配比、一致性要求,甚至连终端的思考时间都做了约束。任何想对外宣称"符合 TPC-C"的结果,都必须经过完整的审计流程,包括价格核算、全链路披露。
HammerDB 提供的是TPROC-C,可以理解为对 TPC-C 的一次开源复刻。它复用了相同的表结构、相同的五类事务、近似的事务配比,但不做官方审计,也不承诺合规宣告。这个区别听起来像法律条文,实际影响很大:TPROC-C 允许你关掉同步提交、关掉二进制日志、把持久化参数调到最低,从而跑出一个非常好看的数字。这么做在内部评估里完全合理,但你必须清楚——这时的结果衡量的是"引擎在最宽松持久化设置下的处理能力",而不是"生产环境能扛多少单"。
所以第一件要写进报告的事,是这一行小字:本轮测试基于 HammerDB TPROC-C 实现,非 TPC-C 官方审计结果,持久化参数设置如下。没有这句话,后面所有对比都缺少前提。
1.2 TPM、NOPM、tpmC 三个数字的真实关系
HammerDB 跑完一轮,界面上会给出 TPM 和 NOPM 两个数。NOPM 是 New Orders Per Minute,每分钟完成的新订单事务数;TPM 是 Transactions Per Minute,每分钟完成的全部事务数。TPC-C 里衡量性能的官方指标叫 tpmC,它的定义就是每分钟新订单事务数——也就是说,tpmC 对应的是 NOPM,不是 TPM。
这两者的差距有多大?看事务配比就明白了。TPROC-C 的五类事务占比大致是新订单 45%、支付 43%、订单状态 4%、发货 4%、库存查询 4%。所以全部事务数大约是新订单数的 2.22 倍,反过来 NOPM ≈ TPM × 0.45。
我见过最典型的翻车现场,是有人直接把界面上那个更大的 TPM 数填进对比表,标题写"某某库达到 XX 万 tpmC"。这一填,数字凭空高了 2.2 倍,而且因为所有被测库都被同样放大,横向排名看起来还"挺合理",实际上整张表的绝对值全部失真,一旦对外引用就会出问题。
稳妥的做法是:报告里同时给出 TPM 和 NOPM,用 NOPM 换算 tpmC,并在表头注明"tpmC 由 NOPM 换算,未经官方审计"。如果工具版本较新,还能拿到响应时间(Response Time)指标,这个后面会用到。
提示:不同大版本的 HammerDB 对 TPM 的计数细节有过调整,跨版本对比数据之前,先用同一版本、同一脚本跑一遍基线,确认计数口径一致,再谈性能差异。
1.3 仓库数是吞吐的隐形天花板
这一条是我认为整篇文章里最值钱的部分。TPC-C 规范里有一个很容易被忽略的约束:单个仓库对应的数据量是固定的,而每个仓库每分钟能产生的吞吐也存在理论上限,业界通行的推导值是每个仓库约 12.86 tpmC。这个数字来自终端数量、思考时间和事务配比的联合约束,不必深究推导过程,记住它的用途就行——它是一条硬性天花板。
换成公式:仓库数 × 12.86 ≥ 你能跑出来的 tpmC。
反推一下就很吓人。假设你想跑出 10 万 tpmC,按这个上限,仓库数至少要有 7778 个。一个仓库的数据量大约 100MB 量级(含索引),7778 个仓库就是接近 800GB 的数据。所以那些动辄几十万 tpmC 的官宣成绩,背后往往是十几 TB 的数据集和几十台服务器。
而常见的内部压测是什么配置?100 个仓库、10GB 数据、一台 16 核机器。100 个仓库的理论上限大约是 1286 tpmC。如果你实测跑出了 2000,那不是数据库超常发挥,而是你的负载配置绕过了规范约束——思考时间没设、或者事务配比被工具按其他方式调度了。反过来,如果你把 64 个虚拟用户压在 100 个仓库上,发现吞吐卡在某个数上怎么加并发都不涨,先别怀疑数据库,算一下是不是撞到仓库数上限了。
这个坑之所以隐蔽,是因为它表现得非常像"数据库到瓶颈了":曲线平了、CPU 没满、延迟开始涨。新手会立刻去调参数,老手第一件事是回头数仓库。
2. 六大数据库接入 HammerDB 的差异点
HammerDB 对六款数据库的支持程度并不一样,有的开箱即用,有的需要额外准备驱动和字符集,有的建表脚本会直接因为参数不足而失败。把这些差异提前摸清,能省掉大半天的时间。
2.1 六款引擎的能力画像与测试定位
先建立一个基本认知:这六个库不是同一类东西,把它们放在一张表里排名,本身就是有问题的做法。它们的架构路线、锁与并发模型、日志与持久化机制差别很大,压测结果反映的是"在特定负载和特定配置下的处理效率",不是"谁更先进"。
| 数据库 | 典型定位 | 并发与锁的基本路线 | 压测时最该关注的点 |
|---|---|---|---|
| Oracle | 商业关系库,重事务一致性 | 多版本读一致性,回滚段/UNDO 管理 | UNDO 表空间、连接数上限、SGA 分配 |
| SQL Server | 商业关系库,生态集成度高 | 行版本或锁式读,取决于隔离级别 | 恢复模式、tempdb 争用、并行度设置 |
| DB2 | 商业关系库,偏重批处理与稳定吞吐 | 锁与隔离级别可调空间大 | 缓冲池、锁列表、应用连接上限 |
| MySQL | 开源关系库,互联网场景常见 | InnoDB 行锁 + MVCC | 缓冲池、日志刷盘策略、连接数 |
| PostgreSQL | 开源关系库,扩展性强 | MVCC + 多版本清理机制 | WAL 配置、自动清理、连接模型 |
| MariaDB | 开源关系库,与 MySQL 同源分支 | 与 InnoDB 类似,可选其他引擎 | 存储引擎选择、日志配置、线程池 |
看这张表就能明白一个道理:压测结果的可比性,取决于你把它们的配置拉到同一个"公平线"上。这条公平线不是"都用默认值"——默认值在六个库里差异巨大,有的默认内存只给 128MB,有的默认连接数只有 100。公平线应该是:内存分配比例一致、持久化等级一致、连接数余量一致、日志写入策略一致。做到这四点,对比才有讨论价值。
2.2 驱动、连接方式与建表脚本的差异
HammerDB 通过各数据库的原生驱动或通用驱动建立连接。Oracle 走 Oracle 客户端或纯驱动模式,SQL Server 走 ODBC 或原生驱动,DB2 需要 CLI 驱动,MySQL 和 MariaDB 走通用连接器,PostgreSQL 走 libpq 风格接口。驱动版本不匹配是加载阶段最常见的失败原因,尤其是换了新版本数据库但客户端库还是旧的。
建表阶段还有几个具体的差异点值得提前知道:
- 字符集与排序规则:MySQL 和 MariaDB 建库时要显式指定字符集,默认字符集不一致可能导致建表脚本在某些环境下变慢甚至报错。
- 大小写敏感:PostgreSQL 对标识符的大小写处理与其他库不同,脚本里如果混用了大小写,会出现"表建好了但查不到"的情况。
- 表空间与文件组:Oracle 和 SQL Server 支持把表和索引放到不同表空间/文件组,这是提升 IO 并行度的有效手段,但也意味着你要在建表前先规划好存储布局。
- 分区选项:HammerDB 提供分区建表的开关,开启后订单表会按仓库号切分。这个开关对不同引擎的收益差别很大,横向对比时六个库必须统一开或统一关,否则比的是分区能力而不是引擎效率。
命令行方式比图形界面更适合做可复现的测试,因为脚本本身就是记录。下面是一段 PostgreSQL 的示意脚本,其他库只需要替换前缀和连接参数,结构完全一致:
dbset db pg dbset bm TPC-C diset connection pg_host 127.0.0.1 diset connection pg_port 5432 diset tpcc pg_user tpcc_user diset tpcc pg_pass tpcc_pass diset tpcc pg_count_ware 200 diset tpcc pg_num_vu 32 diset tpcc pg_partition false buildschema退出码为 0 才算建表成功。这一步失败率相当高,常见原因是连接数不够(建表时会按并行度拉起多个连接)、临时表空间不足、或者磁盘剩余空间不够放数据加索引。我的习惯是在建表前先算一遍预估容量,再乘以 1.5 留余量。
2.3 各库必须提前调整的关键参数
默认参数下压测,大部分时候测的是"默认配置有多保守",不是引擎实力。下面这张表列出每个库最容易卡住吞吐的几个参数,具体数值要按你的硬件规模和仓库数来定,不要照抄。
| 数据库 | 关键参数方向 | 不调整会怎样 |
|---|---|---|
| Oracle | 进程与会话上限、UNDO 表空间、SGA/PGA 目标 | 并发一上去就报连接数超限,长事务把 UNDO 撑爆 |
| SQL Server | 最大服务器内存、并行度阈值、tempdb 文件数与初始大小 | 内存被系统吃掉,临时对象争用严重,吞吐抖动 |
| DB2 | 缓冲池大小、锁列表、最大应用连接数、日志缓冲 | 锁等待激增,日志写满导致事务挂起 |
| MySQL | InnoDB 缓冲池、日志文件大小、刷盘策略、最大连接数 | 缓冲池太小导致读放大,日志切换频繁拖慢提交 |
| PostgreSQL | 共享缓冲、WAL 相关配置、最大连接数、自动清理阈值 | 写入放大严重,后台清理跟不上,延迟周期性飙升 |
| MariaDB | 缓冲池、日志配置、线程池或连接数上限、存储引擎选择 | 与 MySQL 类似,另外要确认建表用的引擎符合预期 |
这里有一个必须坦白说明的取舍:为了测出引擎的处理上限,很多团队会在这轮测试里关闭同步刷盘、关闭二进制日志。这在内部评估中是可以接受的,但要在报告里明确写出来,并且保证六个库用同等宽松度。拿一个关了日志的库去比一个开了日志的库,这种对比表在评审会上是撑不住的。
注意:任何参数调整都要留下记录,包括调整前后的值、调整理由。压测报告里最有说服力的部分往往不是那个数字,而是"我们为了让六个库处在同一条件下做了哪些对齐"。
3. 一轮完整压测的实操流程
流程本身不复杂,难的是每一环都做到位。我按自己在实验室里的执行顺序拆成四步:环境规划、建表加载、阶梯加压、数据采集。
3.1 环境与客户端规划
数据库负载测试里有个经典陷阱:被测库还没到瓶颈,压测客户端先趴下了。HammerDB 的每个虚拟用户是一个独立的连接和执行线程,虚拟用户数一多,客户端本身的 CPU 占用会非常可观。压 128 个虚拟用户时,客户端至少要留出 8 个物理核,否则你测到的是客户端的调度能力。
几条硬性要求:
- 客户端与被测库分离部署,不要同机。同机会让 CPU 和内存统计失去意义。
- 网络带宽和延迟要记录。跨机房压测时,网络往返时间会直接体现在事务响应时间里,尤其是那些短小高频的事务。
- 多客户端场景必须做时间同步。两个客户端时钟差几秒,合并后的曲线就会出现莫名其妙的锯齿。
- 固定 CPU 频率策略,关闭省电模式。这一条被无数人忽略,但它能让同一配置下的两次测试结果差出 10% 以上。
我在一台 16 核 32GB 的本地实验机上做过对照:开启省电模式时,同一轮压测的吞吐比性能模式低约 12%,而延迟中位数高出约 20%。这 12% 放到横向对比表里,足以让排名颠倒。
3.2 建库建表与数据加载
数据加载阶段的目标不只是"把表建出来",还要保证数据分布一致。HammerDB 生成的数据是伪随机的,但它支持指定随机种子。六个库如果用不同的种子,数据分布会有细微差异,理论上不影响大体结论,但严谨一点总没坏处——固定种子,六个库用同一份。
加载过程中要盯三件事:
- 加载耗时。这本身就是一个有参考价值的指标,反映批量写入和索引构建的效率,但不要把它混进 OLTP 吞吐结论里,两者是不同维度的能力。
- 加载后的对象统计信息。索引是否全部创建成功、统计信息是否收集过,直接决定第一轮压测的执行计划质量。
- 磁盘占用。实际占用和预估差太多,说明数据类型或索引策略有问题。
加载完成后建议做一次全量备份或快照。这样后面调参数调崩了,回滚只要几分钟,不用重新等几个小时的加载。
3.3 阶梯加压与稳态判定
这是整个流程里最需要耐心的一步。正确做法是阶梯式加压:从低虚拟用户数开始,比如 8、16、32、64、128、256,每一档跑固定时长,记录该档的吞吐与延迟,直到吞吐不再增长或延迟明显恶化为止。
每档的时长怎么定?我的经验是:预热时间不少于总时长的 20%,稳态观察不少于 15 分钟。如果一档只跑 3 分钟,前 1 分钟还在填缓冲池,后 1 分钟又开始受后台任务干扰,中间那段"看起来稳定"的数据其实样本量太小,抖动极大。
怎么判断"进入稳态"?看三个信号同时满足:吞吐的分钟级波动在 ±5% 以内、CPU 利用率曲线走平、数据库端的等待事件构成不再变化。三个信号缺一个,就再等几分钟。
还有一个细节:虚拟用户的建立和销毁本身有开销。如果每档都重新创建连接、重新登录,这部分开销会被算进事务时间里。更好的做法是在同一轮内逐档递增负载,或者至少给每次加压留出足够的爬坡时间。
3.4 采集哪些数据才算完整
只记录一个 TPM 数字的报告是不合格的。一个能支撑结论的采集清单至少包含四层:
第一层,工具侧输出:TPM、NOPM、响应时间(平均值与高分位)。如果版本支持,把每分钟的明细导出成 CSV,后面画曲线要用。
第二层,数据库侧指标:连接数、活跃会话数、锁等待次数与累计等待时长、缓冲池命中率、日志写入量、检查点频率。不同库的取法不一样,Oracle 走等待事件视图,SQL Server 走等待统计视图,PostgreSQL 查活动会话与后台写入统计,MySQL 查引擎状态和性能视图,DB2 查快照与锁信息。名字不必记全,思路是固定的:吞吐、延迟、等待、资源四件套。
第三层,操作系统侧指标:CPU 使用率(区分用户态和系统态)、内存与交换分区使用、磁盘 IOPS 与队列深度、网络吞吐。命令行工具采集即可,采样间隔 1 秒,和压测时间轴对齐。
第四层,时间戳对齐。四层数据来自不同系统,如果没有统一的时间基准,事后根本对不上。压测开始和结束各打一个时间戳标记,后面所有分析都基于这个基准。
4. 结果解读:从单点数字到吞吐曲线
数据齐了,真正的工作才开始。解读的核心思路只有一句:不要看单点,要看曲线和它的形状。
4.1 找拐点:vuser 与吞吐的曲线怎么画
把所有档位的虚拟用户数作为横轴,吞吐作为纵轴,画出来的曲线通常呈现三个阶段:线性增长区、拐点区、平缓或下降区。
线性增长区说明系统还有余量,加并发就加吞吐。这一段曲线的斜率,反映的是"单个并发连接的边际产出",斜率越高说明引擎在这套配置下的并发效率越好。
拐点区最值得研究。拐点出现的位置,往往对应某个资源的饱和:CPU 打满、锁竞争加剧、日志写入跟不上、连接数触顶。找到拐点后,第一件事是去看那个时刻的四层数据,看哪一个先"变脸"。
平缓或下降区是危险信号。吞吐不再增长还能理解,但如果吞吐开始下降、延迟飙升,说明系统进入了拥塞状态,这时候再多加并发只会让情况更糟。生产环境的容量规划,应该把工作点定在拐点之前的那一档,留出余量。
举个具体的读法:某轮测试里,虚拟用户从 32 加到 64,吞吐涨了 40%;从 64 加到 128,吞吐只涨了 3%,同时 95 分位响应时间翻了一倍,CPU 使用率从 70% 跳到 95%。这组数据的解读是:拐点在 64 到 128 之间,系统的有效工作容量大约在 64 个并发连接附近。至于为什么 CPU 先饱和而不是 IO 先饱和,那要看这个库的内存配置和数据集大小——数据集如果能完整装进缓冲池,IO 就不是瓶颈,CPU 会成为第一道墙。
4.2 延迟与资源利用率的三角验证
只靠吞吐排名会误导人,因为两个吞吐相同的系统,用户体验可能天差地别。延迟指标就是用来补这一刀的。
看延迟要看分布,不能只看平均值。平均值会把长尾抹平,而实际业务里最难受的就是那些偶尔冒出来的慢请求。至少要拿到中位数和 95 分位,有条件的话再加 99 分位。
把吞吐、延迟、资源利用率三个维度放在一起看,能区分出四种典型状态:
| 状态特征 | 可能原因 | 下一步动作 |
|---|---|---|
| 吞吐高、延迟低、CPU 接近满 | 引擎效率高,硬件接近上限 | 这是健康状态,记录为工作点 |
| 吞吐停滞、延迟升、CPU 未满 | 锁竞争、日志写入、连接调度等软瓶颈 | 查等待事件,看是哪类等待占主导 |
| 吞吐停滞、延迟升、CPU 满 | 计算资源耗尽 | 考虑加核,或减少每事务的 CPU 开销 |
| 吞吐波动大、延迟长尾明显 | 后台任务干扰(检查点、清理、日志切换) | 调整后台任务节奏,或延长观测窗口 |
这张表能解释掉大部分"结果看不懂"的困惑。很多人只盯着第一列的数字,忽略了后两列,于是一个明显的锁竞争问题被误判成"数据库性能不行"。
4.3 每核效率与扩展性系数
绝对吞吐受硬件规模影响太大,拿一台 64 核的机器和一台 8 核的机器比总吞吐,除了证明前者核多之外没有别的信息量。所以对比表里应该补两个归一化指标。
一个是每核吞吐:用 tpmC 除以实际使用的物理核数,得到的数字反映单位计算资源的产出效率。这个指标对硬件选型特别有用——如果 A 库每核效率比 B 库高 60%,那么在预算固定、核数受限的场景下,A 库的方案可能更划算。
另一个是扩展性系数:虚拟用户从 N 翻倍到 2N 时,吞吐增长的比例。理想线性扩展是 100%,实际能做到 80% 就很不错了。扩展性差的系统,堆硬件的边际收益会迅速衰减,这类系统在大并发场景下的总拥有成本会明显偏高于账面价格。
这两个指标一起看,能避开一个常见误判:某库在小规模测试里每核效率一般,但扩展性很好,规模一大反而反超。如果你的目标场景是几十个并发,小规模测试更有参考价值;如果目标场景是上千并发,那扩展性系数才是关键。
4.4 同一份结果,两种截然相反的结论
这一小节专门讲误读。下面这些场景我都真实遇到过,每一个都能让报告结论反转。
场景一:把 TPM 当 tpmC 上报。数字虚高约 2.2 倍,六个库全部同样虚高,排名不变但绝对值全错。如果这份数据被拿去做容量规划,采购的机器数量会少一半以上。
场景二:仓库数不足导致吞吐被数据量卡死。现象是曲线提前走平、CPU 只用了 50%、延迟温和上升。这时候去调数据库参数是完全白费功夫,因为瓶颈根本不在数据库,而在数据集规模。解法只有一个:加仓库。
场景三:客户端成为瓶颈。现象和场景二几乎一模一样,区别在于客户端机器的 CPU 已经打满。判断方法很简单,压测时单独看一眼客户端资源占用。我建议把客户端监控和数据库监控放在同一块屏幕上,一眼就能分辨。
场景四:持久化配置不对等。一个库关了同步刷盘,一个库保持默认。这种情况下讨论"谁更快"没有任何意义,因为两者承担的持久化代价不同。
场景五:样本太短,抓到了缓存预热期。数据集远大于内存时,前几分钟的读取全部来自磁盘,吞吐低、延迟高;等热数据进了缓存,数字才好看。只跑 3 分钟就取数,等于在测最差的那一段。
场景六:单次结果当定论。存储有波动、后台任务有周期性、网络有抖动,任何单次测试都有偶然性。同一个配置至少跑三轮,取稳定那轮或取中位数,才有说服力。
5. 六库横向对比结果的呈现方式
数据解读完了,怎么呈现给决策者,是另一门手艺。一张把所有数字堆在一起的排名表,看似信息量最大,实际最容易被误用。
5.1 一张能看懂的对比表
下面这张表是我推荐的字段结构。数值部分取自一个本地小规模实验环境(单机、固定核数与内存、本地固态存储、统一关闭日志持久化、统一关闭分区),仅用于演示解读方法,不能作为选型依据,因为规模太小,远未触及各引擎的真实上限。
| 数据库 | 建表加载耗时 | 稳态 NOPM | 换算 tpmC | 每核 tpmC | 95 分位响应时间 | 拐点并发 | 主要等待类型 |
|---|---|---|---|---|---|---|---|
| Oracle | 较长 | 基准值偏上 | 由 NOPM 换算 | 中等偏上 | 较低 | 较高 | 日志写入为主 |
| SQL Server | 中等 | 基准值偏上 | 由 NOPM 换算 | 较高 | 较低 | 中等 | 临时对象争用 |
| DB2 | 中等 | 基准值居中 | 由 NOPM 换算 | 中等 | 中等 | 较高 | 锁等待 |
| MySQL | 较短 | 基准值居中 | 由 NOPM 换算 | 中等 | 中等 | 中等 | 日志刷盘 |
| PostgreSQL | 中等 | 基准值居中 | 由 NOPM 换算 | 中等偏下 | 中等 | 较低 | 后台清理与写入 |
| MariaDB | 较短 | 基准值居中 | 由 NOPM 换算 | 中等 | 中等 | 中等 | 日志刷盘 |
我在表里刻意不填绝对值,原因有两个。第一,具体数字极度依赖硬件、数据规模、参数配置,任何绝对值被引用出去都会被当成普适结论。第二,真正有价值的信息是相对关系和拐点位置,而不是某个库跑了多少。
表里最值得关注的是"拐点并发"这一列。它的含义是"这个引擎在这套环境下从哪个并发量开始不再线性增长",直接对应生产环境的连接池配置建议。一个拐点在 32 的库,你给它配 200 个连接,多出来的 168 个只会在锁队列里排队。
5.2 什么结论能下,什么结论不能下
压测报告的结论部分最考验克制。基于小规模单机测试,能下的结论大致是这几类:
- 在同等硬件与配置下,各引擎的每核处理效率相对关系,以及拐点出现的大致位置。
- 各引擎在本负载模型下的主要瓶颈类型,这决定了后续调优的方向。
- 数据加载和索引构建这类批量操作的耗时量级差异。
- 参数敏感度,即哪些参数调了收益明显、哪些调了几乎没反应。
不能下的结论同样要明说:
- 不能外推到大并发场景。单机 64 连接的结论,跟 8 台机器 1024 连接的表现可能完全不是一回事。
- 不能外推到不同硬件。换一套存储、换一种 CPU 型号,排名可能变化。
- 不能外推到真实业务。TPROC-C 的事务配比是固定的,而真实业务往往是读写混杂、长短事务交织,负载特征差别很大。
- 不能用来评价运维成熟度、生态完整度、许可成本这些非性能因素。选型是综合决策,性能只是其中一票。
我通常会在报告最后一页放一段"本测试不覆盖的范围",把上述四条写清楚。这页看起来是自我限制,实际是保护——它让报告的使用者知道边界在哪里,也让后续如果有人想拿它做更激进的推断时,有个明确的提醒。
6. 常见问题与排查速查表
压测跑不顺的时候,九成的问题集中在建表、加载、加压、结果四个阶段。把下面这些整理成一张表,贴在工位上比翻文档快。
6.1 建表与加载阶段
| 现象 | 常见根因 | 处理方向 |
|---|---|---|
| 建表脚本中途失败 | 连接数上限不够、临时空间不足、磁盘满 | 提前算容量、提高连接上限、清理空间 |
| 表建好了但查询报找不到 | 标识符大小写、模式名不匹配、搜索路径设置 | 统一使用小写标识符,显式指定模式 |
| 加载速度极慢且越来越慢 | 索引在加载过程中实时维护、日志写入量大、检查点太频繁 | 先建表后建索引、临时放宽日志策略、加大日志文件 |
| 加载完成但压测时执行计划很差 | 统计信息未收集或已过期 | 加载后立即收集统计信息 |
| 加载中途连接断开 | 客户端超时设置过短、服务端空闲断开 | 提高超时阈值,检查网络设备会话保持 |
加载阶段我踩过最冤枉的一个坑,是磁盘空间"看着够"但实际不够。操作系统显示的可用空间不包含数据库预分配的日志文件,而日志文件在加载高峰期会快速膨胀,等到写满才报错,前面几个小时的加载全部作废。现在我一定会先把日志文件的最大容量也纳入估算。
6.2 压测执行阶段
| 现象 | 常见根因 | 处理方向 |
|---|---|---|
| 加压到某档直接报连接错误 | 数据库连接上限触顶 | 检查连接上限与当前活跃连接数,留出管理连接余量 |
| 吞吐不涨、CPU 未满 | 仓库数不足、客户端成瓶颈、锁竞争 | 依次排查:算仓库上限、看客户端占用、查等待事件 |
| 吞吐周期性抖动 | 检查点、后台清理、日志切换等周期任务 | 拉长时间轴观察周期,调整任务节奏 |
| 延迟随运行时间缓慢上升 | 版本链堆积、自动清理跟不上、内存碎片 | 检查清理任务是否跟得上事务速率 |
| 明明加了并发,吞吐反而降 | 超过拐点进入拥塞区 | 减少并发,把工作点拉回拐点之前 |
| 两轮相同配置结果差异大 | 缓存状态不同、后台任务相位不同、存储波动 | 每轮前做缓存预热或用固定快照启动 |
关于缓存状态,这里有个实操技巧:如果条件允许,每轮压测前用数据库快照还原,能保证六个库、多轮测试的初始状态完全一致。这一招能把结果波动压缩到很小,代价是每轮多花几分钟还原时间,非常划算。
6.3 结果可信度自查清单
报告交出去之前,我会拿这份清单逐条对一遍。少一条,数据就打个折扣。
- 六个库的持久化配置是否在同一宽松度?调整记录是否完整?
- 分区开关是否统一?字符集、排序规则是否一致?
- 仓库数与实测吞吐是否符合"每仓库不超过约 12.86 tpmC"这条约束?
- 每档的预热时长和稳态观察时长是否达标?
- 客户端资源占用是否已经确认不是瓶颈?
- 报告的吞吐指标用的是 NOPM 还是 TPM?换算关系是否写明?
- 是否给出了延迟分布而不只是平均值?
- 每档是否有完整的四层数据(工具、数据库、操作系统、时间戳)?
- 同一配置是否至少跑了三轮?取的是稳定轮还是最好轮?
- 结论部分是否写明了适用范围和不适用场景?
这张清单里我认为最容易被跳过的是最后一条。写"适用范围"这件事很反直觉,因为它等于主动削弱自己结论的力度。但从工程角度看,一份知道自己边界在哪里的报告,比一份什么都敢下的报告有用得多——前者能被复用,后者一旦被证伪就整份作废。
最后分享一个我在实际操作中的体会:HammerDB 这类工具的价值,不在于它能给出一个"谁最快"的答案,而在于它逼着你把负载模型、参数配置、观测方法这三件事想清楚。真正让一次对比有意义的,从来不是那个最终数字,而是你在跑到这个数字之前,为了让六个引擎站在同一条起跑线上所做的所有对齐工作。这份对齐的功夫,换个工具、换个负载模型,依然用得上。