做数据库性能测试这些年,我最大的感受是:很多人测了个寂寞。不是工具没用对,也不是场景选得不好,而是从头到尾就没分清自己到底要测OLTP还是OLAP,或者干脆把两类场景揉在一起,用一套脚本、一份参数打天下。结果就是,测出来的数据在汇报会上很好看,一上生产就露馅。OLTP和OLAP是两种完全不同的工作负载模型,它们的性能瓶颈、衡量指标、测试方法乃至数据特征都截然不同。这篇文章我就结合自己实际跑过的压测项目,把OLTP和OLAP场景的覆盖策略从头到尾拆一遍,包括场景怎么建模、数据怎么造、工具怎么选、参数怎么调、结果怎么看、坑怎么避,希望能给正在做数据库选型或性能评估的同学一些参考。
1. 先搞清楚OLTP和OLAP的底层差异,否则后面全白做
很多人以为OLTP就是"读多写少"、OLAP就是"复杂查询",这个理解太粗糙了。如果带着这种认知去做性能测试,场景设计必然走偏。我先从工作负载本质说起。
1.1 OLTP场景的本质特征是"短、频、快、准"
OLTP(在线事务处理)的核心特征是大量并发用户同时执行短小精悍的事务。这类事务通常只涉及少量行,走索引,毫秒级返回。典型的操作是"根据主键查一条记录"、"更新某个订单的状态"、"插入一条流水"。在银行核心系统里就是转账扣款,在电商系统里就是下单减库存,在订票系统里就是锁座出票。
这类场景的技术特征非常鲜明:事务提交频繁,每条事务的执行时间极短(通常在几毫秒到几十毫秒),但并发量极大。系统的瓶颈往往不在CPU计算能力上,而在锁竞争、日志刷盘、网络往返、连接管理这些"周边环节"。
做OLTP压测时,我最关注的是这几个指标:TPS(每秒事务数)和QPS(每秒查询数)、事务的响应时间分布(特别是P99和P95)、锁等待和死锁发生率、连接数使用情况。还有一个很容易被忽略的指标是"事务成功率"——在高并发下,有些事务会因为锁超时或连接被拒而失败,这个比例必须在测试报告中明确记录。
1.2 OLAP场景的本质特征是"大、深、慢、重"
OLAP(联机分析处理)则是完全相反的套路。它面对的是海量历史数据,执行的是复杂的分析查询。典型操作包括大范围扫描、多表关联、分组聚合、窗口函数、排序。这类查询动辄扫描几千万甚至上亿行,执行时间从几秒到几分钟不等,但并发量很低,通常只有几个到几十个分析师在同时跑报表。
OLAP场景的瓶颈集中在存储引擎的扫描能力、列式存储的压缩率、聚合计算的效率、内存排序和哈希join的资源消耗上。在传统行式存储数据库里跑OLAP,经常会出现一个查询把CPU跑满、内存吃光,其他查询全部排队的情况。
衡量OLAP性能的核心指标只有一个维度:查询响应时间,以及对应的资源消耗。具体来说就是:给定一个查询集,在特定数据量下,每个查询跑多久,整体跑多久,资源占用是多少。吞吐量不是重点,因为OLAP的并发本来就低。
1.3 为什么不能把两类场景混在一起测
我见过不少团队图省事,把OLTP和OLAP的操作混在同一个压测脚本里,想着"反正都是SQL,一起跑更接近真实"。这个想法在理论上有一点道理——生产环境确实有OLTP和OLAP混合负载。但问题是,混合压测的前提是你已经分别摸清了两类负载的基线性能。
如果一上来就混测,你根本不知道性能瓶颈来自哪一类负载。比如压测结果TPS上不去,你分不清到底是OLTP的锁竞争拖了后腿,还是OLAP的大查询把CPU吃光了。调试的时候无从下手,汇报的时候也无法给出有针对性的优化建议。
我的做法向来是"先分后合":先分别跑纯OLTP和纯OLAP压测,摸清各自的能力边界和瓶颈点,然后再按业务实际比例混合验证。只有这样做出来的混合测试结果,才有业务参考价值。盲目混测除了得到一个看不明白的数字,什么都说明不了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 场景建模:别拍脑袋,要从业务规律反推
场景建得准不准,直接决定测试结果有没有参考价值。我见过太多人做压测,脚本里就一条SQL,十条并发,跑完就出报告。这种压测如果线上业务真的那么简单,我也不用花这么多篇幅写这篇文章了。
2.1 从业务日志和监控数据反向提取场景比例
做场景建模时,我第一步不是写脚本,而是去看生产环境的监控数据。主要看三类东西:数据库慢查询日志、全量SQL审计日志、应用层的调用链追踪数据。通过分析这些数据,可以得出三个关键信息:核心SQL的分布(哪些SQL占了绝大多数请求)、读写比例、事务的复杂度构成。
举个例子,我之前做过一个电商系统的压测项目。通过分析调用链数据,发现核心链路的请求分布大致是:商品浏览占45%,购物车操作占15%,下单占10%,支付回调占8%,订单查询占12%,其他占10%。这个比例最终直接映射到了压测脚本里的事务权重分配上。
还有一个很关键的点:不要把压测场景设计成"平均分布"。真实业务永远是20%的操作占据80%的流量,比如热点商品、热点账号、热点库存。压测数据里必须构造这种热点倾斜,否则测出来的结果会被平均效应掩盖,一旦上线遇到热点场景,系统直接就崩了。
2.2 OLTP场景建模的完整步骤
标准的OLTP场景建模,我一般按照这五个步骤走:
- 梳理核心业务链路:画出业务的主干路径——从用户发起请求到数据库操作完成,中间经过哪些表、哪些SQL、哪些事务边界。
- 确定事务组成:每一个业务动作(比如"下单")拆成一个事务,包含多条SQL。事务要按业务逻辑包裹,不能把每条SQL当成独立事务,否则测不出事务提交开销。
- 分配权重比例:根据监控数据,确定每个事务在总流量中的占比,写进压测工具的配比配置里。
- 设计数据特征:数据总量、数据分布、索引命中率、热点数据比例,都要按生产环境来。
- 设置并发模型:用户数、到达率、思考时间,要贴合业务实际。电商秒杀和后台管理系统的并发模型完全是两码事。
这里要特别强调一下"用户数与并发数"的换算。1000个在线用户不等于1000个并发线程。正常业务用户的思考时间(比如浏览商品时花5秒看页面)会让实际数据库并发远低于在线用户数。如果没有思考时间,压测线程全部疯狂打数据库,那是在测极限压力,不是测真实场景。两种测法都有意义,但务必要分清哪个是哪个。
2.3 OLAP场景建模时如何设计查询集
OLAP场景建模和OLTP完全不同。OLTP建模的核心是"比例"和"并发",OLAP建模的核心是"查询集"和"数据规模"。
我在做OLAP压测时,不会自己去编SQL,而是从生产环境的报表系统、BI系统里抓取真实的分析查询语句。把这些SQL按执行频率和耗时分组,选出最具代表性的20到30条作为压测查询集。这些查询要覆盖几个维度:大范围扫描、多表关联、多层子查询、窗口函数、复杂聚合、排序分页。
数据规模方面,OLAP压测的数据量至少要达到生产环境下最大表未来一年增长量的规模,否则很多性能问题根本暴露不出来。比如生产最大表现在有1亿行,你要按年增50%来算,压测表至少要有1.5亿行。原因很简单——OLAP查询的优化器会基于统计信息选执行计划,数据量不同,执行计划可能完全不同,性能差异能达到数量级。
我踩过一个很深的坑:在测试环境只有5000万行数据的表上做OLAP压测,结果一切正常,查询都是秒回。上线后发现生产环境的数据量是测试环境的8倍,同一个查询跑了3分钟没出来。原因就是数据量变大后,优化器放弃了索引跳跃扫描,选择了全表扫描加哈希关联。
2.4 补充场景:用Elasticsearch实现OLAP分析
聊到OLAP场景,就绕不开一个热词:Elasticsearch实现OLAP。很多团队在做日志分析、指标监控、用户行为分析时,会用Elasticsearch作为OLAP引擎。Elasticsearch的聚合框架确实非常适合做多维分析,尤其在做时间范围过滤、terms聚合、直方图分桶这类操作时,性能非常亮眼。它之所以在OLAP场景中屡屡被采用,核心优势在于倒排索引配合列式存储Doc Values,能在海量文档上快速完成过滤和聚合,不需要像传统数仓那样构建复杂的预聚合模型。
但注意,ES是OLAP场景的一种实现选择,不是万能替代品。我在压测ES的OLAP能力时,会重点覆盖以下几类查询:时间范围过滤加group by(最常见的大盘监控查询)、多条件过滤加terms分桶(比如按区域、按渠道统计用户数)、父子文档关联查询(这类在ES里性能比较敏感)、大数据量下的排序分页。ES在聚合上的性能优势比较明显,但在高频更新、事务一致性要求高的场景里并不合适,所以做ES的OLAP压测前,一定要先确认业务场景匹配。
3. 压测数据准备:细节决定成败
数据准备是性能测试里最枯燥但最要命的环节。数据造得不符合生产特征,后面的测试结论全是废纸。我在这部分翻过车,所以多说几句。
3.1 数据量和数据分布必须贴合生产
首先是数据量级。OLTP场景需要的数据量至少要覆盖生产环境核心表的数据规模,比如生产订单表有5000万行,压测库至少也要有5000万行。否则索引的效果、缓冲池的命中率、优化器的执行计划选择都会失真。
其次是数据分布。生产数据的分布通常是不均匀的,比如用户表里80%的流量来自20%的活跃用户,订单表里商品维度的数据有明显的长尾和热点。造数据的时候要刻意制造这种倾斜,不能搞平均主义。用自增主键顺序插入,索引B+树的填充率和真实场景差异很大,压测结果会偏向乐观。
第三是数据新鲜度。OLTP场景中,热数据通常是最新产生的数据。压测时要把数据分成"历史冷数据"和"近期热数据",让查询集中在热数据范围内,这更贴合真实业务。
3.2 造数据的几个实用技巧
造数工具方面,我常用的是两类:通用造数工具和SQL脚本。通用工具适合批量生成结构化测试数据,可以自定义字段类型、值域范围、分布规律。SQL脚本适合生成业务规则复杂的关联数据。
造数时有几个容易被忽略的细节:
- 唯一键冲突问题:多线程并发造数时,幂等性设计不好极易触发唯一键冲突,我习惯用"线程编号+序列号"的方式生成主键,天然规避冲突。
- 外键一致性:如果压测SQL里有JOIN场景,子表的外键必须能关联上主表数据,造数时要用同一套维度数据去生成,不能让子表和主表各造各的。
- 索引统计信息更新:数据造完后,一定要重新收集表的统计信息。我在一次MySQL压测里就吃过亏——数据灌了一亿行,忘了分析表,优化器按旧统计信息选择了全表扫描,压测结果一塌糊涂,还排查了大半天。
- 数据均匀落盘:顺序插入会导致数据物理存储集中,测试时热点块竞争严重。可以适当打乱插入顺序,让数据更均匀地分散在存储上。
OLAP场景的数据准备有一个不同的地方:需要额外构造数据版本。数仓的分析数据往往带时间分区,压测时要模拟出跨多个月甚至跨年的分区数据。我建议按"日期分区+数据追加"的方式设计压测数据生成脚本,让压测数据可以分批次灌入,模拟生产环境持续增长的数据态势。
3.3 压测环境隔离和数据清理
压测环境一定要和开发测试环境隔离。我见过不止一次,压测跑了一半,开发同事在同一个库执行了一个大表DDL,直接把压测数据弄崩溃了。更稳妥的做法是用独立的数据库实例,至少也要用独立的schema或独立表空间。
压测过程中,数据库会产生大量binlog、redo日志和临时文件,压完一轮后务必清理干净。如果是MySQL,检查binlog目录是否撑爆磁盘;如果是ES,注意压测产生的索引分片、segment merge操作对磁盘的占用。压完一轮换个批次时,该清库的清库,该重建索引的重建索引,不要图省事在脏数据基础上继续跑。
4. 工具选型与压测参数设计
工具选得好不好,直接影响测试的效率和可信度。我不太迷信"某个工具一定最好"的说法,关键是匹配场景。下面按OLTP和OLAP分开说。
4.1 OLTP压测工具:sysbench、HammerDB还是JMeter
OLTP压测工具我主要用三款:sysbench、HammerDB、JMeter。
sysbench是我最常用的,因为它轻量、灵活、脚本可控,内置了oltp_read_write、oltp_point_select、oltp_insert等常用测试模式。它的Lua脚本机制很强大,你可以自定义事务逻辑,模拟真实业务的SQL序列。我一般用sysbench跑基准测试和对比测试,比如数据库版本升级前后的性能对比、不同参数配置的优化效果验证。
HammerDB更适合做数据库的标准化TPC-C测试。它内置了完整的TPC-C业务模型:仓库、商品、库存、订单等表结构,以及新订单、支付、发货等标准事务。如果你要跟行业基准数据做对比,或者评估数据库的联机事务处理天花板,HammerDB的TPC-C模式是最合适的。缺点是比较重,配置复杂,而且自定义程度不高。
JMeter适合做协议层和应用层的压测。比如你的压测目标是经历完整的应用链路(HTTP接口到连接池再到数据库),JMeter可以模拟真实用户请求。但它测的是应用的整体表现,链路里网络开销、应用代码开销都算进去了。如果只关心数据库自身性能,JMeter不是最优选择,直接用sysbench打得更准。
有些团队会用企业级压测工具自带的事务模型,比如商业数据库厂商的测试套件,这些在特定数据库上有优化适配,没有特殊要求的话,用开源工具足够。
4.2 OLAP压测工具:TPC-H、TPC-DS和自定义查询集
OLAP压测的标准化工具是TPC-H和TPC-DS。TPC-H面向的是决策支持类查询,包含8张业务表,22条分析SQL,覆盖了多表关联、聚合、排序、子查询等典型操作。TPC-DS则是更复杂的版本,包含25张表、99条SQL,模拟了更真实的决策支持工作负载,更适合数据仓库类数据库的压测。
但实际业务跟标准模型往往有差异,所以我通常的做法是:先用TPC-H或TPC-DS测出数据库的基础分析能力,再叠加一组从生产环境抽取的真实业务查询,形成"标准集+业务集"的组合测试方案。标准集用来横向对比,业务集用来验证真实场景。
跑OLAP压测还绕不开一个工作:EXPLAIN分析。每一条压测SQL,都要先跑一遍EXPLAIN,记录执行计划、扫描行数、使用的索引、join类型等关键信息。这一步不可跳过,因为后续做性能分析时,你要知道每条SQL的执行计划长什么样,才能判断压测结果异常是SQL本身的问题还是数据库参数的问题。
4.3 时间线场景模拟:不只是并发和耗时
除了常规的并发压力测试,我强烈建议在OLTP压测中加入时间线场景模拟。真实生产环境的负载不是恒定不变的,它有波峰波谷,有突发流量。我之前在某电商公司做过一次大促压测,用的就是时间线模拟:压测脚本里在前10分钟保持低频请求模拟日常流量,然后在第11分钟突然把并发拉到峰值的5倍,持续5分钟模拟大促秒杀,之后逐步回落到正常水平,最后再拉高一次模拟活动返场。
这种时间线模拟能测出常规恒定并发测不出来的问题:比如连接池的连接风暴、慢查询积压、缓存击穿、限流策略生效后的排队情况。做这种模拟时,压测工具需要支持阶梯加压和实时并发调整,sysbench可以通过脚本配合外部控制实现,JMeter可以配置定时器实现,更专业的可以用分布式压测平台的调度能力。
4.4 关键参数设计与注意细节
不管用什么工具,OLTP压测有四个参数必须仔细设计:
- 并发线程数:不要只测一个固定值。我通常从50并发开始,按50的梯度逐级往上加,直到系统的TPS不再上升或者错误率超过阈值,找到拐点。这个拐点就是系统的能力上限。很多团队喜欢只测一个"看起来合理"的并发值,那会漏掉系统的真实瓶颈位置。
- 测试时长:单轮压测不能太短。我至少跑30分钟,其中预热阶段5分钟,稳定阶段20分钟以上,恢复阶段5分钟。时间太短,InnoDB缓冲池还没预热完毕,慢查询还没完全暴露,得不出可靠结论。
- 预热策略:正式压测前,先跑一小段低并发的请求让数据库缓冲池充分预热,否则前几分钟的数据完全是"冷启动"表现,不代表稳态性能。
- 采集粒度:监控数据的采集间隔建议不超过5秒,压测工具的TPS统计间隔同理。如果采样粒度是1分钟,拐点附近的细节全部丢失了。
OLAP压测的参数设计重点则在查询并发和超时时间上。OLAP并发一般控制在1、2、5、10这样的小并发梯度,因为生产环境分析查询的并发本身就不高。每条SQL的超时时间要单独设置,一般是该SQL生产环境执行时间的5倍以上。超时设置太短会把慢查询杀掉,测不出真实瓶颈。
5. 压测执行与结果分析方法
测试执行看着简单,脚本一跑就完事。但想得到可靠结论,执行过程中的细节控必不可少。
5.1 我执行压测时的标准流程
我在压测执行阶段保持一套固化的流程:
- 基线确认:正式压测前,先确认数据库版本、参数配置、硬件环境、压测工具版本,全部记录在案。这步看似基础,但在多次压测数据对比时,版本不一致会导致结论完全无法对比。
- 预热:用低并发预热5到10分钟,确认数据库各项指标正常后进入正式压测。
- 梯度加压:按预定梯度拉升并发,每个梯度维持3到5分钟。保证每个并发档位下的系统指标都进入稳定状态再做记录,避免把瞬时的指标波动当成稳态数据。
- 持续稳定压测:在目标并发下持续运行20到30分钟,这段时间是整个压测最关键的。很多性能问题需要运行一段时间后才会暴露——内存缓慢增长、连接泄漏、临时表磁盘溢出、慢查询积压,这些都要时间积累。
- 回放与恢复:压测结束后,不要立刻关掉监控。观察5到10分钟,记录系统恢复到正常水平的耗时,这个指标用于评估系统的自愈能力和资源释放效率。
- 数据归档:每一轮压测的监控数据、压测工具输出、数据库日志、配置信息全部归档,作为后续分析的原始依据。
5.2 OLTP压测结果怎么看:不要只盯TPS
DLTP压测结果出来后,第一个要看的指标是TPS没错,但不能只看TPS。我发现很多同学拿到压测报告,首先问"TPS多少"——这个思维框架太窄了。
TPS必须配合响应时间分位数一起看。举个例子:系统A的TPS是5000,P99是50毫秒;系统B的TPS是4500,P99是20毫秒。单看TPS,A更好;但如果生产环境的业务对响应时间要求高,比如核心交易链路P99不能超过30毫秒,那A其实是不可用的。
除了TPS和响应时间,OLTP压测必须关注这几个方面:
- 错误率:连接超时、锁等待超时、死锁等错误的数量和占比。任何非零错误率都要分析原因,不能拿"没事,就几个失败"敷衍过去。
- 连接池状态:活跃连接数和空闲连接数。如果在高并发下,活跃连接数长期占满连接池上限,说明连接池需要扩容或数据库的连接处理能力是瓶颈。
- 锁等待和死锁:如果压测过程中锁等待次数暴涨,说明事务间的冲突严重。事务冲突在真实业务中也存在,但压测中如果比例远高于生产,要回头检查压测数据是否有问题,是不是热点数据的倾斜度设置得过度了。
- InnoDB缓冲池命中率:命中率过低说明数据量超出了缓冲池容量,或者压测数据的访问分布与生产不符,需要结合实际情况判断。
压测过程中我还会顺手记录一个容易被忽视的指标:单条SQL的平均扫描行数和返回行数。这个数据能判断SQL的索引使用情况是否正常。如果扫描行数远大于返回行数,说明SQL存在索引失效的风险,压测得到的高性能可能是数据量不够大导致的假象。
5.3 OLAP压测结果怎么分析:执行计划优先
OLAP压测结果的分析思路完全不同。拿到查询耗时后,不要急着下结论,先去查每一条慢查询的执行计划,判断查询性能是由什么决定的。
具体分析路径我总结为四步:
- 看执行计划:查询是否走了正确的索引、join顺序是否合理、是否存在全表扫描、扫描行数是否在预期范围内。
- 看资源消耗:查询执行期间CPU、内存、磁盘IO的消耗情况。判断是计算密集型(CPU打满)还是IO密集型(磁盘等待时间长)。
- 看数据特征:查询涉及的数据量、聚合基数、排序数据量。如果排序的数据量超过内存排序缓冲区,触发了磁盘排序,性能断崖式下跌,这种情况通常不是数据库调优能解决的,要从SQL改写或预聚合策略入手。
- 看并发影响:多个OLAP查询并发执行时,相互之间的资源争抢是否严重,是否有查询把系统资源占满导致其他所有查询排队。
为了排查更深层的瓶颈,我还会再看一组系统级指标:磁盘IOPS队列长度、NIC流量、swap使用率。很多OLAP性能问题其实出在数据落盘或网络传输上,而不是数据库引擎本身的计算能力。有些查询在SSD上跑得飞快,换成机械盘就凉了——这个信息在硬件的选型决策里价值巨大。
6. 常见问题与排查技巧实录
压测做得多了,你自然会发现有些问题反复出现。我把高频问题整理成一个速查表,方便大家在实际操作中对照。
| 现象 | 可能原因 | 排查思路 | 预防手段 |
|---|---|---|---|
| TPS上不去,CPU利用率低 | 连接数不够,请求在排队;锁等待严重 | 查活跃连接数、锁等待监控、线程状态 | 压测前置加大max_connections,排查慢事务持有锁的情况 |
| 压测刚开始性能很好,5分钟后断崖下跌 | InnoDB缓冲池未预热结束,或慢SQL开始堆积 | 检查缓冲池命中率、慢查询日志时间点 | 增长预热时间,对比压测不同阶段的缓冲池命中率 |
| 查询响应时间P99暴涨,但P50很低 | 少数热点键争抢严重,或有长尾慢查询拖累 | 分析响应时间分布、定位慢查询 | 压测数据制造热点前控制倾斜度,监控长事务并分析 |
| 压测进程报连接超时 | 数据库连接数达到上限,连接队列溢出 | 查连接数使用率、错误日志、应用连接池配置 | 压测前按预估并发规划连接池和数据库并发参数 |
| OLAP查询第一次跑很慢,第二次变快 | 数据页缓存到了内存,或结果集被缓存 | 对比冷热缓存下的执行时间 | 明确压测目标,冷缓存压测代表最坏情况,热缓存压测代表常态效率 |
| ES聚合查询超时 | 分桶数量过多,内存压力大,GC频繁 | 查看ES监控的GC频率、聚合内存使用 | 优化聚合精度,考虑分桶裁剪、近似聚合,或扩容节点 |
| 压测机上CPU已经100%,数据库还非常空闲 | 压测机自身成为瓶颈 | 查看压测机的CPU、内存、网络开销 | 使用分布式压测模式,多台压测机共同施压 |
除了这个速查表,我再说一个排查过程中的经验:永远保留现场。压测出问题时,不要马上关掉业务、停掉压测工具去"看看情况"。你就让现场维持着,先把数据库的processlist、监控曲线、日志这些快照收集起来,再决定下一步动作。很多性能问题的根因,只有在现场存续的时候才能查出来,一旦现场被破坏,线索就断了。
还有一个常被忽略的排查点:数据库的线程栈。有一次MySQL压测出现整体卡顿,从监控曲线看不出明显异常,连接数正常、CPU不高、IO不高。最后通过pstack抓了mysqld的线程栈,发现大量线程卡在同一个mutex上,定位到是某个版本的redo log写入竞争问题。换了个小版本之后,问题直接消失。这条经验说明,压测遇到诡异问题时,工具链不能停留在SQL层面,系统级、甚至数据库源码层面的排查手段也要掌握。
最后说说我做完一次大型压测之后必做的一件事:写压测报告时会附上环境版本和配置快照。多次压测数据对比时,版本不一致会导致结论完全无法对比。我曾经在不同小版本的MySQL上测出过20%以上的并发性能差异,差点误导了数据库选型决策。把环境信息记录清楚,是对测试结果负责,也是对自己负责。
我个人在实际操作中的体会是,数据库性能测试这项工作,真正的功力不在工具使用上,而在你对业务负载的理解有多深。OLTP和OLAP的场景覆盖策略,本质上是在回答一个问题:你的系统在真实的业务压力下,能不能扛住,能扛多久,瓶颈在哪里。把这个问题的答案用数据清晰地讲出来,比用一个华丽的TPS数字去汇报有价值得多。
