【问题标题】:Pandas SQL chunksizePandas SQL 块大小
【发布时间】:2015-10-28 13:15:01
【问题描述】:

这更像是一个关于理解而不是编程的问题。 我对 Pandas 和 SQL 很陌生。我正在使用 pandas 从具有特定块大小的 SQL 中读取数据。 当我运行 sql 查询时,例如 将熊猫导入为 pd

df = pd.read_sql_query('select name, birthdate from table1', chunksize = 1000)

我不明白的是,当我不给出块大小时,数据存储在内存中,我可以看到内存在增长,但是,当我给出块大小时,内存使用率并没有那么高。

我拥有的是这个 df 现在包含许多我可以访问的数组

for df_array in df:
    print df.head(5)

我不明白的是,如果 SQL 语句的整个结果都保存在内存中,即 df 是一个携带多个数组的对象,或者这些数组是否像指向由 SQL 查询创建的临时表的指针。

我很高兴能对这个过程的实际运作方式有所了解。

【问题讨论】:

    标签: python sql-server pandas chunks


    【解决方案1】:

    让我们考虑两个选项,以及在这两种情况下会发生什么:

    1. chunksize 为无(默认值):
      • pandas 将查询传递给数据库
      • 数据库执行查询
      • pandas 检查并发现 chunksize 为 None
      • pandas 告诉数据库它想一次接收结果表的所有行
      • 数据库返回结果表的所有行
      • pandas 将结果表存储在内存中,并将其包装到数据帧中
      • 现在您可以使用数据框了
    2. chunksize 在非无:
      • pandas 将查询传递给数据库
      • 数据库执行查询
      • pandas 检查并发现 chunksize 有一些价值
      • pandas 创建一个查询迭代器(通常的 'while True' 循环会在数据库表示没有更多数据时中断),并在您每次需要结果表的下一个块时对其进行迭代
      • pandas 告诉数据库它想要接收 chunksize 行
      • 数据库从结果表中返回下一个块大小的行
      • pandas 将下一个 chunksize 行存储在内存中并将其包装到数据帧中
      • 现在您可以使用数据框了

    更多细节你可以看pandas\io\sql.py模块,它有据可查

    【讨论】:

    • 注意,正如@joris 的回答中提到的,many database drivers already put all data into memory in the execute step。所以在很多情况下,chunksize 对内存使用没有多大帮助。
    【解决方案2】:

    当您不提供chunksize 时,查询的完整结果会立即放入数据框中。

    当您提供chunksize 时,read_sql_query 的返回值是多个数据帧的迭代器。这意味着您可以像这样迭代:

    for df in result:
        print df
    

    在每个步骤中,df 是一个数据框(不是数组!),它保存了部分查询的数据。请参阅相关文档:http://pandas.pydata.org/pandas-docs/stable/io.html#querying

    要回答有关内存的问题,您必须知道从数据库中检索数据有两个步骤:executefetch
    首先执行查询 (result = con.execute()),然后从该结果集中获取数据作为元组列表 (data = result.fetch())。获取时,您可以指定一次要获取的行数。当您提供 chunksize 时,这就是 pandas 所做的。
    但是,许多数据库驱动程序已经在执行步骤中将所有数据放入内存中,而不仅仅是在获取数据时。所以在这方面,它对内存应该没有多大关系。除了将数据复制到 DataFrame 中这一事实之外,仅在使用 chunksize 进行迭代时发生在不同的步骤中。

    【讨论】:

      【解决方案3】:

      当您有大量查询时,它基本上可以阻止您的服务器内存不足。

      输出到 CSV

      for chunk in pd.read_sql_query(sql , con, chunksize=10000):
          chunk.to_csv(os.path.join(tablename + ".csv"), mode='a',sep=',',encoding='utf-8')
      

      或到镶木地板

      count = 0
      folder_path = 'path/to/output'
      
      for chunk in pd.read_sql_query(sql , con, chunksize=10000):
          file_path = folder_path + '/part.%s.parquet' % (count)
          chunk.to_parquet(file_path, engine='pyarrow')
          count += 1
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-19
        • 1970-01-01
        • 1970-01-01
        • 2021-02-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多