最近因为碰到一个大量数据传输到 SAP 的场景,在个人的 ECC 虚拟机上做了一个数据导入到 SAP 并且从 SAP 导出的测试,本文是对测试过程要点的记录。

导入

测试场景:将 具有 4 列 500 万条数据导入到 zemployee 表,zemployee 表的结构:

通过 Python 第三方模块 faker 生成模拟数据,4 列数据以 csv 格式存储,文件体积为 350 M。

from faker import Faker
import random

fake = Faker(locale="zh_CN")
MAX_ROW = 5000000

def generate_random_info():    
    emp = {
        "name": fake.name(),
        "address":fake.address(),
        "phone":fake.phone_number()
    }

    return emp

if __name__ == "__main__":
    with open("fakeemployees.csv", mode="a", encoding="utf8") as f:
        for idx in range(0, MAX_ROW):
            info = generate_random_info()
            line = ",".join([str(idx+1), info.get("name"), info.get("address"), info.get("phone")])
            f.write(line+'\n')

一次性将所有这些数据导入到 SAP 是不合理的,所以我用分批的方式将这些数据导入,但也不是逐笔导入。在 SAP 中用 function module 实现数据的导入,一次传输导入的数据给 table 类型的参数,

创建一个 zemployee_insert 函数,employees 表参数为 importing 参数, ret 为返回值。


函数的代码如下:

zemployee_insert 允许远程调用,用 Python 的 PyRfc 模块来调用这个函数,不需要对文件进行分割,通过 Python 的 yield 关键字,实现数据分批。因为 yield 能在函数的调用者和函数之间反复交接控制权,减少内存的压力。每次以 1000 条为单位将数据传给 SAP zemployee_insert 函数。

from SAP.sap_systems import current_sap_connection

upload_file = "fakeemployees.csv"
batch_count = 1000

def get_data_from_file(batch_max):
    employees = []
    with open(upload_file, mode="r",encoding="utf8") as f:
        batch = 0
        for line in f:
            (id, name, addr, phone) = line.split(sep=",")
            employees.append({
                "MANDT": "001",
                "EMPID": id,
                "EMPNAME": name,
                "EMPADDR": addr,
                "PHONE": phone
            })
            batch += 1

            if batch == batch_max:
                yield employees
                employees =[]
                batch = 0
    if len(employees) > 0:
        yield employees

def insert_employee():
    sap_conn = current_sap_connection()
    for employees in get_data_from_file(batch_count):     
        rv = sap_conn.call("ZEMPLOYEE_INSERT", EMPLOYEES=employees)
        print(rv["RET"])

if __name__ == "__main__":
    insert_employee()

我的 ECC 虚拟机运行在个人笔记本上,运行 python 代码的过程中,内存占用不大,还可以一边愉快地做其它事情。

导出

如果想全部将这 500 万条数据导出到本地文件,我试过包括后台运行在内的几种方法,都失败了。所以我最后决定用 ABAP 代码实现分批式将数据导出到 application server,文件从服务器到本地就不是难事。sql 语句的 package size 关键字实现了数据的分批处理。

源码

github - bulk data upload and download

参考

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐