首页 > 解决方案 > 使用 glob 读取 csv 文件以将数据传递到数据库非常慢

问题描述

我有很多 csv 文件,我正在尝试将它们包含的所有数据传递到数据库中。出于这个原因,我发现我可以使用 glob 库来遍历我文件夹中的所有 csv 文件。以下是我使用的代码:

import requests as req
import pandas as pd
import glob
import json

endpoint = "testEndpoint"
path = "test/*.csv"

for fname in glob.glob(path):
    print(fname)

    df = pd.read_csv(fname)

    for index, row in df.iterrows():
        #print(row['ID'], row['timestamp'], row['date'], row['time'],
        #     row['vltA'], row['curA'], row['pwrA'], row['rpwrA'], row['frq'])

        print(row['timestamp'])

        testjson = {"data":
                        {"installationid": row['ID'],
                         "active": row['pwrA'],
                         "reactive": row['rpwrA'],
                         "current": row['curA'],
                         "voltage": row['vltA'],
                         "frq": row['frq'],
                         }, "timestamp": row['timestamp']}

        payload = {"payload": [testjson]}
        json_data = json.dumps(payload)
        response = req.post(
            endpoint, data=json_data, headers=headers)

这段代码一开始似乎运行良好。然而,一段时间后它开始变得非常慢(我注意到这一点是因为我在上传数据时打印了时间戳)并最终完全停止。这是什么原因?我在这里做的事情真的低效吗?

标签: pythonpandascsvglob

解决方案


我可以在这里看到 3 个可能的问题:

  1. 记忆。read_csv速度很快,但它会将完整文件的内容加载到内存中。如果文件真的很大,你可能会耗尽真实内存并开始使用交换,它的性能很糟糕
  2. iterrows:您似乎构建了一个数据框-意味着针对按列访问优化的数据结构-然后按行访问它。这已经是一个坏主意,并且iterrows知道性能很糟糕,因为它为每行构建一个系列
  3. 每行一个帖子请求。http 请求有其自身的开销,但此外,这意味着您一次向数据库添加行。如果这是你的数据库唯一的接口,你可能别无选择,但你应该搜索是否可以准备一堆行并作为一个整体加载。它通常提供超过一个数量级的增益。

如果没有更多信息,我几乎不能说更多,但是 IHMO 在数据库馈送中可以找到更高的增益,所以在第 3 点。如果在那一点上什么都做不了,或者如果需要进一步的性能提升,我会尝试替换 pandas使用面向行且占用空间有限的 csv 模块,因为无论文件大小如何,它一次只处理一行。

最后,如果它对您的用例有意义,我会尝试使用一个线程来读取 csv 文件,该文件将提供一个队列和一个线程池以向数据库发送请求。这应该允许获得 HTTP 开销。但请注意,根据端点实现,如果真的是数据库访问,如果限制因素,它不会有太大改善。


推荐阅读