于慧 廖华元
株洲南车时代电气股份有限公司信息中心应用开发部,湖南 株洲 412001
近年来,随着信息技术的迅猛发展,各大企业为顺应信息时代的步伐,不断寻找数据流程及流程管理的解决方案,而SAP系统作为目前世界排名第一的ERP软件已被世界范围的众多企业接受并推广使用。SAP平台为用户提供了强大的业务管理解决方案,囊括了几乎企业所需要的全部业务功能。但由于各企业业务背景不一致,需要使用SAP的专用开发语言ABAP在已有SAP系统基础上进行二次开发,用来解决用户定制化需求。
SAP系统为企业提供统一解决方案和事务处理系统,支撑企业的日常运营,并促使企业流程规范化。同时,也使得企业管理系统的事务数据呈海量增长,系统压力成倍增加,日常业务事务运行所需时间越来越长,难以满足企业快速响应的需求。为了顺应企业发展需要,必须提高SAP系统性能、降低事务响应时间。提高系统性能的方法中提升硬件环境是行之有效的方法之一,但提升硬件设施成本高,不可仅依赖这一种方式来解决系统性能问题。可行的方法是提高SAP系统程序的性能,SAP本身标准程序经过几十年的验证和完善,响应性能相对较高,且标准程序逻辑复杂,各模块相互关联,改造标准程序风险较大;而由用户或实施商自行开发的程序,会由于各种原因,导致程序本身会存在性能问题,分析ABAP二次开发程序性能不高的原因主要有以下三点:
1)开发工程师对ABAP语言了解不全面,还未能熟练掌握开发技巧,未采用高效率的语法进行程序开发;
2)系统工程师对系统业务和逻辑不了解,造成数据关联的逻辑不准确;
3)系统上线初期,因为数据库中数据较少,未能发现程序运行中存在的瓶颈。
由此可知,随着开发工程师、系统工程师对ABAP语言和SAP系统的逐步学习和掌握,二次开发的程序有着很大的优化空间。因此,通过对二次开发的程序进行性能优化是非常有必要的[1]。
下面分别从程序性能问题分析、优化方法和应用经验这三个方面加以论述。
除了用户或系统工程师经过对开发程序的实际使用,发现程序性能问题外,一般还可以通过以下两种方法发现可优化的程序。
2.1.1 使用工作负载监控器
事务代码ST03,即工作负载监控器。通过该事务可按年、星期、月、日查看SAP系统中用户运行的所有事务清单,包括交易次数、总响应时间、平均相应时间、等待时间、数据库时间、处理时间等等。一般按月从该事务中查找平均响应时间较长、运行次数较多的事务,对排名相对靠前的程序进行优化。
2.1.2 查询错误日志
事务代码ST22,即ABAP错误日志查询。通过该事务可查看系统一段时间内所有的异常报错日志,其中包括程序超时。SAP正式环境设置前台程序运行时长为20min,程序运行超过这个时间,会立即停止运行,并显示Time Out的异常。通过ST22,汇总统计超时运行的程序次数,并跟踪分析几个月,选择经常出现超时问题的程序进行优化。
筛选出响应时间较长、经常运行超时的程序之后,就得找出造成程序运行瓶颈的原因,需确定是读某个数据库表慢,还是循环处理数据慢等等。可通过如下两个SAP标准事务代码来达到“对症下药”的目的。
2.2.1 跟踪事务的指定操作
事务跟踪器ST05,通过这个事务可跟踪事务的指定操作,还可选择跟踪模式:SQL跟踪、队列跟踪、远程函数调用RFC跟踪和缓存区跟踪。一般选择SQL跟踪。该事务可显示每一个读表语句所花费的时间,从而分析每条语句。
2.2.2 ABAP运行时长分析
使用该工具主要用于某个事务或程序后台ABAP 的运行时分析。与ST05不同的是,SE30不光可监控到读表所花费的时间,还能记录其它数据处理语句或整个子程序花费的时间。可根据需要设定跟踪的数据范围和分析结果的粒度,采用渐进式的方法分析跟踪结果[2]。
优化开发程序性能的方法主要有三点:一是优化读取数据库表的语句,低效率的SQL语句不仅耗时,还会占用数据库大量资源,造成其它语句排队等待资源的现象;二是改进ABAP程序设计的算法,算法的优劣也同样决定着报表程序的运行时间,嵌套循环、反复内表赋值等,往往也是导致程序运行超时的罪魁祸首;三是改善用户使用SAP系统功能的习惯,引导与培养用户掌握正确、良好的SAP查询方法也是很重要的,输入日期、组织机构等查询范围,就能大幅度减小取数范围。因此程序性能优化方法的研究就需要从这三个方面开始。
3.1.1 使用数据库索引
数据库表的一级索引为关键字段,比如年度、凭证编号、行号等等。限定和关键字段一致的选择条件读取速度是最快的,但往往仅个位数的关键字段很难满足多维报表的查询需求。因此可根据查询数据的经验,建立二级索引。SAP允许用户对标准数据表创建索引。但使用时,要注意where条件后的字段顺需和索引完全保持一致,可缺少其中的某个字段,但从上至下的顺序是不能打乱的。如某个数据表的二级索引字段为工厂、物料、移动类型、库存地点,在使用的过程中定义为工厂、库存地点、物料、移动类型,则是不可以的。
另一种情况,若大多数选择条件都存在索引,而个别条件不存在,则建议在读取数据表的SQL语句中把个别条件去除,取数完成之后再通过逻辑语句进行数据筛选。
值得注意的是,不是任何时候都通过建立索引的方式来提高读取速度,因为索引的建立需要占用数据库空间,只应对经常使用到的查询条件建立[3]。
3.1.2 降低数据库负载
要提高读取数据的性能,就需要减少从数据库传输到应用服务器的数据量、减少读取数据库表的次数,或者将增加系统负载的操作转移到应用服务器上。
有些程序员为了方便、省事,将无关字段定义在程序内表中,取数语句不指定字段名称,直接用“SELECT*”代替。当程序仅从一个包含两百多个字段的表中读取几个字段时,“SELECT*”带来了多余的数据量。当然,这是一个比较极端的例子,但资源的占用往往是无形的。取数时,跟选择条件有关、能限定数据范围的表要先读取,尽量减少从数据库传输到应用服务器的数据量。
在设计程序逻辑的时候,系统工程师可能未考虑到性能问题,只是将取数先后顺序、数据处理方式简单的罗列。但在开发工程师进行系统开发时,就得注意尽量将对同一张数据表的取数合并成一次,更应避免在LOOP循环语句中,使用select single每次读取一条数据的方式。必须减少读取数据库的次数,从而缓解系统压力。
另外,SQL语句是支持GROUP BY、MAX等排序、比较功能的,但这种排序不应由数据库来执行,而是应由程序命令在应用服务器上执行。因为一般情况下,SAP正式环境应用服务器数量多于数据库服务器,应用服务器的资源比数据库资源多,所以在应用服务器上执行操作,可以减少对数据库服务器的资源占用,从而提高系统整体性能。
3.1.3 取数语句使用注意事项
当数据来源为多个相关表时,可以使用Join 关联语句将几个表按关键字关联起来。不过这种关联表的个数最多不能超多三张,否则系统不能选出最优的索引取数方法,反而降低了速度。
有一种语句“FOR ALL EINTRIES IN”,用来限定取数范围,将取数与已有相关内表数据关联起来,是程序中经常使用到的语法。但使用该语句有一个先决条件,及作为驱动表的内表不能为空,否则“FOR ALL EINTRIES IN”将造成整个数据表数据的读取。对于系统增量表来说,缺乏驱动表为空的检查,必会带来超时的后果。此外,驱动表最好不包含重复的条目,否则会造成相应的数据从数据库中获取对应条目的次数,可通过排序并删除重复行来避免这种情况。
通过使用以上三种优化方法对公司财务报表“现金流量表”进行优化,效果十分明显。通过事务代码SE30对该程序运行时长进行分析,为了避免数据缓存对第二次取数的速度影响,故先运行优化后的程序,其两者在测试环境运行时间对比如下:
如图一、图二所示,程序优化后总体运行时长为519,622毫秒,而优化前的程序运行时长为2,050,436毫秒,速度提升了2.9倍;而数据库耗用时间方面,优化后仅需118,307毫秒,而优化前是1705,921毫秒,速度提升了14.4倍。由此可看出优化效果十分明显。
图1 程序优化后运行时长
图2 原程序运行时长
程序优化,需要在程序设计时,除了选择最优数据结构,还需要有最优执行语句、设计最优执行流程,从而达到程序执行速度快、占用系统资源少的目的。以下几种方法是在日常开发工作中常用到的语法优化方法。
3.2.1 二分法查找
当一个内表数据量大时,使用二分法查找的优化效果特别明显,事半功倍。因为利用二分法查找一个元素的最大比较次数不超过[log n]+1,这里n 为数列元素的个数。相比之下用顺序查找的最大比较次数为n-1,由此可知使用二分法后程序性能大为提高。因此在read内表时,往往都会加上二分法的标志性字段“Binary search”。但在使用二分法之前,一定要根据关联条件对读取内表进行排序,否则就事倍功半了。
3.2.2 避免嵌套循环
当内表数据量比较大时,应减少使用循环嵌套的次数,并不应在循环中定义变量。一般的嵌套循环可以采用一层循环和二分法读取内表来代替,若碰到有多行需计算汇总数量或金额等,则可先在循环外使用Collect或At new/At end等方式获取所需结果,再结合read内表方法读取。
有些程序逻辑过于复杂,嵌套循环往往能节省很多的代码段,达到最终的显示效果,但这种方式虽省力但不省时,因此需要尽量避免。
3.2.3 及时释放表空间
多使用内表处理数据能帮助减少数据库压力,但是使用之后无用的内表数据应及时清空,释放资源。且内表字段不宜定义的过多,应按需分配,减小占用空间。
在SAP中有Clear itab、Clear itab[]、Refresh itab和Free itab四种清空内表的方法,但四种方法的实现效果不相同。Clear itab仅清空表头,对内表数据存储空间不影响;Clear itab[]和Refresh itab功能一致,即清空内表数据存储空间,以上三种方法均保留内存区, 而仅有Free itab即可清空内存表数据存储空间,并释放内存区。因此确定使用完毕的内表,则可使用Free语法释放空间。
3.2.4 了解业务场景和流程
开发人员除了掌握ABAP程序开发语言之外,还需对公司业务场景和流程有一定的了解,知道系统数据表中的数据是从哪一步操作得来的。虽说企业可能有专门的ERP业务分析人员,但他们对业务和系统后台表之间的关系不一定很清楚,给出的设计方案中取数可能会走弯路,比如采购订单物料凭证信息在MSEG、EKBE中都存在,但MSEG包括所有的物料移动凭证信息,EKBE则只包含与采购订单相关的凭证信息,因此读取EKBE时会比MSEG快很多[4]。
3.2.5 设置后台运行功能
当程序取数逻辑、语法均优化过后,发现程序仍然会因为数据量大、运算逻辑复杂运行超时,就需要为该程序开发后台运行功能。系统标准功能可直接后台运行指定程序,但该方法显示的报表结果不方便查看和导出,因此需通过运行自定义后台运行功能,最终得到与前台运行一致的展现结果。
表1 报表优化效果举例
开发后台运行功能时,可根据报表性质,按月或按天晚上自动运行后台作业,将上月或前一天的报表结果计算好保存到指定自建表中。用户前台运行时,程序可按照查询条件,从后台自建表中取出已有数据,与本月或当天新增数据合并后显示。这样即可满足不同用户的需要,又可减少后台运行的次数,并大大缩小前台运行的时间和所需资源。
企业组织架构复杂,各分子公司的业务流程和要求有很多差异,因此可能开发了大量业务日常需要的事务功能,包括查询报表、单据打印、数据导入等等,这其中查询报表占得数量是最多的;查询报表又分为明细查询报表、年度或月度汇总报表;并且系统积累了大量的业务数据,若每张报表都不加任何查询条件的穷查,那将造成严重的服务器负载,用户最终也得不到想要的数据结果。因此作为SAP系统程序的开发者,在程序开发时就得通过以下几种方式来引导与培养用户掌握正确、良好的SAP查询方法[5]。
3.3.1 限定报表关键查询条件必填
设置查询报表的选择条件,首先要了解用户的需求和操作习惯,与用户达成一致之后,则将关键查询条件设置成为必输字段,若这些字段未输入,则会弹出相关消息提醒用户。关键字段一般为日期范围、订单类型、工厂、采购组等等,用于缩小查询数据的范围。
3.3.2 默认查询条件
在上一步了解了用户查询习惯之后,可对必填条件设置默认值。比如某张按照月度查询的财务报表,就可默认查询日期从当月1日到查询当天,用户即可临时修改,又省去了每次都需手工输入的麻烦。
3.3.3 引导用户需求
企业组织架构、业务类型随着市场的需要,不断地在发生变化,用户对报表的取数逻辑和展现格式也在跟着变化,因此业务部门可能会向信息部门提出很多新的开发需求。这种情况下,建议信息部门系统工程师和开发工程师组织专家对这些需求进行评审,判断是否可以通过对原有报表的修改来满足新需求。在ERP实施和运维的整个阶段中,应控制新报表的开发,尽量使用系统已开发报表或系统标准功能,因为程序量多,维护工作也相应增多,很难保证每个程序的最优逻辑和取数语法。
本人所在单位从两年前开始开展优化工作,在数据库以平均每天1G增长速度的应用情况下,SAP系统对话响应时间能基本保持稳定。部分程序优化效果十分明显,受到了用户的良好反馈。表1为部分优化程序优化效果举例。
通过实践表明,本文介绍的SAP系统ABAP程序优化方法能够有效地提高SAP系统的整体性能,使系统可用性得到了提高,这对提高用户满意度起着重要的作用。
总而言之,系统性能优化是一个长期且复杂的系统性工程,需要注重多方面的问题。开发人员需更加深入了解业务流程,并掌握系统数据增长趋势,才能更有针对性的对程序逻辑进行优化,对系统资源进行合理分配,为提高企业SAP系统应用水平提供更有力的支持。
[1]托马斯·施奈德. SAP性能优化指南[M]. 北京:东方出版社,2006.
[2]黄佳. SAP程序设计[M]. 北京:机械工业出版社,2005.
[3]秦靖,刘存勇. Oracle从入门到精通[M]. 北京:机械工业出版社,2011.
[4]邹玉龙,王昕磊. ABAP程序性能优化的研究及应用[J]. 电脑知识与应用,2011(8).
[5]李娜娜,李长海. ABAP编程中提高执行效率的几个技巧[J]. 数字技术与应用,2010(4).