SAP ABAP 程序优化思路

发布时间:2024年01月18日

ABAP 程序优化思路

降低CPU负荷(减少循环次数)、降低DB负荷(减少IO操作)、降低内存使用(减少内表大小)

一、数据库

  1. **不要使用 SELECT *** …,选择需要的字段, SELECT * 既浪费CPU,又浪费网络带宽资源,还需占用大量的ABAP内存
  2. 不要使用SELECT DISTINCT …,会绕过缓存,可使用 SORT BY + DELETE ADJACENT DUPLICATES 代替
  3. 少用相关子查询,因为子查询对外层查询结果集中的每条记录都会执行一次
  4. 少用嵌套SELECT … ENDSELECT,可以使用联合查询或FOR ALL ENTRIES来替换,减少循环次数
  5. 如果确定只查一条数据时,使用 SELECT SINGLE… 或者是 SELECTUP TO 1 ROWS
  6. 统计时,直接使用SQL聚合函数,而不是将数据读取出来后在程序里再进行统计
  7. 使用游标读取数据,这样省掉了将从数据库中的取记录放入内表的INTO语句这一过程开销
  8. 多使用inner join,必要时才使用left join
  9. inner join获取数据时,尽量不要用太多的表关联,特别是大表关联,关联顺序为:小表-大表

10.where 条件里面多用索引、主键,顺序也要遵循小表-大表

11.inner join条件放置的位置应该按照 On、Where、Having的顺序放,因为SQL条件的的执行一般是按这个顺序来执行的,将条件放在最开始执行,则可过滤掉大部数据;但要注意Left Outer Join,是否可以将ON中的条件移动到Where从句则要考虑(如果真能放在Where从句中,则应该使用Inner Join,而非Left Outer Join,因为Where条件会过滤掉那些包括在右表中不存在的左表数据),因为此时条件放在On后面与放在Where语句后面结果是不一样的(因为不管on中的条件是否为真,左表中在右边表不存在的数据也会被返回,但如放在where条件中,则会对On产生的数据再次过滤的条件,会滤掉不满足条件的记录——包括左表在右表中找不到的记录,这时已经没有left join的含义)

  1. 要根据主键或索引字段查找数据,且WHERE从句中的条件字段需按INDEX字段顺序书写,且将索引字段条件靠前(左边),如:在VBFA表中查找SO所对应的交货单DN,因为如果直接到LIPS中找时,SO的订单中号与行号在LIPS中非主键,但在VBFA是部分主键(VBFA中根据部分主键查找 SO -> DN; 根据索引查找 SO -> PO,VBFA-VBELN+VBFA-POSNN组合字段上创建了索引,即根据SO找PO时,不要从EKKN关联表中查找,而是通过VBFA中查找。后来查看EKKN,发现在VBELN+VBELP字段上创建了索引,所以从VBFA与EKKO查找应该差不多,主要看哪个表数据量少的问题了)

检查条件组合字段是否是主键,或者是上在上面创建了索引,避免条件组合字段即不是主键又没有索引

  1. SELECT语句WHERE条件,应该先将主键相关条件放在前面 然后按照比较符 = 、< 、>、 <> 、LIKE IN 的顺序排列WHERE条件

14.使用部分索引字段问题:如果一个索引是由多个字段组成的,只使用一部分关键字段来进行查询时,也是可以使用到索引,但使用时要注意要按照索引定义的顺序且取其前面部分

  1. 根据索引字段进行ORDER BY,否则通过程序进行SORT BY。与其在数据库在通过非索引字段进行排序,不如在程序中使用SORT BY语句进行排序,因为此情况下应用服务器上的执行速度要比数据库服务器快(应用服务器上采用的是内存排序)

16.避免在索引字段上使用:

  • not、<>、!=、IS NULL、IS NOT NULL,**可以用> 与 < 来替代

  • 避免使用 LIKE,但LIKE '销售组1000’和LIKE '销售组1000%'可以用到,而LIKE ‘%销售组1000’(百分号前置)则用不到索引

  • 不要使用OR来连接多个索引字段(但同一字段多个值之间可以使用OR);对于同一索引字段,可以使用IN来替代OR:

  • 带有BETWEEN 的WHERE 条件不能通过索引来搜索?也可使用IN代替

17.避免使用以下语句,因为使用这些语句时,不能使用 Table Buffer

  • Aggregate expressions
  • Select distinct
  • Select … for update
  • Order bygroup byhaving从句
  • Joins,使用JOIN时,会绕过SAP缓存,可以使用FOR ALL ENTRIES来代替
  • WHERE从句中使用Sub queries(子查询)
  • WHERE从句中使用IS NULL条件

18.在下面情况下使用FOR ALL ENTRIES IN:

  • 在循环内表 LOOP…AT Itab中循环访问数据库
  • 簇表是禁止JOIN的表类型, 当需要联接簇表查询数据时,如:BSEG(会计凭证)、KONV(条件表)

簇表一般是由多个表组成,簇表中的数据来自于多个表,有点像视图,但不能直接通过簇表进行数据维护

  • JOIN超过3个表会出现性能问题, 当使用JOIN联接的表超过3个时
  • 如果两个表的数据非常大时(上百万),使用JOIN进行联合查询会很慢,此时改用FOR ALL ENTRIES IN

19.使用内表批量操作数据库,而不要使用工作区一条条操作,如:

SELECT … INTO TABLE itabINSERT dbtab FROM TABLE itabDELETE dbtab FROM TABLE itabUPDATE/MODIFY dbtab FROM TABLE itab

20.如果你使用 CLIENT SPECIFIED,需在WHERE从句第一个位置上指明 MANDT条件,否则使用不到索引

二、程序

  1. READ TABLE …WITH [TABLE] KEY….BINARY SEARCH读取标准内表使用二分查找
  2. 循环(LOOP AT …WHERE…)或查询(READ TABLE …)某内表时,如果未使用索引(排序表、哈希表)或二分查找,则在查询组合字段创建第二索引,查询时通过USE KEY或WITH [TABLE] KEY选项使用第二索引,这样在查询时会自动进行二分查找或哈希找查

在没有用二分查找的情况下,可在查询组合字段上创建第二索引(哈希或排序索引),则在读取或循环内表时会自动使用二分查找或哈希查找算法

  1. 查找时,优先考虑使用哈希表进行查找,再考虑使用排序表进行二分查找,因为哈希查找的时间复杂度为(O (1)),不会因数据的增加而受到影响;而二分查找虽然比顺序搜索快很多,但随着数据的增加会慢下来,其时间复杂度为(O (log2n));标准内表的时间复杂度为O(n)。注:如果只使用到部分关键字为搜索条件,哈希表则会全表扫描,此时应该使用二分找查
  2. FOR ALL ENTRIES:需要判断内表是否为空,否则会查询出所有数据
  3. LOOP AT itab… ASSIGNING …、READTABLE …ASSIGNING … 在循环或读取内表时,使用字段符号来替换表工作区,将数据分配给字段符号Field Symbols,减少数据来回传递
  4. 尽量避免嵌套循环,如必须时,将循环次数少的放在外层,次数多的放在内层,这样可以减少在不同循环层之间的频繁地切换及内部循环次数
  5. 条件语句中多使用短路与或,“与”连接时将为假的机率大的条件放在前面,“或”连接时将为真的机率大的条件放在前面
  6. 少使用递归算法,递归时会增加调用栈层次,降低了性能,可使用队列或栈来避免递归
  7. 尽量不要使用通用类型(如FIELD-SYMBOLS、及形式参数),使用具体限定类型;比较时尽量使用同一数据类型:IF c = c.比IF i = c.快,原因是未发生类型转换

10.不要使用混合类型进行计算与比较,除非有必须

11.尽量使用静态语句,少用动态编程,动态编辑虽然灵活,但性能有所下降

12.在对字符进行操作进,尽量使用String代替C固定长度类型,如:concatenate[k?n?kat?ne?t]语句对固定长度的C连接时,会去扫描那些非空字符出来再进行连接,速度没有String快

13.READ/MODIFY TABLE时使用TRANSPORTING只读取或修改必要的字段 [tr?ns?p?:t]

14.尽量避免使用MOVE-CORRESPONDINGSELECT…INTO CORRESPONDING FIELDS OF [TABLE] (SELECT时,查询几个字段就定义具有这几个字段的内表,而不是直接使用基于数据库表类型创建的内表,否则如果直接使用 INTO TABLE语法检查时会警告,但结果是没有问题的)。CORRESPONDING语句在系统内部存在隐式操作: 逐个字段的检查元素名称匹配; 检查元素类型匹配;元素类型转换[?k?ris?p?ndi?]

15.最好不要向排序内表中插入(INSERT … INTO TABLE …)数据,因为在插入时会进行排序,速度会随着数据量的增加而慢下来,所以最好只向标准内表或哈希表中插入数据

16.将某个内表中的全部记录或部分记录追加到另一内表时,使用INSERT/APPEND LINES OF … 代替循环逐条追加;如果是全新赋值,直接对内表使用“=”进行赋值操作即可

17.调用类方法要快于Function

Calling Methods of global Classes: call method CL_PERFORMANCE_TEST=>M1.

Calling Function Modules: call function ‘FUNCTION1’.

18.通过运行事务代码SLIN(或者直接通过SE38的菜单),进行代码静态检查,根据SAP提供的反馈信息,优化代码

19.通过老式方式定义内表时,使用OCCURS 0 而非OCCURS n :[??k?:s] 重现

  • OCCURS n 代表初始化内表的空间大小为n(空间固定),当内表存储记录条数超出n时,系统将依靠页面文件存放超出部分的数据。 当系统内存资源十分紧缺的时候,我们可以使用OCCURS n的初始化方法, 但是这样的效率稍微慢
  • OCCURS 0 代表初始化内表的空间大小为无限,当内表存储记录条数不断增加时, 内表所使用的内存空间不断扩大, 直到系统无法分配为止。使用内存比使用页面交换更快一些, 但是要考虑系统的资源状态

20.使用完成后及时清空释放内表所占用的空间:FREE .

21.使用CASE…WHEN语句代替 IF…ELSEIF…;使用WHILE…ENDWHILE 代替 DO…ENDDO

22.LOOP循环内表时加上Where条件减少CPU负荷,而不是在循环里通过IF语句来过滤数据

文章来源:https://blog.csdn.net/zkl519/article/details/135595434
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。