本来RFC性能好于WebService是毋庸置疑的,但是最近总有兄弟说WebService或者Restful性能好于RFC,于是有了此篇文章,以正视听。
首先,在确定的服务器、客户端,接口逻辑和数据量一定的前提下,RFC的性能主要取决与两个地方,一是内表放到Tables还是Export下面,二是RFC的序列化协议。
一般来说,如果协议是典型序列化器(Classic
Serializer),内表放到Export和放到Tables两者之间性能差别是非常大的,在检查RFC函数的时候,系统也会警告提示:
如果是其他协议,则放到哪儿都是一样的。
为了直观的对比各个场景的性能差异,我写了一个简单的对比程序,在同一个系统/不同系统、Export参数/Tables参数、不同序列化协议、不同数据量和调用次数,以及WebService的运行时间对比。
对比结果如下, 后面的数值是所用时间,单位为 微秒 :
首先是小数据量(100条)的单次调用
其次是大数据量(内表100000条)的单次调用
最后是小数据量(内表100条)的多次(100次)调用
需要说明的是,程序运行在S4,而远程系统是ECC6,ECC6是不支持快速序列化的,所以跨系统RFC的快速序列化并没有特别的快。
结论:
1、如果是用Classic协议,内表一定不要在Export,否则性能极差。
2、BasXML协议是需要转成XML来传输的,性能不是太好。
3、快速序列化是性能最好的,但是老系统不支持,S4开始支持,如果可能请尽量使用此序列化协议。
4、WebService性能不如RFC,小数据量且调用次数较少时可以使用。
5、Restful因为可以自定义传输数据的格式,方法不同性能差别也很大,所以就不做比较了,但是大概可以参考WebService的性能。
附 测试程序和函数:
REPORT ztestrfc NO STANDARD PAGE HEADING.
DATA: itab TYPE TABLE OF dd02l.DATA: ws_proxy TYPE REF TO zwsco_zget_dd02l.DATA: ws_input TYPE zwszget_dd02l.DATA: ws_respo TYPE zwszget_dd02lresponse.DATA: eoutab TYPE zwscnvmbt_dd02l_t, toutab TYPE zwstable_of_dd02l, initab TYPE zwsdd02l_tab WITH HEADER LINE.DATA: t1 TYPE i, t2 TYPE i.
PARAMETERS: p_dbcnt TYPE sy-dbcnt DEFAULT 3000.PARAMETERS: p_count TYPE i DEFAULT 1.AT SELECTION-SCREEN OUTPUT. %_p_dbcnt_%_app_%-text = '内表条数'. %_p_count_%_app_%-text = '连续调用次数'.
START-OF-SELECTION. WRITE: '内表条目数:',p_dbcnt. WRITE: / '调用次数:',p_count. SKIP.
GET RUN TIME FIELD t1. DO p_count TIMES. CLEAR itab[]. CALL FUNCTION 'ZGET_DD02L' EXPORTING dbcnt = p_dbcnt param = 'E' IMPORTING eoutab = itab. ENDDO. GET RUN TIME FIELD t2. t1 = t2 - t1. WRITE: /(30)'正常函数调用Export:', t1.
GET RUN TIME FIELD t1. DO p_count TIMES. CLEAR itab[]. CALL FUNCTION 'ZGET_DD02L' EXPORTING dbcnt = p_dbcnt param = 'T' TABLES toutab = itab. ENDDO. GET RUN TIME FIELD t2. t1 = t2 - t1. WRITE: /(30)'正常函数调用Table:', t1.***RFC Classic序列化器 SKIP. WRITE '本系统RFC' COLOR 1. GET RUN TIME FIELD t1. DO p_count TIMES. CALL FUNCTION 'RFC_CONNECTION_CLOSE' EXPORTING destination = 'DS4_185_C' EXCEPTIONS destination_not_open = 1.
CLEAR itab[]. CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_C' EXPORTING dbcnt = p_dbcnt param = 'E' IMPORTING eoutab = itab. ENDDO. GET RUN TIME FIELD t2. t1 = t2 - t1. WRITE: /(30)'Classic序列化器 Export:', t1.GET RUN TIME FIELD t1. DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE' EXPORTING destination = 'DS4_185_C' EXCEPTIONS destination_not_open = 1.
CLEAR itab[]. CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_C' EXPORTING dbcnt = p_dbcnt param = 'T' TABLES toutab = itab. ENDDO. GET RUN TIME FIELD t2. t1 = t2 - t1. WRITE: /(30)'Classic序列化器 Table:', t1.***BasXML SKIP. GET RUN TIME FIELD t1. DO p_count TIMES. CALL FUNCTION 'RFC_CONNECTION_CLOSE' EXPORTING destination = 'DS4_185_B' EXCEPTIONS destination_not_open = 1.
CLEAR itab[]. CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_B' EXPORTING dbcnt = p_dbcnt param = 'E' IMPORTING eoutab = itab. ENDDO. GET RUN TIME FIELD t2. t1 = t2 - t1. WRITE: /(30)'BasXML Export:', t1.GET RUN TIME FIELD t1. DO p_count TIMES. CALL FUNCTION 'RFC_CONNECTION_CLOSE' EXPORTING destination = 'DS4_185_B' EXCEPTIONS destination_not_open = 1.
CLEAR itab[]. CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_B' EXPORTING dbcnt = p_dbcnt param = 'T' TABLES toutab = itab. ENDDO. GET RUN TIME FIELD t2. t1 = t2 - t1. WRITE: /(30)'BasXML Table:', t1.***强制BasXML序列化器 SKIP. GET RUN TIME FIELD t1. DO p_count TIMES. CALL FUNCTION 'RFC_CONNECTION_CLOSE' EXPORTING destination = 'DS4_185_O' EXCEPTIONS destination_not_open = 1.
CLEAR itab[]. CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_O' EXPORTING dbcnt = p_dbcnt param = 'E' IMPORTING eoutab = itab. ENDDO. GET RUN TIME FIELD t2. t1 = t2 - t1. WRITE: /(30)'强制BasXML Export:', t1.GET RUN TIME FIELD t1. DO p_count TIMES. CALL FUNCTION 'RFC_CONNECTION_CLOSE' EXPORTING destination = 'DS4_185_O' EXCEPTIONS destination_not_open = 1.
CLEAR itab[]. CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_O' EXPORTING dbcnt = p_dbcnt param = 'T' TABLES toutab = itab. ENDDO. GET RUN TIME FIELD t2. t1 = t2 - t1. WRITE: /(30)'强制BasXML Table:', t1.***快速序列化器 SKIP. GET RUN TIME FIELD t1. DO p_count TIMES. CALL FUNCTION 'RFC_CONNECTION_CLOSE' EXPORTING destination = 'DS4_185_F' EXCEPTIONS destination_not_open = 1.
CLEAR itab[]. CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_F' EXPORTING dbcnt = p_dbcnt param = 'E' IMPORTING eoutab = itab. ENDDO. GET RUN TIME FIELD t2. t1 = t2 - t1. WRITE: /(30)'快速序列化器 Export:', t1.GET RUN TIME FIELD t1. DO p_count TIMES. CALL FUNCTION 'RFC_CONNECTION_CLOSE' EXPORTING destination = 'DS4_185_F' EXCEPTIONS destination_not_open = 1.
CLEAR itab[]. CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_F' EXPORTING dbcnt = p_dbcnt param = 'T' TABLES toutab = itab. ENDDO. GET RUN TIME FIELD t2. t1 = t2 - t1. WRITE: /(30)'快速序列化器 Table:', t1.***不同系统 ClassicRFC SKIP. WRITE '跨系统RFC' COLOR 1.
***Classic GET RUN TIME FIELD t1. DO p_count TIMES. CALL FUNCTION 'RFC_CONNECTION_CLOSE' EXPORTING destination = 'HSD_125_C' EXCEPTIONS destination_not_open = 1.
CLEAR itab[]. CALL FUNCTION 'ZGET_DD02L' DESTINATION 'HSD_125_C' EXPORTING dbcnt = p_dbcnt param = 'E' IMPORTING eoutab = itab. ENDDO. GET RUN TIME FIELD t2. t1 = t2 - t1. WRITE: /(30)'Classic序列化器 Export:', t1.GET RUN TIME FIELD t1. DO p_count TIMES. CALL FUNCTION 'RFC_CONNECTION_CLOSE' EXPORTING destination = 'HSD_125_C' EXCEPTIONS destination_not_open = 1.
CLEAR itab[]. CALL FUNCTION 'ZGET_DD02L' DESTINATION 'HSD_125_C' EXPORTING dbcnt = p_dbcnt param = 'T' TABLES toutab = itab. ENDDO. GET RUN TIME FIELD t2. t1 = t2 - t1. WRITE: /(30)'Classic序列化器 Table:', t1.***BasXML SKIP.
...