0

I have a python code here which goes into SAP using BAPI RFC_READ_TABLE, queries USR02 table and bring back the results. The input is taken from an excel sheet A column and the output is pasted in B column The code is running all fine. However, for 1000 records, it is taking 8 minutes approximately to run. Can you please help in optimizing the code? I am really new at python, managed to write this heavy code but now stuck at the optimization part.

It would be really great if this can run in 1-2 minutes max.

from pyrfc import Connection, ABAPApplicationError, ABAPRuntimeError, LogonError, CommunicationError
from configparser import ConfigParser
from pprint import PrettyPrinter
import openpyxl

ASHOST='***'
CLIENT='***'
SYSNR='***'
USER='***'
PASSWD='***'
conn = Connection(ashost=ASHOST, sysnr=SYSNR, client=CLIENT, user=USER, passwd=PASSWD)


try:

wb = openpyxl.load_workbook('new2.xlsx')
ws = wb['Sheet1']
for i in range(1,len(ws['A'])+1):
    x = ws['A'+ str(i)].value
    options = [{ 'TEXT': "BNAME = '" +x+"'"}]
    fields = [{'FIELDNAME': 'CLASS'},{'FIELDNAME':'USTYP'}]
    pp = PrettyPrinter(indent=4)
    ROWS_AT_A_TIME = 10
    rowskips = 0
    while True:
    
        result = conn.call('RFC_READ_TABLE', \
        QUERY_TABLE = 'USR02', \
        OPTIONS = options, \
        FIELDS = fields, \
        ROWSKIPS = rowskips, ROWCOUNT = ROWS_AT_A_TIME)         
        rowskips += ROWS_AT_A_TIME
        if len(result['DATA']) < ROWS_AT_A_TIME:
                break
    
    data_result = result['DATA']
    length_result = len(data_result)
    for line in range(0,length_result):
        a= data_result[line]["WA"].strip()
        wb = openpyxl.load_workbook('new2.xlsx')
        ws = wb['Sheet1']
        ws['B'+str(i)].value = a
        wb.save('new2.xlsx')

except CommunicationError:
    print("Could not connect to server.")
    raise
except LogonError:
    print("Could not log in. Wrong credentials?")
    raise
except (ABAPApplicationError, ABAPRuntimeError):
    print("An error occurred.")
    raise

EDIT : So here is my updated code. For now, I have decided to output the data on command line only. Output shows where is the time taken.

try:
    output_list = []
    wb = openpyxl.load_workbook('new3.xlsx')
    ws = wb['Sheet1']
    col = ws['A']
    col_lis = [col[x].value for x in range(len(col))]
    length = len(col_lis)
    for i in range(length):
        print("--- %s seconds Start of the loop ---" % (time.time() - start_time))
        x = col_lis[i]  
        options = [{ 'TEXT': "BNAME = '" + x +"'"}]
        fields = [{'FIELDNAME': 'CLASS'},{'FIELDNAME':'USTYP'}]
        ROWS_AT_A_TIME = 10
        rowskips = 0
        while True:
            result = conn.call('RFC_READ_TABLE', QUERY_TABLE = 'USR02', OPTIONS = options, FIELDS = fields, ROWSKIPS = rowskips, ROWCOUNT = ROWS_AT_A_TIME)         
            rowskips += ROWS_AT_A_TIME
            if len(result['DATA']) < ROWS_AT_A_TIME:
                break
        print("--- %s seconds in SAP ---" % (time.time() - start_time))
        data_result = result['DATA']
        length_result = len(data_result)
        for line in range(0,length_result):
            a= data_result[line]["WA"]
            output_list.append(a)
    print(output_list)  

enter image description here

4

2 回答 2

1

首先,我将时间标记放在代码的不同位置,并将其划分为功能部分(SAP 处理、Excel 处理)。

在分析时间后,我发现 Excel 编写代码消耗的运行时间最多,请考虑时间间隔:

16:52:37.306272 
16:52:37.405006 moment it was fetched from SAP
16:52:37.552611 moment it was pushed to Excel
16:52:37.558631 
16:52:37.634395 moment it was fetched from SAP
16:52:37.796002 moment it was pushed to Excel
16:52:37.806930
16:52:37.883724 moment it was fetched from SAP
16:52:38.060254 moment it was pushed to Excel
16:52:38.067235 
16:52:38.148098 moment it was fetched from SAP
16:52:38.293669 moment it was pushed to Excel
16:52:38.304640 
16:52:38.374453 moment it was fetched from SAP
16:52:38.535054 moment it was pushed to Excel
16:52:38.542004 
16:52:38.618800 moment it was fetched from SAP
16:52:38.782363 moment it was pushed to Excel
16:52:38.792336 
16:52:38.873119 moment it was fetched from SAP
16:52:39.034687 moment it was pushed to Excel
16:52:39.040712
16:52:39.114517 moment it was fetched from SAP
16:52:39.264716 moment it was pushed to Excel
16:52:39.275649 
16:52:39.346005 moment it was fetched from SAP
16:52:39.523721 moment it was pushed to Excel
16:52:39.530741  
16:52:39.610487 moment it was fetched from SAP
16:52:39.760086 moment it was pushed to Excel
16:52:39.771057   
16:52:39.839873 moment it was fetched from SAP
16:52:40.024574 moment it was pushed to Excel

如您所见,Excel 编写部分是 SAP 查询部分的两倍。

您的代码中的问题是您在每次循环迭代中打开/初始化工作簿和工作表,这会大大减慢执行速度并且是多余的,因为您可以从顶部重用工作簿变量。

另一个多余的事情是去除前导零和尾随零,这是非常多余的,因为 Excel 会自动为字符串数据执行此操作。

这种代码变体

try:
    wb = openpyxl.load_workbook('new2.xlsx')
    ws = wb['Sheet1']
    print(datetime.now().time())
    for i in range(1,len(ws['A'])+1):
        x = ws['A'+ str(i)].value
        options = [{ 'TEXT': "BNAME = '" + x +"'"}]
        fields = [{'FIELDNAME': 'CLASS'},{'FIELDNAME':'USTYP'}]
        ROWS_AT_A_TIME = 10
        rowskips = 0
        while True:  
            result = conn.call('RFC_READ_TABLE', QUERY_TABLE = 'USR02', OPTIONS = options, FIELDS = fields, ROWSKIPS = rowskips, ROWCOUNT = ROWS_AT_A_TIME)         
            rowskips += ROWS_AT_A_TIME
            if len(result['DATA']) < ROWS_AT_A_TIME:
                    break
        data_result = result['DATA']
        length_result = len(data_result)
        for line in range(0,length_result):
            ws['B'+str(i)].value = data_result[line]["WA"]
        wb.save('new2.xlsx')
    print(datetime.now().time())
except ...

给我以下程序运行的时间戳:

>>> exec(open('RFC_READ_TABLE.py').read())
18:14:03.003174
18:16:29.014373

1000 条用户记录需要 2.5 分钟,对于这种处理来说,这看起来是一个合理的价格。

于 2020-09-28T15:19:07.287 回答
0

在我看来,问题出在 while True 循环中。我认为您需要优化查询逻辑(或更改它)。不知道你对数据库感兴趣是很难的,其他的东西看起来简单快捷。

可能有所帮助的是尝试不连续打开和关闭文件:尝试计算您的“B”列,然后在 xlsx 文件中一次打开并粘贴所有内容。它可能会有所帮助(但我很确定这是问题所在)

PS也许你可以使用一些计时库(比如这里)来计算你大部分时间花在哪里。

于 2020-09-27T19:51:22.047 回答