生命在于折腾
分类: 架构设计与优化
2011-08-27 18:02:03
6, 将循环内的重复性工作进行缓冲
有时我们的内表数据量很大,但又不得不在每次循环的时候,都进行类似的一些操作,比如调用函数FI_PERIOD_DETERMINE获取某日期对应的会计年度和期间,调用函数MD_CONVERT_MATERIAL_UNIT进行单位转换,等等。每个函数的调用背后都要执行一系列的读表以及运算工作,程序的效率明显下降了。所以我们得想出有效的办法。
比如针对FI_PERIOD_DETERMINE的调用,可以改用循环前对函数G_PERIODS_OF_YEAR_GET的调用。根据公司代码BUKRS读取T001-PERIV,然后调用G_PERIODS_OF_YEAR_GET获取某会计年度每个会计期间对应的起始日期和结束日期。这样在循环内部,只要根据上面的结果即可算出某日期对应的会计年度和期间了。
又比如针对MD_CONVERT_MATERIAL_UNIT的调用。相信对于it_vbap的10万个行项目,物料号重复的有很多。所以可以先汇总物料号,然后一次性读取表MARM以存储换算关系。有了MARM的换算关系,循环中大量的单位换算就可以自己算了,如果无法换算的再考虑调用函数MD_CONVERT_MATERIAL_UNIT。(函数MD_CONVERT_MATERIAL_UNIT除了读取MARM的换算关系,还会考虑同一维度单位间的换算关系比如G和KG的关系,所以其功能更强大。)
7, 关于字段的增强以及TABLE INDEX的创建
这里提到字段的增强,主要是性能方面相关的。假设我们需要基于系统所有的billing document做个动作,比如将其导出到金税系统。至少有两种方案:第一是新建一个表,专门记录已经导出到金税的开票凭证;第二是在系统标准的开票凭证抬头表vbrk中新增一个字段,记录是否已导出到金税。
用户在处理业务的时候肯定会反复查询“未导出到金税”的所有开票凭证。那么第一种方案下,我们需要先查询VBRK表(比如得到1万条记录),然后针对自建表的记录(比如得到9800条记录)做个减法,最后得到200条记录的结果集。而第二种方案就快多了,查询VBRK的时候判断新字段=“未导出”即可。
随着业务的持续,VBRK表的条目将越来越多,而“未导出”的条目则会维持在一个较为平稳的数字上,为了有效区分历史数据和现用数据,可添加TABLE INDEX,提高报表的查询速度。很多SAP标准表都自带了一些索引,这些索引大都比较实用。
创建索引需要注意以下几点:
(1)索引会占用额外的数据库空间,还会降低插入/修改的速度(虽然可提高查询速度),所以需要考虑实用性,肯定不是越多越好。如果表中已有类似的索引,则不推荐新建。而对于容量大的、被多个程序访问的表加索引就更要谨慎了,比如VBFA、MSEG、FAGLFLEXA、LIPS、VBAP、EDIDC、STXH等等。
(2)创建索引时应注意字段的先后次序,MANDT是必须的而且都要放在第一位。字段的先后次序取决于实际业务需要。另外索引的字段不宜太多,字段越多占用的数据库空间就越多,对于插入/修改的影响也更大。
8, 选用一些替代表/替代字段(VBFA, SHP_IDX_)
曾做过一些类似于“未拣配交货单”、“未发货过账交货单”的报表,刚开始用的是LIKP、VBUK等表,速度并不理想。后来调试了标准程序VL06O,发现其用的表是SHP_IDX_PICK、SHP_IDX_GDSI等。原来系统在创建交货单的时候,也会更新这些临时表。当拣配完成,该条目就从SHP_IDX_PICK中删除。所以表SHP_IDX_PICK的条目数始终不多,查询速度很快。
同样的,当我们在多个表中进行查询时,可能不同的限制条件都能达到同样的结果集,但效率差异就很大,所以选用有效的字段非常关键。比如需要查询某销售组织某天已发货的销售订单,我们可以将VBAP与LIPS联查。此时查询条件VBAK-LIFSK=SPACE或VBAP-ABGRU=SPACE并不影响查询结果,但它们可以在第一时间就排除大量无关的订单,对于性能的提升帮助很大。
另外我们在查询时也可以适当考虑视图的使用,比如需要对LIKP和LIPS进行Inner Join时,可以查看LIKP的Where-used List,找到一个能满足要求的视图。
9,考虑企业的特点及数据量状况
做优化不是简单的技术活,既要考虑报表的实际需求,也要考虑企业的业务状况。比如有的企业客户量很大但物料号不多,有的企业则客户量较少但物料号多而繁杂。有些企业订单量很大、时间性很强,所以最有效的查询条件往往就是组织编码+日期,有些企业则可能订单量小但每份订单的价值都很高。只有充分考虑到企业的业务特点,开发报表时才能更有效地估算查询结果的数量级,从而提高报表性能。
【结束】