ZCOR0015的优化全过程记录文档

    2015年3月,今天无意翻到这篇写于2010年7月的文档,回想那时的工作,毕业3年初出茅庐的我面对接触不多的SAP+DB2竟敢操刀动斧,自信满满。
虽然这过程一路坎坷,数次判断几乎全都被打脸验证,看着如小强般坚毅的我,哈哈~ 文档里带着情绪的措词十分逗笑,可以洞悉那时的心情。 ——如今5年过去,却久未闻硝烟,怀念ing~
目录:

ZCOR0015的优化全过程记录文档... 1

内容说明:1

1.寻找问题点,切入分析... 2

2.再次碰到问题,转折点.. 6

3.反复尝试,直至最后解决... 9

4.结果... 12

5.总结... 14

6.参考文档... 15

内容说明:

红色字体为突出个别文字的内容

黑色字体为普通过程阐述

蓝色字体为图解说明

黑色背景的字体为一些关键步骤点

优化目的:让ZCOR0015能够迅速取出数据,并且不通过MKPFMSEG中间表的处理.

业务的接受度: 跑1个月跨度的报表,要在5分钟内返回结果,跑半年的报表,要在1小时内返回结果.

结果: ZCOR0015 统计一个月的数据20090101~20090131

 

 

X轴为消耗时间,单位(秒)

上图为优化后的时间消耗,下图为优化前的时间消耗.

红色为数据库层时间消耗,蓝色为ABAP层时间消耗.

1.寻找问题根源,切入分析

先在se38里找出该程序,根据开发人员的测试,该程序的大部分的时间消耗在数据库层面,过后开发人员做了一个定时job,定期把视图WB2_V_MKPF_MSEG2的数据导入MKPFMSEG表里, 写程序的时候就直接从MKPFMSEG里取数据即可,这样暂时可以解决这个程序的缓慢问题,但是却把性能的隐患转移至后台job程序上了, 当前这个job跑起来非常消耗资源,并且也存在数据实时性的问题,

这次的调优目的就是彻底的解决这个问题.

我一开始的假想,认为这性能的问题,无非就是SQL语句所走的执行计划匹配上不合理的索引,导致不合理的资源消耗,当然这个早早下的结论也没错,只是太宽泛了,起初我认为折腾一天就可以搞定,甚至是一下午,但是最终却消耗了10天的时间…

没有全盘了解系统的细节结构、应用层面的逻辑 对SAP经验不足, 却又自信满满的姿态去看这次的问题 ,其实还蛮可怕的 ,这次的事情 所覆盖的知识面完全超出了我的想象。

把这段存在性能问题的sql从abap程序里抓出来,基本如下:

SAP端:

    select a~matnr_i
a~mblnr_i
a~bwart_i
* b~aufnr
a~budat
a~WERKS_I
a~bukrs_i
a~menge_i
a~mjahr_i
a~aufnr_i
a~SHKZG_I
INTO CORRESPONDING FIELDS OF TABLE g_t_result
from WB2_V_MKPF_MSEG2 as a "inner join aufm as b on a~mblnr_i = b~mblnr and a~mjahr_i = b~mjahr and a~matnr_i = b~matnr
where
a~budat BETWEEN s_budat1 AND s_budat2 and
a~bukrs_i = s_bukrs and
a~werks_i = s_werks and
a~mjahr_i = s_mjahr and
a~bwart_i in ('','','','','','','Z09','Z10','Z11','Z12','Z21','Z22','Z01','Z02','','','','','','','','','','','','') AND
a~matnr_i BETWEEN '' and ''.

改成DB2里的SQL: (先暂时改成count(*) 计数,优化完了再改为实际取的字段名,大体上执行计划不会有差异.)

    select count(*)
from sapprd."MKPF" T0001, sapprd."MSEG" T0002
where
T0002."MANDT"= T0001."MANDT"
AND T0002."MBLNR"= T0001."MBLNR"
AND T0002."MJAHR"= T0001."MJAHR"
AND T0001."BUDAT" BETWEEN '' AND ''and
T0002."BUKRS"=''and
T0002."WERKS"=''and
T0001."MJAHR"=''and
T0002."BWART"in('','','','','','','Z09','Z10','Z11','Z12','Z21','Z22','Z01','Z02',
'','','','','','','','','','','','') AND
T0002."MATNR" BETWEEN ''and'';

执行计划如下,MKPF上的索引是非常不合理的,光是扫描一个索引就消耗那么多的资源,从这里就判定出索引的不合理性.

下面为这MSEG,MKPF这2张表在SDX里的状况,行数,统计信息更新时间,页数等等.与生产机的数据量基本同属于一个数量级.

第二段是MKPF的两个索引状况,叶子数,索引字段的基数,统计信息时间.(还有levels 一般不超过3)

以下为这个执行计划消耗的I/O ,CPU,BUFFERS等等资源的状况. (这里为估算值,并非真正的实际值)

接着开始在DB2数据库层面优化SQL.

单纯在数据库层面其实不复杂,就那么几个招式:

1.改SQL.

2.建立合适的索引(根据业务逻辑+需要把多少工作交给ABAP层面来做,减少SQL的谓词来取一个平衡点)

3.收集统计信息,让数据库有稳定的执行计划.

把SQL改写了一下

  1. T0002."BUKRS"='1000'and
  2. T0002."WERKS"='1000'and
  3. T0001."MJAHR"='2009'and
  4. T0002."BWART"in('101','102','122','123','161','162','Z09','Z10','Z11','Z12','Z21','Z22','Z01','Z02',
  5. '601','602','653','654','261','262','531','532','543','544','961','962')

把上面这部分繁琐的业务逻辑去掉,如果把这部分内容纳入SQL里的话,会明显的加重取回数据的负担,将会扫描更多的索引页,或是建立更多的索引,本身SAP的内表就很强大,把这部分逻辑交给ABAP层面做即可,先取回数据到内表里,再LOOP循环一次,把结果筛选一遍,这样的思路应该是最优的.

然后再分别建两个索引.

附上建立的ddl:

    CREATE INDEX "SAPPRD"."IX_MKPF_BUDATMANDT"
ON "SAPPRD"."MKPF"
("BUDAT" ASC,
"MANDT" ASC
)
PCTFREE 10
DISALLOW REVERSE SCANS
COLLECT DETAILED STATISTICS;
GRANT CONTROL ON INDEX "SAPPRD"."IX_MKPF_BUDATMANDT" TO USER "SAPPRD";
CREATE INDEX "SAPPRD"."MSEG~GM"
ON "SAPPRD"."MSEG"
("MANDT" ASC,
"MBLNR" ASC,
"MJAHR" ASC,
"MATNR" ASC
)
PCTFREE 10
DISALLOW REVERSE SCANS
COLLECT DETAILED STATISTICS;
GRANT CONTROL ON INDEX "SAPPRD"." MSEG~GM " TO USER "SAPPRD";

大致上解释下这几个参数,

PCTFREE:为填充因子,10的含义是 遗留下10%的页空间,以供insert or update时不至于那么快导致页分裂,如果值太大的话,会导致扫描更多的索引页,增加成本.

DISALLOW REVERSE SCANS: 是否使用反转索引,其实在这是物理上的概念,并非索引就倒序了,只是避免热点块的发生,我们的SAP不存在那么高的并发,所以DISALLOW即可.

COLLECT DETAILED STATISTICS: 收集详细的统计信息.

接着在DB2里执行一下这个SQL:

    select
T0002.matnr,
T0001.mblnr,
T0002.bwart,
T0001.budat,
T0002.WERKS,
T0002.bukrs,
T0002.menge,
T0001.mjahr,
T0002.aufnr,
T0002.SHKZG
from sapprd."MKPF" T0001 inner join sapprd."MSEG" T0002 on
T0002."MANDT"= T0001."MANDT"
AND T0002."MBLNR"= T0001."MBLNR"
AND T0002."MJAHR"= T0001."MJAHR"
where T0001."BUDAT" BETWEEN '' AND ''and
T0002."MATNR" BETWEEN ''and'';


速度不错,两次索引扫描,然后fetch 出数据,再做Nested loop join,

并且先loop的小表MKPF,成本都很低,这已经是最佳的执行计划以及索引选择了,这个时候我笑了,我认为问题已经完美解决,并且返回数据的速度都在个位数的秒级.

2.再次碰到问题,转折点.

这时我把程序交给开发人员,我把思路说明了一遍,我说这个程序现在1个月数据量在10秒内即可出来,半年的数据量顶天也就1分钟,

等开发人员把程序写入ABAP报表里了,跑了一下,我傻眼了....一个月的数据量, 竟然需要10+分钟...和我预期的完全不一样.

脑袋里开始空白了,这是过于自信所带来的空白..

开始扫荡式寻找问题点,数据库性能,数据库参数,AIX性能,磁盘
存储 网络,ABAP代码..全都翻了一遍,

起初发现AIX里的TOPAS显示

hdisk4
的busy%程度非常高,高达90+,但是CPU显示的user不高,大部分CPU时间都是在wait,IDLE基本持平90%左右 (这时SDX的环境只有我一个人在用)

(tips:后来事情结束后才恍然大悟,其实大量表扫描+hash join的特征.)

虽然我脑子里很清晰的知道,他们出问题的可能性不大,

其实这时我心里很清楚,由于我自身的瓶颈(SAP+DB2的经验不足)其间的逻辑交互机制不清晰,单方面从数据库层面来判断问题,显然是捉襟见肘的。

但是近乎自负的那种自信却抵触了我否定自己的念头。

接着还是一味的在AIX操作系统层面寻找问题…… 并且还消耗了蛮多时间,索性到最后,还是回到数据库,啃了些文档,打算在数据库层面寻找问题点。

  1. select*from sysibmadm.TOP_DYNAMIC_SQL order by AVERAGE_EXECUTION_TIME_S desc fetch first 5 rows only;
 

上面的语句可以找出在共享池里的SQL,按执行时间排序.(这个手段我在Oracle和SQLServer里倒是经常用,但是DB2比较陌生..)

发现了从ABAP层送出的SQL语句和我所认知的完全不一样,这个时候开始有突破口了.

下面的代码为ABAP层面送给DB2的原句

SELECT T_00."MATNR",T_01."MBLNR",T_00."BWART",T_01."BUDAT",
           
                                 T_00."WERKS",T_00."BUKRS",T_00."MENGE",T_01."MJAHR",
                                                T_00."AUFNR",T_00."SHKZG"
           
FROM SAPPRD."MSEG"T_00 INNER JOIN SAPPRD."MKPF"T_01 ON
                            T_01."MANDT"=?
                            AND T_01."MANDT"=T_00."MANDT"
                            AND T_01."MBLNR"=T_00."MBLNR"
                            AND T_01."MJAHR"=T_00."MJAHR"
WHERE
          
T_00."MANDT"=? AND
          
T_01."BUDAT" BETWEEN ? AND ? AND
          
T_00."MATNR" BETWEEN ? AND ? 
          
WITH UR -- OPTLEVEL( 10 ) -- QUERY_DEGREE( 1 )
-- LOCATION( ZCOR0015_1 , 125 ) -- SYSTEM( SDX , SAPPRD )'

看了下执行计划,终于找到问题了,

ABAP层面送出的SQL语句,所导致的执行计划是非常烂的,又走回之前的2个索引,一个MKPF~BUD,一个是MSEG~M,

并且根据这个索引计算出来的连接方式为HASH JOIN. 使用不合理的索引,带来的成本是非常高的.

这段程序和我所想传送给数据库的语句有2个不同的地方

首先是T_01."MANDT"=?

其次是WITH UR --
OPTLEVEL( 10 ) -- QUERY_DEGREE( 1 ) -- LOCATION( ZCOR0015_1 , 125 ) -- SYSTEM(
SDX , SAPPRD )'

琢磨了下 MANDT这个是cline代码,用来区分800,900的数据,SAP自动给加上的,可以理解

再者是这个WITH UR 是锁级别,

OPTLEVEL(10)是优化级别,QUERY_DEGREE是并行的参数.

为什么带这些东西后,这段程序的执行计划差异会那么大呢??

我把『?』问号 都替换成了实际值,然后套入SQL里,执行下面的语句.

而且还在我后来建立的MKPF索引里添加了MANDT字段,

SELECT T_00."MATNR",T_01."MBLNR",T_00."BWART",T_01."BUDAT",
           
                                 T_00."WERKS",T_00."BUKRS",T_00."MENGE",T_01."MJAHR",
                                                T_00."AUFNR",T_00."SHKZG"
           
FROM SAPPRD."MSEG"T_00 INNER JOIN SAPPRD."MKPF"T_01 ON
                            T_01."MANDT"='900'
                            AND T_01."MANDT"=T_00."MANDT"
                            AND T_01."MBLNR"=T_00."MBLNR"
                            AND T_01."MJAHR"=T_00."MJAHR"
WHERE
          
T_00."MANDT"='900' AND
          
T_01."BUDAT" BETWEEN '20090101' AND '20090201' AND
          
T_00."MATNR" BETWEEN '000000000010000000' AND '000000000019999999'
          
WITH UR -- OPTLEVEL( 10 ) -- QUERY_DEGREE( 1 )
-- LOCATION( ZCOR0015_1 , 125 ) -- SYSTEM( SDX , SAPPRD )'

这样子速度非常快,并且执行计划也是正确的,我就纳闷了.为什么同样的程序,我提交给DB2的 与ABAP提交给DB2的相差那么?

脑子再次迷糊.

3.反复尝试,直至最后解决

这时我想到了用HINT来解决问题,在ABAP里写HINT 强制走NESTED LOOP,指定索引

尝试了一大堆%_HINT未果,仍然找不到匹配DB2使用的HINT

就连网上比较普遍的一个HINT也无果,没有实际作用,

%_HINTS
    ADABAS   'ORDERED'
    INFORMIX 'ORDERED'
    MSSQLNT  'OPTION FORCE ORDER'                         
    DB6 '<NLJOIN><IXSCAN TABLE=''MSEG'' SAP_INDEX=''M''/>'
    DB6 '<IXSCAN TABLE=''MKPF'' SAP_INDEX=''0''/></NLJOIN>'.

我猜测或许SAP针对DB2这一块写的HINT程序,只是匹配的早前的DB2版本,在后续版本中已经废弃掉了,

(我之所以会这么猜测,是因为我跟踪了MB51的标准程序,有一个选择用过账日期开始来访问数据库,但是这个标准程序根本就不会走到那段HINT代码里,说明这个选择是不会生效的)

忽然有种被忽悠的感觉.

如果废弃了,应该有所说明,并且把新的语法公告之,但是我没有翻到相关的ABAP基于DB2 HINT的说明文档,这种undocument的方式让人十分不爽啊.

反倒是Oracle的HINT说明非常多,而且很容易使用,我在这里非常的BS IBM DB2,它让我翻看了一晚的程序,翻文档
翻到有一种想吐的感觉..

Google搜索”ABAP DB2 HINT” 这三个关键字,能搜索到的内容我全都尝试了一遍.

我已经快2年没有这样的感觉了,真恶心啊。

下面这个也是模仿着Oracle写的,没法使用,在ABAP里写Oracle的HINT就很容易,因为语法和Oracle里的基本一样,对比之下Oracle的文档就丰富许多.(黝黑18摸)

*%_HINTS DB2 'USE VALUES FOR OPTIMIZATION'
*DB2 'INDEX("MKPF" "MKPF~BUD")'.

SAP的F1 文档很烂,在这一块基本没什么说明,如此大的几家厂商,一起融洽的合作就那么困难吗??稍微麻烦的点的东西就undocument
,太让人气愤..这个时候我甚至想到把问题发msg给SAP.

多次测试之后,以瞎猫碰上死老鼠的方式…

发现USE_OPLEVEL这个参数起到了效果,原来是

WITH UR -- OPTLEVEL( 10 )
-- QUERY_DEGREE( 1 ) -- LOCATION( ZCOR0015_1 , 125 ) -- SYSTEM( SDX , SAPPRD )'

这个10级的OPTLEVEL,起到了影响.

这个参数是可以对应到DB2里的.不明白为什么SAP默认要强制送给DB2这个参数??而且SAP默认安装的时候DB2数据库的这个参数值为5 ,也不知道从哪里可以改变SAP的这个默认级别.

无论你在数据库层面更改这个值, ABAP程序送出SQL时总会是带上--
OPTLEVEL( 10 )
的 ,有点类似于 基于session更改参数的概念. 不影响整体参数.

这时快要水落石出了,解决它有2种途径:

1、更改&SUBSTITUTE VALUES&对于 SAP 内核版本
4.6,这个参数需要把 SAP 配置参数 dbs/db6/dbsl_substitute_literals
设置为 1 。这个参数使在 ABAP 语句中的所有输入值都被作为 SQL 语句文本的文字实现。就像 &SUBSTITUTE LITERALS&,DB2 优化器可以使用关于涉及表中的分布信息。这个基本同等于Oracle理解的绑定变量,如果设置了这个值的话,SAP送给DB2的SQL就是完整的,带有”字面值”的,那么我相信执行计划也一定会是正确的,不过修改这个SAP配置参数的评估已不在我目前的工作范围内了.

2、在ABAP程序里加上提示DB6 'USE_OPTLEVEL 0'.

我现在在DB2里测试下这个级别0,与10的区别

在数据库里对应这个SAP的参数是DFT_QUERYOPT

(在DB2里为0,1,2,3,5,7,9,但是不明白为什么SAP里有10级…咳咳,不知道这是怎么对应上的,反正只能靠猜测了):
在session端更改DFT_QUERYOPT(db cfg级别), 默认为5
譬如SQL:set current query optimization = 5

数据库里最大值为9,SAP里最大值为10.最小值都为0

    Set current query optimization =9;
SELECT T_00."MATNR", T_01."MBLNR", T_00."BWART", T_01."BUDAT",
T_00."WERKS", T_00."BUKRS", T_00."MENGE", T_01."MJAHR",
T_00."AUFNR", T_00."SHKZG"
FROM SAPPRD."MSEG" T_00 INNER JOIN SAPPRD."MKPF" T_01 ON
T_01."MANDT"=?
AND T_01."MANDT"= T_00."MANDT"
AND T_01."MBLNR"= T_00."MBLNR"
AND T_01."MJAHR"= T_00."MJAHR"
WHERE
T_00."MANDT"=? AND
T_01."BUDAT" BETWEEN ? AND ? AND
T_00."MATNR" BETWEEN ? AND ?
WITH UR;
以下为执行计划

烂的一塌糊涂,还是hash join, 而且也走的错误的索引,不是我想要的执行计划.

难怪ABAP送出的SQL与我相同,但是执行计划不同,导致性能并且很慢的原因就在这里.

改为0级别,再测试一次.

set current query optimization = 0;

这次的执行计划正确了!!

4.结果

在之前所创建的索引下,

套用到ABAP程序底部,加个HINT

    select
MSEG~matnr
MKPF~mblnr
MSEG~bwart
* b~aufnr
MKPF~budat
MSEG~WERKS
MSEG~bukrs
MSEG~menge
MKPF~mjahr
MSEG~aufnr
MSEG~SHKZG
INTO CORRESPONDING FIELDS OF TABLE g_t_result
from MSEG AS MSEG INNER JOIN MKPF as MKPF
on MKPF~MANDT = MSEG~MANDT
AND MKPF~MBLNR = MSEG~MBLNR
AND MKPF~MJAHR = MSEG~MJAHR
WHERE
* a~budat in s_budat AND
MKPF~BUDAT BETWEEN '' AND ''and
MSEG~MATNR BETWEEN ''and''
%_HINTS DB6 'CONVERT_FAE_TO_CTE'
DB6 'USE_OPTLEVEL 0'.

其实让DB2查询优化器,自己分析出来的执行计划我还是很放心的,但是在SAP里解析后的程序,添油加醋后 再给DB2, 这是完全不同的东西,很让我失望

MKPF~BUDAT BETWEEN '20090101' AND '20090105'  and
       MSEG~MATNR BETWEEN '000000000010000000' and '000000000019999999'

调整过后的速度非常快,与我预料的一样,类似上面这样的5天范围的数据查询,把数据返回到内表里,连1秒钟都不需要.

MKPF~BUDAT BETWEEN '20090101' AND '20090201'  and
       MSEG~MATNR BETWEEN '000000000010000000' and '000000000019999999'

一个月的数据返回到内表里,大致5~10秒.

MKPF~BUDAT BETWEEN '20090101' AND '20090701'  and
       MSEG~MATNR BETWEEN '000000000010000000' and '000000000019999999'

半年的数据返回到内表,不到1分钟

我本来以为数据库层面的问题已经完全解决了,但是这里又再出出了问题,其实在测试阶段出问题倒挺好的,做到全面的测试,把问题都扼杀在测试阶段..省得到时候部署到生产系统之后再出乱子.

2010-7-29,今天发现程序变得异常缓慢,与昨天的不一样,我调整了下优化级别为0,然后到DB2里看看执行计划.

    set current query optimization =0;
SELECT T_00."MATNR", T_01."MBLNR", T_00."BWART", T_01."BUDAT",
T_00."WERKS", T_00."BUKRS", T_00."MENGE", T_01."MJAHR",
T_00."AUFNR", T_00."SHKZG"
FROM SAPPRD."MSEG" T_00 INNER JOIN SAPPRD."MKPF" T_01 ON
T_01."MANDT"=?
AND T_01."MANDT"= T_00."MANDT"
AND T_01."MBLNR"= T_00."MBLNR"
AND T_01."MJAHR"= T_00."MJAHR"
WHERE
T_00."MANDT"=? AND
T_01."BUDAT" BETWEEN ? AND ? AND
T_00."MATNR" BETWEEN ? AND ?
WITH UR;

真奇怪, 又用回MKPF~0索引了,真的有够烂,不稳定的执行计划是不可能放入生产环境使用的,看来还是要彻底的去解决这个问题.

假设 : 每次ABAP层面发送SQL语句给DB2的时候都是发送的字面值,而不是类似 “MANDT=?”这样的问号,那么这时数据库的CBO就会根据统计信息生成最优的执行计划。

(虽然每次发送字面值,都会让数据去解析执行计划,会造成执行计划不共享,带来一小部分CPU开销,但是我认为是值得的,因为是报表程序(OLAP应用),正确的执行计划显得非常重要,并且这个CPU开销是十分小的,对比这个报表的消耗时间来说,基本可以忽略掉了)

如果把ABAP对SQL语句造成的影响降到最低,那么就是发送字面值了(字面值的意思就是类似 “MANDT=900”这样的程序).

以下的公式是成立的:

SQL发送字面值+正确稳定的统计信息+合理的索引 ≈ 最优的执行计划 ≈ 最优的速度

 

这时候想办法让ABAP发送字面值吧

1.   开始想到了改 SAP 配置参数 dbs/db6/dbsl_substitute_literals 设置为 1 ,这样SAP系统发送的全部SQL语句都是字面值..

可惜我没找到相关的参数,网上的资料说这个参数是4.6版本的,新版本的找不到了,但是却可以找到对应Oracle和MSSQL的参数.(再次晕倒..)

2.   在ABAP程序里增加 %_HINT来强制 程序发送字面值,

WHERE
      MKPF~BUDAT BETWEEN '20090101' AND '20090201'  and
      MSEG~MATNR BETWEEN '000000000010000000' and '000000000019999999'
    %_HINTS
      DB6 'CONVERT_FAE_TO_CTE'
      DB6 'USE_OPTLEVEL 0'
      DB2 '&SUBSTITUTE LITERALS&'
      DB6 '&SUBSTITUTE LITERALS&'
      DB2 '&SUBSTITUTE VALUES&'
      DB6 '&SUBSTITUTE VALUES&'.

经过测试,程序速度很快 10秒内数据就返回到内表了 : ) 估计发送了字面值,DB2的执行计划已经正确,但是为了严谨,我还是要验证一下.

select * from sysibmadm.TOP_DYNAMIC_SQL where stmt_text like '% FROM
"MKPF" T_00 INNER JOIN "MSEG" T_01 %' order by AVERAGE_EXECUTION_TIME_S;

经查询,字面值已经传入数据库.这样子,执行计划就是正确的了!

只要保证ABAP报表程序传入的是字面值,并且数据库端的索引是合理的,并且数据库的统计信息是正确的话, 就会拥有稳定的执行计划,以及最优的执行效率!

至此数据库层面的优化基本结束,这才是数据库真正的威力。
接着放到测试环境里测试,发现ABAP程序里还是消耗了10分钟(这时数据库的消耗只有5秒),
进行跟踪发现瓶颈在2万多数据量的内表嵌套LOOP部分.导致的性能低下。
这时与吴恒取得联系,让他给予一些关于嵌套LOOP的优化思路.然后我们这边的开发人员迅速做出了响应,不断的更改测试,更改测试,最后取得了非常好的效果!!!

以下为开发人员做的一些优化记录,经过这段时间的折腾,我们的开发人员能力也得到了提升,懂得如何撰写性能良好的程序 : )

SAP系统 ABAP 层面的性能优化。

在sap中进行abap编程时候会不可避免的遇到循环嵌套,在本着尽量少的访问数据库时,将数据多放在内存中处理,提高数据的处理速度。一般不建议使用loop嵌套循环,特别是针对数据量大时,体现的尤为明显。尽量在通过READ TABLE来读取第二张内表中的数据,再进行数据逻辑的处理,这样子在取数性能上可以大大提高效率。
下面我们就拿取一个月的数据时,所用到的两个逻辑取数耗时上的对比:
一、使用LOOP循环嵌套取数。
1、语法:

    LOOP AT g_t_out.
LOOP AT g_t_result WHERE matnr = g_t_out-matnr_i .
IF g_t_result-bwart =''.
g_t_out-DDCHS = g_t_out-DDCHS + g_t_result-menge.
ELSEIF g_t_result-bwart =''.
g_t_out-CXDDS = g_t_out-CXDDS + g_t_result-menge.
ELSEIF g_t_result-bwart =''.
g_t_out-GYSTH = g_t_out-GYSTH + g_t_result-menge.
……………
ENDLOOP.
modify g_t_out.
CLEAR g_t_out.
ENDLOOP.

2、耗用时间(如下图):

通过 LOOP循环嵌套取09年1月份的数据耗时为784秒

二、使用read table… with key 取数。
1、语法:

    sort g_t_out by matnr_i auart budat mblnr_i.
sort g_t_collect by matnr_i auart budat mblnr.
LOOP AT g_t_out.
read table g_t_collect With key matnr_i = g_t_out-matnr_i bwart_i ='' BINARY SEARCH.
if sy-subrc =.
g_t_out-DDCHS = g_t_out-DDCHS + g_t_collect-menge_i.
endif.
read table g_t_collect With key matnr_i = g_t_out-matnr_i bwart_i ='' BINARY SEARCH.
if sy-subrc =.
g_t_out-CXDDS = g_t_out-CXDDS + g_t_collect-menge_i.
endif.
read table g_t_collect With key matnr_i = g_t_out-matnr_i bwart_i ='' BINARY SEARCH.
if sy-subrc =.
g_t_out-GYSTH = g_t_out-GYSTH + g_t_collect-menge_i.
endif.
modify g_t_out.
CLEAR g_t_out.
ENDLOOP.
 

2、耗用时间(如下图):

使用READ TABLE取09年1月份的数据耗时为19秒
通过以上两种方法进行比较,第一种方法取同一月的数据要784秒,而第二种取同一月的数据只要19秒。显然采用第二种方法取数在效率上要远远优于第一种方法。

5.总结

这次的调优的总体难度对比以往在MIS MES上的Oracle,SQLServer来说并不算很难(单纯考虑数据库层面的对比),

但是对SAP的一些内部机制不够了解,对DB2的陌生……导致消耗了大量的时间在反复测试和阅读文档上,

途中找瓶颈点时还折腾了AIX,怀疑操作系统配置,改动了SAP参数,数据库参数,怀疑存储性能,把所有可能的环节全都怀疑了一遍, 把熬工,刘工等人也折腾得不行了,ABAP开发人员也配合一起做了大量的更改+测试..

总体来讲,调优还是需要对整体应用系统涵盖数据库,后台操作系统,存储等等..有全面的了解

只有全方位的了解应用系统,以及数据库才能快速的定位出问题根源,

否则只能是铺天盖地的寻找瓶颈点头痛医头脚痛医脚,甚至像我一样到最后依靠瞎猫碰死老鼠的招式,不过能解决问题仍然是很高兴的,

与大家分享之 : )

6.参考文档

DB2 最佳实践: 编写并调优查询语句以优化性能最佳实践

http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0909querytuning/

SAP官方联机丛书

IBM DB2官方联机丛书

2010-7-28 @LDK xinyu

SAP+DB2 糟糕的报表查询『ZCOR0015』 优化全程记录的更多相关文章

  1. 『IOS』 遇到问题记录(长期更新)

    遇到的很多问题,解决后都是自己记着,以为不会忘记,之后却会想不起来了. 所以把今后解决的问题记录在这. 一. 在二级页面设置了CAlayer的代理,在返回一级页面报错: EXC_BAD_ACCESS( ...

  2. SAP MM 按采购订单查询付款信息的报表?

    SAP MM 按采购订单查询付款信息的报表? 上午给P3项目采购部门用户做了一个采购相关的报表的培训.培训过程中,客户的采购部门经理提出了一个问题:有没有报表能查询到各个采购订单的付款情况,显示采购订 ...

  3. [原创]java WEB学习笔记90:Hibernate学习之路-- -HQL检索方式,分页查询,命名查询语句,投影查询,报表查询

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  4. 用excel打造报表查询系统

    网络数据库以及ERP在中小型企业中日益风行,虽然ERP功能强大,但有的ERP报表系统中规范的报表较少,主要提供二次开发接口或通过如CRYSTALREPORT等其他报表工具进行管理,其实我们可以使用Ex ...

  5. SNF开发平台WinForm-EasyQuery统计分析-效果-非常牛逼的报表查询工具

    无论是单轴曲线 .双轴曲线 .柱形图 .饼图 .雷达图 .仪表图.图表引擎全能为您轻松实现.您只需要 3 步操作(数据源准备,设计图表,挂接到您想要展示的位置)便可完成 BI 的设计. 无论是普通报表 ...

  6. 『备忘录』elasticsearch 去重分页查询

    一开始数据结构设计的很复杂,又是父子关系又是嵌套关系,结果发现不能通过简单的查询得到想要的结果:比如一个商店只出现一件符合条件的商品,弄得查询语句就变成这样了 curl -XPOST http://l ...

  7. INPUT和CONSTRUCT指令——范例报表查询,作用让用户输入数据,自动生成SQL的WHERE条件,带开窗查询

    INPUT指令 说明:1. 当程序执行到INPUT指令时,会将控制权交给用户,让用户输入数据.2. 用户输入完字段的数据,会将数据回传给程序中的变量接收.3. 只要执行到INPUT的指令,程序会将每个 ...

  8. 『片段』OracleHelper (支持 多条SQL语句)

    C# 调用 Oracle 是如此尴尬 >System.Data.OracleClient.dll —— .Net 自带的 已经 过时作废. >要链接 Oracle 服务器,必须在 本机安装 ...

  9. [日推荐] 『Streeter』极乐商店邀你一起来尬舞啊!-store.dreawer.com

    你听的舞蹈有哪些?Jazz?Poppin?Hiphop?现代舞?民族舞?... 今天推荐一款小程序『Streeter』,几乎包含所有舞蹈视频,偷偷学好了,邀请你来尬舞啊 Streeter 这个Logo ...

随机推荐

  1. vim(三)golang代码跳转配

    在golang的代码里跳来跳去.... godef 安装 跳转是通过godef实现,godef的安装目录一般是$GOBIN,只要让godef命令在$PATH下即可 godef 命令安装: go get ...

  2. 【网络】CCNA实验一:Vlan、Trunk

    要求: 1:不同楼层物理隔离,但逻辑相连 2:相同楼层物理相连,但逻辑隔离 3:主机可以动态获取IP地址 4:不同VLAN间可以进行通信 5:主机最终访问www.esafenet.com弹出" ...

  3. lnmp 优化

    一,版本信息优化 重启 直接更改版本号: 在源码包里改 第二个要改的地方 第三个需要更改的 改完后编译安装,下次我直接写进编译脚本上

  4. JavaScript设计模式(二) - 单例模式

    什么是单例模式? 单例模式从字面上的理解是不困难的,js上就是指只有一个对象实例. 为什么需要单例模式? 我们可以将一些成员变量封装在一个单例对象中,每次访问这些变量都只能从这个单例对象进行访问,这样 ...

  5. hadoop面试题一

    1.hadoop运行的原理?xxxxxx 2.mapreduce的原理?xxxxxx 3.HDFS存储的机制?xxxxxx 4.举一个简单的例子说明mapreduce是怎么来运行的 ?xxxxxx 5 ...

  6. VRRP协议介绍--转

    http://www.cnblogs.com/jony413/articles/2697404.html VRRP协议介绍 参考资料: RFC 3768 1. 前言 VRRP(Virtual Rout ...

  7. FFmpegInterop 库在 Windows 10 应用中的编译使用

    FFmpegInterop 简介 FFmpegInterop 是微软推出的封装 FFmpeg 的一个开源库,旨在方便在 Windows 10.Windows 8.1 以及 Windows Phone ...

  8. js数组与字符串相互转换

    一.数组转字符串(将数组元素用某个字符连接成字符串) var a, b;a = new Array(0,1,2,3,4);b = a.join("-"); 二.字符串转数组(将字符 ...

  9. 百度云BCC 上的Ubuntu 16.04 LTS - 升级内核到4.14.87

    99元1年,整来玩玩. =============================================================== 重点是这个libssl1.1的deb,安装上了之 ...

  10. [LeetCode]27. Remove Element移除元素

    Given an array nums and a value val, remove all instances of that value in-place and return the new ...