五、Sql优化
一、选择条件
v 在从数据库中读取数据时最好直接在select语句中加入选择条件,从而直接限制筛选出符合条件的数据,而不建议读出所有的数据然后用ABAP代码来过滤筛选。
v 例如,不建议使用:
v Select * from zflight.
v Check : zflight-airln = ‘LF’ and zflight-fligh = ‘BW222’.
v Endselect.
v 建议使用:
v Select * from zflight where airln = ‘LF’ and fligh = ‘222’.
v Endselect.
v 这里还要提醒的一点是关于 select *。通常这是一个懒惰的做法,程序员使用select * 的时候其实可能只有一两个字段需要选择。这实际上会显著减慢程序的运行速度,并在整个系统上加载不必要的负担。当应用服务器将这个请求发送到数据库服务器的时候,数据库服务器不得不将每一行数据的整个结构都发送回应用服务器。这样既浪费CPU,又浪费网络带宽资源,尤其是在表结构很大的时候。
v 因此建议只选择那些需要的字段,以便使数据库服务器只传递少量数据回来。
二、集合函数
v 可以使用ABAP提供的集合函数取代ABAP代码来获得最大或最小值。
v 不建议使用:
v Maxnu = 0.
v Select * from zflight where airln = ‘LF’ and cntry = ‘IN’.
v Check zflight-fligh > maxnu.
v Maxnu = zflight-fligh.
v Endselect.
v 建议使用:
v Select max( fligh ) from zflight into maxnu where airln = ‘LF’ and cntry = ‘IN’.
v 其它可用集合函数还有 min (最小值), avg (平均值), sum (求和) and count (数据选择的行数).
三、视图取代基本表
v 很多时候 ABAP 程序员需要使用基本表和嵌套的选择。其实我们应该查看一下是否有SAP已经提供的这些基本表的某些视图可供使用,以便直接获得想要的数据,而不用特别编写代码来获取。
v 不建议使用:
v Select * from zcntry where cntry like ‘IN%’.
v Select single * from zflight where cntry = zcntry-cntry and airln = ‘LF’.
v Endselect.
v 建议使用:
v Select * from zcnfl where cntry like ‘IN%’ and airln = ‘LF’.
v Endselect.
v 视图可以减少数据库DB的读写操作,当使用VIEW视图的时候,当被视图join的table有数据更新操作的时候,同时系统也会更新到这个view里面,使得它们之间的数据一样,所以使用视图会对这些日常操作带来效率问题.
四、“into table” 语句
v 与其一行一行的读取数据添加入内表,不如一次性取出所有数据行。
v 不建议使用:
v Refresh: int_fligh.
v Select * from zflight into int_fligh.
v Append int_fligh.
v Clear int_fligh.
v Endselect.
v 建议使用:
v Refresh: int_fligh.
v Select * from zflight into table int_fligh.
v 附加INTO CORRESPONDING FIELDS ... 把字段内容复制到具有相同名称的目标字段。这种类型的复制会比使用INTO TABLE 左对齐复制到合适的内表或者明确列出目标字段的工作量大。 对于APPENDING CORRESPONDING FIELDS 和APPENDING TABLE 也是一样的。
五、修改ABAP 代码:判断操作符NOT 和<>
v 如果WHERE 子句中的字段用操作符NOT 或<> 来指定,这些WHERE 条件就不能用于某个数据库索引上的搜索。因此应该在可能的情况下用肯定形式来表达 SQL 语句。
v – 如果无法使用肯定的公式,例如,IN 清单过长,才可以用NOT 来指定WHERE 条件,以减少传输的数据。
v – 对于下面两个例子,索引范围扫描都可以用于与字段MANDT、KUNNR 和AUART 一致的索引。
v 1.SELECT vbeln erdat kunnr FROM vbak INTO TABLE g_itab_vbak WHERE kunnr IN g_kunnr AND NOT auart IN ('TA', 'KL', 'SO', 'ZBC').
v 对于上面的语句,只有字段MANDT 和KUNNR 可以用于索引搜索。在解释SQL 中,可以看到一个索引范围扫描。
v 2.SELECT vbeln erdat kunnr FROM vbak INTO TABLE g_itab_vbak WHERE kunnr IN g_kunnr AND auart IN ('BV', 'WV', 'ZWK1', 'SM', space).
v 对于2的语句,字段MANDT、KUNNR 和AUART 都可以用于索引搜索。因此在解释SQL 中可以看到一个索引范围扫描的串联。
六、使用二分查找(Binary Search)选项
v READ命令使用顺序查找数据表,这会降低处理速度。取而代之,使用binary search的附加命令,可以使用二分查找算法,可以帮助加快内表查找速度。 在使用binary search之前必须首先将内表排序,否则有可能找不到记录,因为二分查找反复将查找区间对半划分,如果要查找的值小于查找区间的中间位置的数据项值,则查找区间将缩小到前半个区间,否则查找将局限于后半区间。要了解更多的关于二分查找算法介绍,请点击这里。
v 不推荐使用:
v Read table int_fligh with key airln = ‘LF’.
v 推荐使用:
v SORT int_fligh by airln.
Read table int_fligh with key airln = ‘LF’ binary search.
七、使用 “for all entries”
v 使用SELECT FOR ALL ENTRIES 是为了把SELECT 语句从循环中分离出来。这个方法相当于再内表和数据库表之间创建一个JOIN连接。
v 不推荐使用:
v Loop at int_cntry.
v Select single * from zfligh into int_fligh
v where cntry = int_cntry-cntry.
v Append int_fligh.
v Endloop.
v 推荐使用:
v IF NOT int_cntry[] IS INITIAL.
v Select * from zfligh appending table int_fligh
v For all entries in int_cntry
v Where cntry = int_cntry-cntry.
v ENDIF.
v 注意:内表不能为空。如果选择内表为空,则选择就没有限制。通常,如果WHERE 子句的条件没有参考内表的话,就不会被评估。
v • 在执行SELECT ... FOR ALL ENTRIES 之前,重复的内表条目应该被删除。如果没有删除,就会从数据库不必要的读出 相同数据。
八、“where” 语句的正确结构
v 当一个基本表有多个索引的时候, where 语句中的字段顺序应该与索引的顺序一致,无论第一索引还是第二索引。
v 在选择一个索引的时候,优化机会检查where语句中字段名,然后选择一个与这些字段名排列顺序一致的索引。
v 另外一个提示就是如果一个表是以 客户端编号MANDT 开始的,而索引不是的话,则优化机很有可能不会使用那个索引。
v 在某些情况下,建议查看是否有新的索引可以加速程序的运行。这在访问财务表的程序中会非常实用。
九、正确使用”inner join”
v 当多个 SAP 表在逻辑上关联的时候,总是建议使用右关联 inner join 来从中读取数据。这会降低网络的负载。
v 以两个表为例:zairln 和 zflight。表 zairln 有字段 airln 存储了航空公司的代码,和字段 lnnam 存储了航空公司的名称。表 zflight 有航空公司代码字段 airln, 以及其他字段存储了航空公司运行的航班的详细信息。
v 既然两个表在逻辑上通过 airln 字段可以关联,建议使用以下 inner join:
v Select a~airln a~lnnam b~fligh b~cntry into table int_airdet
v From zairln as a inner join zflight as b on a~airln = b~airln.
v 这样就可以根据选择条件来限制数据,以上inner join还可以增加 where 条件来进一步限制选择条件。
v 使用SQL语句里面的JOIN时候,应该避免JOIN的表不要超过3个,否则严重影响效率.如果真的要JOIN表3个以上的话,而是使用SELECT ... INTO TABLE ... FOR ALL ENTRIES IN以及 READ TABLE WITH KEY BINARY SEARCH.例如我们要提高读取BSEG表的性能,首先我们会根据GJAHR主键从BKPF表取出部分数据到内表itab,然后使用FOR ALL ENTRIES IN itab WHERE BSEG~BELNR = itab~BELNR 这样的的方法取得符合itab里所有条件的BSEG数据.注意使用FOR ALL ENTRIES要先CHECK作为条件的内表itab是否为空,还有作为WHERE的条件在这个内表里面是否会有空值存在,否则无效.
十、使用 ABAP “Sort” 取代 “Order By”
v order by 命令是在数据库服务器上执行的,而 sort 语句是在应用服务器上执行的。因此,与其在select语句中使用order by命令,不如将数据先读取到内表中然后使用sort命令来将结果排序,因为应用服务器上的执行速度要比数据库服务器快。
六、其他优化
其他:
v 避免过得而频繁的数据类型转换,比如N转换为C,但是从N转换成STRING却是很快的,因为操作STRING比CHAR类型少了比较长度的时间.
v 对于同一功能的函数和方法, 调用METHOD比调用FUNCTION要快.
v 使用效率比较高的COLLECT, DELETE ADJACENT DUPLICATES FROM语句。
内存优化方面:
v 1, 虽然ABAP拥有垃圾处理的机制,但是这个是在程序运行完成后实现的.所以我们尽量把无用的变量,内表,对象都释放掉;
v 2, 尽量减少无用的静态定义的变量,内表和对象,因为静态定义的对象会在编译开始就占有内存空间;
v 3, 尽量减少网络的传输负载,比如在设计RFC远程调用传回的内表数据要尽量精简,数据量越大,对CPU和内存需求越多;
v 4, 内存使用紧张的情况下,使用FREE语句,以及SQL语句的PACKAGE SIZE n选项.
v SELECT vbeln erdat
FROM vbak
INTO TABLE li_vbak PACKAGE SIZE 50.
ERP交流群379113944(验证:来自博客)
微信服务号“ERP运维咨询”(超多猎头,求职招聘,很多干货分享,顾问远程做项目)