优化ALV报表,最主要就是优化取数逻辑和数据库查询。因为几乎在所有的程序中都会用到数据库查询,所以这篇文章的内容也不仅局限于SAP、ABAP程序,虽然ABAP有其特殊之处。
优化的时候我遵从以下几个原则:
1.把数据库连接视为一种极其珍贵的资源,大量的数据库操作会增加网络负载,增加程序的运行、等待时间,降低程序性能。因此有以下的注意事项:
(1)因此数据库操作能少则少,严禁在循环中写SQL语句对数据库进行操作;
(2)应该将数据读取到内存中,对内存中的数据进行操作,如排序和运算等,而不是直接对数据库表进行;
2.多表连接查询时,连接的表的数量不超过2-3张。当表的数量过多、数据量大时,会极大程度影响性能。应该先将数据读取到内表(类似于数组)中,使用FOR ALL ENTRIES IN 来和其余需要连接的表进行关联。且簇表无法连接,只能使用FOR ALL ENTRIES IN的方法。 虽然我看到有开发规范说尽可能只连接1张表,但是实际的业务需求中经常只是取其他表的1、2个字段,为了这1、2个字段单独建结构,然后用FOR ALL ENTRIES IN查询实在是太麻烦,这里把限制放宽到2-3张也算是为了方便和为了性能的折中考虑吧。
3.尽可能使用系统提供的方法,而不是自己实现。比如使用SQL的聚合函数进行统计、计算,而不是自己实现。
4.少循环。当数据量比较大时,多次循环会消耗大量的时间和性能。所以循环语句应该近可能少,尽量避免嵌套循环,尽可能将操作放在一次循环中进行。
5.使用一些高效的写法(至少我认为是高效的:)),在编程和优化过程中不断的参照了一些Performance Examples里的一些写法。主要是以下几点:
(1)需要修改内表中的某行的某字段值时,我选择使用
FIELD-SYMBOLS(类似指针),LOOP ... ASSIGNING field-symbols和READ TABLE itab ASSIGNING field-symbols这样的写法,
而不是使用
LOOP ... INTO wa READ TABLE itab INTO wa 修改完后再MODIFY TABLE itab FROM wa;
(2)声明的变量尽可能指明类型、长度;
(3)对于长度较长、长度可变的字符串使用STRING类型替代C类型;:
当然难免有产生冲突的情况,比如:有时多次循环、嵌套循环不可避免,使用聚合函数进行统计需要额外的一次数据库查询等,这就需要具体情况具体分析,选择一种折中、合适的方法。
一些优化实例:
1.使用了动态查询条件,适用于查询字段相同,只是条件不同的情况,主要是减少了重复代码,说不上能改善性能。
2.将两次循环合并成一次循环进行
将原来的两段循环:
合并成:
3.使用SELECT……ENDSELECT-LOOP
这个类似于常规SQL中的游标,能每次对查询结果中的单条数据进行处理和操作。这个一定程度上弥补了ABAP的OPEN-SQL无法对查询字段做运算和SELECT 常量的操作:例如select a+b from tab 和 select ‘常量’,但感觉上使用SELECT……ENDSELECT-LOOP会增加数据库连接的占用时间。
我使用SELECT……ENDSELECT-LOOP筛选出COSS~WTG004和COSP~WTG004相加为零的结果,将原来一次额外的LOOP写到SELECT……ENDSELECT-LOOP中。
OPEN-SQL没法SELECT常量,所以只能查询后再手动修改,我将修改的一次额外循环也合并到SELECT……ENDSELECT-LOOP。
4.使用子查询,这在ABAP性能实例中也提到过,当需要判断是否存在时使用EXISTS加子查询,而不要在SELECT……ENDSELECT-LOOP再次查询是否存在,这样相当于循环中执行SQL。
5.使用聚合函数,而不是自己实现统计功能,尤其是需要进行分组统计时。
6.在需要获取内表长度的时候,用ABAP关键字DESCRIBE TABLE itab LINES length,而不是自己循环内表进行统计。
小结
看了公司发的开发规范,觉得有些地方和我自己的想法还是有些出入,比如当中要求:
在SELECT中尽量避免使用SUM,MAX,GROUP BY,HAVING,GORDER BY语句和如果要使用JOIN,则最多使用一次JOIN,即两个表联合查询
如果本文中所说的有不对之处,欢迎提出建议和改进。
作为一个有专业水准的技术顾问,对自己的要求是不仅是要完成功能,而且要在完成功能的基础上让代码最少最优,这才体现出专业水准和技术水平,我也不希望后人看到我的代码的时候觉得这是一坨无可救药的垃圾代码。共勉~!