公司SAP ERP系统为早年上的ECC6,到现在已经10多年了,SO行项目数1.3亿左右,数据库为Oracle,因为历史原因未做归档。
因为这个系统主要是营销系统在使用,所以SD的报表性能就尤为重要,但是原来实施公司写的代码很烂,非常烂!以其中一个发货状态的报表为例,原开发者遵循了JOIN不超过3个表的(狗屁)原则,通篇的
FOR ALL ENTRIES IN ,2019年的时候就因为性能不能满足需求优化过一次,改 FOR ALL ENTRIES IN为JOIN,
提效差不多二三十倍,暂时可以满足需求了。
近两年,随着数据量的增加和数据库性能的降低,又出现了一个报表运行几万秒的极端情况,至于运行几百秒的,比比皆是,已经影响了业务,优化迫在眉睫,于是又开始了第二轮优化工作。
以上为报表优化的背景。
本次优化的目标是90%的查询需要控制在2秒钟以内,最大查询时间不可以超过3分钟,也就是说原来需要几万秒的查询,需要控制在180秒以内。就当前的数据量和这个老态龙钟的系统来说,这是一个挑战,一个使用传统优化方式不能实现的挑战,所以本次优化毫无疑问又使用了以空间换时间的方案(怎么说了一个又?)。
所谓以空间换时间,就是在订单/交货的状态更新的时候,使用增强的方式把数据预先按照报表的格式存放到自定义表内,当然不是所有报表字段,只是一些关键字段即可,不然的话,速度虽然上去了,报表的扩展性就很差了。然后报表改为在这个自定义表取数,因为很多取数工作都已经在更新表的时候做了,所以性能可以大幅度提升。
考虑到数据量相对于传统的非内存数据库来说还是有点大,就跟业务部门组会讨论了一下数据范围的问题,得到的回复,大概就是3个月内的数据会查询的比较频繁,偶尔会查询一年前的数据,用来和当前数据做一个对比。两年前的数据就基本上不会再查询了。
于是具体方案设计如下:创建日期在三个月内的SO以及历史未完结的SO为热数据,单独存在一个自定义表ZTSO02,三个月前到三年内的已完结SO为冷数据,放到另一个自定义表ZTSO02H,三年之前的数据算是休眠数据,自定义表就不再存放了,如果真的有查询的需求,就使用老报表来查。
使用以空间换时间这种方案最大的问题是要保证自定义表数据和系统数据的一致性,以前使用这种方案的人,往往因为自定义表的数据错误很多,最后不得的做一个修正程序每天跑一次来修正,或者是干脆就废弃了这个方案。所以如何能够保证数据的正确性是需要第一位考虑的。在增强中把数据补全存储到自定义表中看起来是很简单的事情,但是当系统并发一增加,有些接口SO的创建、交货、过账一起做,甚至过账失败再删除交货、删除SO等等,这些都是在一瞬间完成,很多时候不能保证增强程序按照严格先后顺序执行,就很容易导致数据不一致了。
总体方案设计为:在SO、DN、Billing三个凭证保存的地方写增强,把涉及的SO存放到表ZTSO01,然后随即触发bgRFC,使用串行的方式把ZTSO01表内的SO根据报表逻辑补全数据,存放到热数据表ZTSO02,再然后每天会有一个JOB把ZTSO02表内的超期数据挪到冷数据表ZTSO02H(ZTSO02H和ZTSO02结构完全一样)。优化后的新报表主要在ZTSO02取数,然后辅以其他表内字段,根据报表选择屏幕日期判断是否需要在ZTSO02H取数。
下面是具体的方案设计,因为不是通用代码,就不贴具体代码了 自定义表ZTSO01:
ZTSO02/ZTSO02H(注意根据具体情况设置索引):
增强: 1、SO保存
函数ZTSD01_UPDATE_01
函数ZTSD01_UPDATE_04:
函数ZTSD01_UPDATE_02,红框为关键点
当然还需要一个数据初始化、差错、修正的程序
以上为优化工作的关键部分,后续根据自定义表写报表就非常简单了,不再赘述。 下面看下优化成果: 先是老程序的执行时间
新程序的执行时间:
再看执行时间最长记录 老程序:
新程序:
中位时间:
完美实现优化,而且是一劳永逸式的优化,以后数据库再增加也不会对报表有多大的影响了。 Perfect!