☰
ABAP性能分析实战:从SQL跟踪到优化落地
2026/10/10 4:47:13 网站建设 项目流程

前一阵子某公司交付的采购报表上线没两天,客户就打电话来说“系统卡死了”。我上去一看,一个查询库存金额的报表,数据量只有几万条主数据,跑完却要将近三分钟。更离谱的是,同一个查询在开发环境只要三十秒。这种“环境一变就变慢”的问题,十次里有八次不是带宽问题,而是SQL行为和程序逻辑在真实数据量下彻底暴露了原形。我把整个排查过程整理成了一套标准打法,正好借这篇“ABAP 性能分析实战”,把思路和工具整体串一遍。

这篇内容面向两类人:一类刚接触SAP开发,对SE30、ST05这些事务码还停留在“听说过”层面的初级顾问;另一类是已经被性能问题折磨过、手里有工具却不知道先按哪个键的开发者。文章会讲清楚怎么看耗时、怎么用跟踪工具锁死罪魁祸首、怎么用FOR ALL ENTRIES和索引这类常规手段做优化,同时会把我在生产环境里踩过的坑一并交代出来。

1. 先把性能问题看明白:现象、指标与根因

1.1 用户说“慢”,到底是哪里慢

接到性能问题工单,第一件事不是打开调试器,而是先把“慢”这个模糊概念拆开。用户嘴里的“慢”至少包含三种完全不同的情况:第一种是报表执行本身慢,点完执行按钮到画面出结果要很久;第二种是画面响应慢,操作查询、双击明细、点下一页都像在泥里行走;第三种是后台作业慢,比如夜间批量跑批,平时两小时跑完,最近变成四小时。

这三种情况的排查方向差别很大。报表执行慢大概率是SQL或程序逻辑问题;画面响应慢要怀疑屏幕逻辑、ALV刷新方式、以及是否有不该有的同步调用;后台作业慢则要结合批处理的特征去查,比如主键冲突、锁等待、大数据量累积后又没有归档。如果一开始就抱着“反正都是性能,先把代码拉出来看一遍”的想法,很可能会花几个小时改了一堆无关代码,问题却原封不动。

判断慢在哪里,我会先用系统自身的仪表盘数据做一轮快速体检。对于在线事务,用事务码 STAD 能看到某个用户的对话步骤(Dialog Step)耗时细节,能区分是数据库时间、加载时间还是CPU时间占了大头。对于整个系统层面的慢,ST03N 可以按日期、时段、应用类型查看平均响应时间变化。先把“慢”定位到具体维度,后面跟踪工具才会用对地方。

1.2 根因归档:百分之八十的问题集中在三类

在我做过的性能分析里,最终定位出的根因绝大多数跑不出下面三类。

第一类是数据库访问方式有问题。典型特征包括:循环体内逐条执行SELECT SINGLE,明明是几千条数据却产生了上万次数据库往返;查询条件没有走索引,导致全表扫描;SELECT * 把不需要的字段全部捞出来,数据量翻了好几倍;还有FOR ALL ENTRIES用的表为空却没做保护,一执行就把全表数据拉下来。这类问题的共同点是:程序的CPU开销其实不大,但数据库时间和网络传输时间拖垮了整体响应。

第二类是ABAP程序内部逻辑低效。典型特征是内表操作没有用好ABAP的运行机制,比如应该用二分查找的地方却在做线性扫描;LOOP嵌套LOOP而且内层还在处理大内表;对超大内表频繁INSERT、DELETE,造成内存重分配开销。这类问题在数据量小的时候完全看不出来,一旦数据量上到十万级别,运行时间会呈现非线性暴涨。

第三类是外部交互和资源等待。比如同步调用外部接口,而对方接口处理超时;比如更新锁没有及时释放,导致后续请求排队;比如数据量大时锁等待导致后台作业互相阻塞。这类问题不会直接表现在某一支SQL上,它需要结合事务跟踪和时间曲线去判断。

把根因归档的好处在于,分析工具能有的放矢。如果你想都不想就开始改代码,很容易把性能问题做成“薛定谔的优化”——看着像优化了,线上还是慢。

2. 工具选型:先搞清楚每个仪器是测什么的

2.1 常用性能分析事务码一览

ABAP开发环境并不缺少性能分析工具,缺的是对工具适用场景的明确认知。我把平时用到的工具整理成一张表,方便照着用。

事务码工具名称核心用途适用场景
SE30ABAP运行时分析单程序/事务的耗时分布定位某支ABAP程序的内部热点
SATABAP跟踪分析SE30的升级版,分析树更友好细致分析单事务各个ABAP语句耗时
ST05SQL跟踪捕获数据库访问与表操作查出特定程序发出的所有SQL及其耗时
STAD工作负载统计(单步骤)单个对话步骤的时间分解判断耗时是数据库还是CPU
ST03N工作负载分析系统/时段级响应时间趋势观察性能是偶发还是持续劣化
ST04/DBACOCKPIT数据库监控查看缓冲命中率、数据库活动判断数据库层是否正常
ST22短转储分析记录程序异常终止遇到ABAP dump优先看这里
调试器(SE80/SE24中启动)逐步查看变量与执行路径排查逻辑错误,不专门用于性能

需要特别说明,SE30 和 SAT 在功能上是同一族工具,SE30 是老版本,SAT 是后续推出的新界面。新版本里很多团队直接推SAT,但项目上还有些旧系统只有SE30可用,所以两个都值得掌握。我不会说“必须用某一种”,工具是死的,能定位问题的就是好工具。

2.2 按场景选工具的实战思路

根据问题形态选择工具,比把工具全部跑一遍要高效得多。

如果问题是一个业务报表或事务执行慢,而且能明确复现,首选SAT或SE30。它们能告诉你程序内部哪一行语句消耗最多。这里我要给一个经验:不要一上来就采集完整跟踪,先把问题缩小到某个功能范围,能只分析一个事务或一个功能模块就只分析这一块,否则分析树会大到你找不到关键路径。

如果是怀疑SQL慢、数据库访问多,直接挂ST05。ST05能列出所有SQL语句,包括Open SQL和Native SQL,还能看到每条语句的缓冲标志、返回行数、执行时间,这是定位“循环内查询”这类问题的利器。

如果是系统整体慢、不是单个程序慢,则先去ST03N看趋势。比如恰好是每天下午三点慢,那很可能是某个定期作业或特定业务时段集中导致的资源争抢,你需要看时间曲线而不是单个程序。

还有一类问题值得提醒:当程序报了ABAP短转储(比如嵌套循环次数过多、内存不足),不要先去性能分析,而是先看ST22。短转储信息里通常直接写明了出错语句和异常类,很多内存类和“动态循环次数过多”的问题一眼就能看出来。

2.3 我为什么通常从ST05或SAT下手

刚入行那会儿,我拿到性能问题第一反应是上SE30,但真正跑完发现分析报告里几百条语句,一时间分不清主次。后来总结下来,除非你明确知道是屏幕逻辑卡顿,否则我的默认顺序是:能判断“慢在数据库”的属性,就先用ST05过滤出问题场景;如果SQL层面看不出问题,再用SAT去看ABAP层的耗时分布。这个顺序能够避免被大量正常且快速的SQL干扰视线。

第二个原因在于,ST05的输出非常直观。它会捕获所有数据库操作,你可以按总耗时排序,最慢的几条SQL一眼看到底。多数情况下,优化一条耗时巨大的SQL,比优化一百条微不足道的语句有效得多。

简单说,先确认瓶颈所在层(数据库层还是ABAP层),再决定用什么工具深挖。这个思路适用于绝大多数情况,少走弯路。

3. 一次完整性能分析实操:从复现到优化

3.1 先把复现环境准备好

后端问题分析最忌讳在“半真实”的环境里测试。同一个程序,在开发机、质量机和生产机的数据量完全不同,你很可能在开发机上跑出来性能优秀,上了生产就严重劣化。所以我的建议是,如果生产环境允许且系统不是特别繁忙,尽量在生产或贴近生产数据量的测试环境做跟踪,并且选择一个业务影响最小的时段。

具体到ST05的操作步骤:先在ST05界面勾选 General 和 SQL Trace,激活跟踪,然后跳去执行目标程序或事务,执行完成后回到ST05停止跟踪,最后查看跟踪列表。如果你把跟踪点放得太宽,整个事务对几十个程序同时发生的话,捕获的数据会很杂。我会先跟用户确认,进入事务后只做核心动作:点查询、等结果、最多翻一两页,就退出。

这里有一个我在生产环境吃过亏的细节:跟踪期间会给系统带来额外开销,慢的程序会变得更慢,所以不要在高峰期对大规模批量作业做完整跟踪,尽量选空闲时段或者只跟踪一个对话步骤。

3.2 从SQL跟踪结果里揪出“循环内查询”

回到开头说的那个库存金额报表,客户反馈执行要三分钟。我用ST05做了跟踪后,导出跟踪列表,按“执行时间”排序,看到有一类SQL语句被重复执行了上万次:每次都是对同一张物料表按物料号查询。典型代码如下:

LOOP AT lt_result INTO ls_result. SELECT SINGLE matnr FROM mara INTO ls_mara-matnr WHERE matnr = ls_result-matnr. ... ENDLOOP.

问题一眼就看穿了:内表 lt_result 有大约8000条数据,程序就在循环内执行8000次SELECT SINGLE。虽然单次SELECT很快,但累积起来的数据库往返耗时非常可观。打印出统计信息时,这8000次的数据库访问时间加起来接近两分钟,占了总耗时的八成。

这类问题的标准解法是用FOR ALL ENTRIES批量查询。改法很简单:

IF lt_result[] IS NOT INITIAL. SELECT matnr ... FROM mara INTO TABLE lt_mara FOR ALL ENTRIES IN lt_result WHERE matnr = lt_result-matnr. ENDIF.

FOR ALL ENTRIES 的本质是把条件拼接成一个IN列表交给数据库一次处理,数据库往返次数从几千次骤降到个位数。但这个语法有几个反直觉的坑,我在后面的问题速查里会专门说,这里先记住一个原则:使用前必须判断内表是否为空,否则运行时它会生成一个没有约束条件的查询,直接拖动全表。

3.3 用SAT继续深挖ABAP层热点

有些场景,比如SQL本身没问题,但是程序运行还是慢,这时候就要把视角放到ABAP语句层。我用SAT做过一次服务单分析,过程可以作为参考。在SAT初始界面创建一个新的分析变式,指定要分析的事务或程序,勾选需要的跟踪粒度。启动分析后,程序跑完会自动生成一个分析结果树,双击每个节点都能看到对应源码及累计时间、调用次数。

我习惯先把分析树按“累计时间”降序排列,然后逐层展开,重点看两类数据:一是哪些ABAP语句累计耗时最高,二是在耗时高的语句里,数据库时间、CPU时间、系统管理时间各占多少。有一次我发现一个报表的瓶颈完全不在SQL,而在内表排序:有个内表没有按字段建排序表,程序在后面反复用线性查找(普通READ TABLE不加二分查找),10万行数据逐行读过去,代码看着不复杂,时间全耗在扫描上。

优化手段也不复杂:要么在内表初始定义时声明为 SORTED TABLE,这样自动按主键二分;要么在使用高频读取前,先用SORT语句按查找字段排好序,再在READ TABLE时加 BINARY SEARCH 参数。改完之后同样场景的执行时间从8秒降到0.4秒,可以说非常典型。

3.4 优化实施:从“定位”到“看效果”

做优化不要一次性改完以后不测试。我的做法是先明确当前基线,比如同一个查询在测试环境执行当前耗时3分钟、数据库时间120秒、返回记录数8000条,改完这个点之后重新测同一场景,最好连跟踪文件和执行统计一起重新跑一遍,对比数字变化。

现在的SAP系统可以很方便地在报表或函数内部打开系统负载统计(System Load),或者直接在调试器的“系统”菜单查看当前请求的数据库时间。如果你改的是报表类程序,还可以用SE30或SAT分别录一段“优化前”和“优化后”的对比。优化后数字如果确实降下来了,再把变更走测试发布流程。这种可量化对比不仅让你心里有底,汇报给业务用户时也更有说服力。

我自己的经历是,很多优化在改动后反而第一次跑没看出明显差异。原因多半不是优化没用,而是没有重启应用服务器或者使用了旧缓冲。尤其涉及表和视图改动时,要记得同步考虑系统缓冲刷新,否则测试结果会误导你。

4. 高发问题与排查经验速查

4.1 那些高频出现的“性能陷阱”

性能问题看多了,你会发现各种业务场景千奇百怪,但代码级问题就那么几个。

陷阱一:SELECT *。很多程序习惯性地把所有字段都查出来,尤其开发刚开始时图省事。实际业务只需要两三个字段,却把整行数据都拉进内存,传输数据量呈几何级增长。纠正办法是只选需要的字段,并且尽量用内联声明配合数据库层的行与列裁剪。要理解一点:SELECT * 在某些极端情况下(比如只取一条记录)可以接受,但只要是大数据量,就是性能隐患。

陷阱二:循环内访问数据库。我前面说过这类问题,它可以细分为循环内SELECT SINGLE、循环内UPDATE/DELETE。单看每条语句都不起眼,累计起来就是灾难。批量处理的基础认知是:能用一条SQL为一批数据处理,就不要用N条SQL处理N条数据。用MODIFY、UPDATE在FOR ALL ENTRIES基础上做批量更新,往往能将数据库交互次数降低几个数量级。

陷阱三:内表查找没有排序和二分。ABAP内表如果按顺序查找,复杂度是O(N),数据量到十万级别就会明显变慢。用SORTED TABLE或者BINARY SEARCH可以压到O(log N)。有些老代码从性能角度来讲属于“能用但是不能扛量”,一换大数据场景立刻露馅。

陷阱四:执行计划被陈旧统计信息误导。这是个隐蔽问题:明明代码没问题,运行时数据库却选择了差的全表扫描路径。很多项目只在数据变化巨大的情况下才去刷新数据库统计信息,平时根本没人盯这个。排查时除了看SQL文本,有条件的话去数据库层看执行计划(比如HANA的PlanViz,或者传统数据库的EXPLAIN)。这通常需要权限,没有权限时可以先看报表耗时是否呈增长趋势,辅助判断统计信息是否老化。

陷阱五:锁等待。这个和前面几个不太一样,它不会一直慢,而是“偶尔慢一下”。如果会话分析反复发现多条语句在等锁,那就要去查锁对象的持有者。有时候是用户开了GUI没退出导致更新锁一直挂着,定期清理会话会缓解一大半。

4.2 排查过程里那些“不写进文档”的心得

第一,复现问题时尽量用小数据尝试。如果你能构造一个几千行的测试场景把问题放大,就不要直接在生产几百万行数据上反复试。我在一次测试中为了让问题更明显,特意做了个只有200行的测试程序,竟然也能把几分钟的性能问题在几秒内复现出来,这让后续定位速度快了很多。

第二,注意看“总时间”的构成。同样是执行时间5秒,可能是某一条SQL耗时4.9秒,也可能是100条SQL各耗时0.05秒。前者要优化SQL本身,后者要优化循环或批量策略。用ST05拿到执行时间后,把前N条SQL列出来,基本就能判断属于哪一种。

第三,开跟踪时给自己留“足够的行为样本”但不要太多。我习惯把一个完整业务流程拆成最小可执行步数:比如“打开报表-输条件-执行-查看第一屏”,每一步做一遍就退出。多了容易在跟踪结果里掺杂无关SQL,少了可能抓不到关键语句。

第四,性能分析是带验证条件的,要有耐心。最常见的问题是,你按经验改了几处代码,结果重新运行发现还慢,然后开始怀疑工具。实际上,有时候问题就藏在“你以为不是问题”的那一小段里,比如程序里某个对ALV单元格格式做处理的子例程,每次刷新都触发,看着不起眼,刷新次数一多就成了热点。用SAT的“调用次数”再排一次序,往往能看到这类隐藏热点。

4.3 优化武器库:从数据库层到程序层的调整项

做优化时可以考虑的顺序是:先低成本高收益,再侵入性较强的手段。

数据库层面的第一选项是索引。查询条件字段在表上缺少合适索引时,数据库只能全表扫描。建立合适的二级索引,很多慢查询可以立竿见影地提速。但索引不是越多越好,每张索引都会影响写入、占空间,所以我会建议先看最慢的几条SQL,只对确实高频且选择性好的字段建索引。

第二个选项是裁剪数据量和字段。SELECT之后记住只取需要的列,WHERE条件尽量用索引字段,分页查询考虑显式分批。

程序层面的核心是减少数据库往返:能用一次FOR ALL ENTRIES解决的,不写循环内查询;能用JOIN的,不拆成多次单表查询。当然JOIN“能用”不等于“一定好”,还要看数据关系和查询量,这里不展开。

第三个常被忽略的选项是启用或刷新系统缓冲区。某些主数据表(如状态表、配置表)可以进SAP Buffer,配置得当能让读放大效应得到极大缓解。如果发现某张主数据表被频繁读取、但缓冲命中率很低,不妨检查一下该表的技术属性里是否建议了缓冲方式。

还有一个进阶思路是并行处理。如果业务允许,可以用并行RFC把大任务拆成若干子任务同时跑,适合夜间批量。但并行不是银弹,单任务耗时、资源争抢、输出一致性都需要评估。

4.4 一个典型的“装睡”问题:优化后没生效

优化实施后没生效,先别急着质疑方案。最常见的几个原因是:程序没有重新激活,当前运行的其实是旧版本;数据库统计信息没有刷新,执行计划没有变化;缓存里存着旧数据,测试环境效果看不出来;代码虽然改了,但调用路径里有一段旧的SQL缓存路径,比如使用了Native SQL绕过了Open SQL缓存。

其中“程序没有重新激活”这类事情在多人开发协作环境里经常发生,所以要确认激活对象、传输请求是否完整、服务器上是否是新的运行版本。有的项目甚至有多个应用服务器,还要注意不同应用服务器的代码版本是否一致,否则你做性能分析时连到的服务器和用户实际访问的服务器不是同一个,会把问题带偏。

我记得有一次就是因为应用服务器负载均衡后,分析会话落在了A服务器,生产用户访问落在B服务器,两边代码版本不同,走了完全不同的SQL。排查三个小时最后发现是版本不一致,这类环境层面的坑比代码本身的坑还多。

5. 写在最后:一点个人体会

做了不少性能分析之后,我的体会是:不要追求把所有代码都优化到极致,先做测量,再挑成本最低、收益最高的热点开刀。性能分析本质上是一个证据链过程——先找到时间都去哪儿了,再去改代码。整个过程里最贵的往往不是优化动作,而是定位路径上走的弯路。

有一点我想特别强调:在项目里养成做性能基线的习惯。每个重要报表或事务上线前,用同一个标准场景跑一次SE30/SAT,把关键数据(总耗时、数据库时间、SQL次数)记录到文档里,就算当前没有性能问题,这个基线也是之后排查时的参照物。之后某天性能劣化时,你再跑一次同样的场景,干扰项会少得多。这项投入非常小,收益却很大。

另一个实战小技巧是:分析线上性能问题的时候,不要只收集一份跟踪文件。如果条件允许,多收集不同时间点、不同用户的对同一业务的跟踪,做过对比之后,你会更容易区分哪些慢是代码层次的,哪些慢是偶发的锁等待或系统资源紧张。先把手头的ST05和SAT用熟,日常工作里八九成的问题其实都能解决。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询