如何从SQL查询创建大型pandas数据框而不会耗尽内存?

sli*_*izb 35 python sql bigdata pandas

我无法从MS SQL Server数据库查询大于500万条记录的表.我希望能够选择所有记录,但在选择大量数据到内存时,我的代码似乎失败了.

这有效:

import pandas.io.sql as psql
sql = "SELECT TOP 1000000 * FROM MyTable" 
data = psql.read_frame(sql, cnxn)
Run Code Online (Sandbox Code Playgroud)

...但这不起作用:

sql = "SELECT TOP 2000000 * FROM MyTable" 
data = psql.read_frame(sql, cnxn)
Run Code Online (Sandbox Code Playgroud)

它返回此错误:

File "inference.pyx", line 931, in pandas.lib.to_object_array_tuples
(pandas\lib.c:42733) Memory Error
Run Code Online (Sandbox Code Playgroud)

我在这里读到,从csv文件创建数据帧时存在类似的问题,并且解决方法是使用'iterator'和'chunksize'参数,如下所示:

read_csv('exp4326.csv', iterator=True, chunksize=1000)
Run Code Online (Sandbox Code Playgroud)

是否有类似的SQL数据库查询解决方案?如果没有,首选的解决方法是什么?我是否需要通过其他方法读取块中的记录?我在这里阅读了一些关于在pandas中处理大型数据集的讨论,但执行SELECT*查询似乎需要做很多工作.当然有一种更简单的方法.

ksi*_*ndi 43

正如评论中提到的,从pandas 0.15开始,你有一个chunksize选项read_sql来读取和处理chunk的查询块:

sql = "SELECT * FROM My_Table"
for chunk in pd.read_sql_query(sql , engine, chunksize=5):
    print(chunk)
Run Code Online (Sandbox Code Playgroud)

参考:http://pandas.pydata.org/pandas-docs/version/0.15.2/io.html#querying

  • 任何依赖使用chunksize选项的人都应首先阅读https://github.com/pandas-dev/pandas/issues/12265.对于许多数据库,在返回迭代器之前,整个数据集仍将被整体读入内存.对于某些数据库,适当地设置连接选项可以解决此问题 - 例如使用Postgres,在创建引擎时设置execution_options = {'stream_results':True} ... (24认同)
  • 这不会节省内存 - 它会拉下整个表格,然后将其整理好. (8认同)
  • **这是处理 RAM 大小 < db_you_wish_to_load 大小的问题的方法** (2认同)
  • 查看 Janak Mayer 链接的最后一条评论 (2认同)
  • @JanakMayer 在设置 `stream_results` 时还需要指定 `chunksize` 吗? (2认同)

The*_*ist 35

更新:请务必查看下面的答案,因为Pandas现在已经内置了对分块加载的支持.

您可以简单地尝试以块为单位读取输入表,然后从各个部分组装完整的数据帧,如下所示:

import pandas as pd
import pandas.io.sql as psql
chunk_size = 10000
offset = 0
dfs = []
while True:
  sql = "SELECT * FROM MyTable limit %d offset %d order by ID" % (chunk_size,offset) 
  dfs.append(psql.read_frame(sql, cnxn))
  offset += chunk_size
  if len(dfs[-1]) < chunk_size:
    break
full_df = pd.concat(dfs)
Run Code Online (Sandbox Code Playgroud)

整个数据帧可能太大而无法容纳在内存中,在这种情况下,除了限制您选择的行数或列数之外,您没有其他选择.

  • 您也可以将这些df写入HDF5文件(您引用的问题使用该文件,也请仔细阅读文档,附加表格:http://pandas.pydata.org/pandas-docs/dev/io.html#hdf5-pytables.然后回读(部分,或根据需要迭代); HDF5比数据的SQL更紧凑 (3认同)

fly*_*our 10

代码解决方案和备注。

# Create empty list
dfl = []  

# Create empty dataframe
dfs = pd.DataFrame()  

# Start Chunking
for chunk in pd.read_sql(query, con=conct, ,chunksize=10000000):

    # Start Appending Data Chunks from SQL Result set into List
    dfl.append(chunk)

# Start appending data from list to dataframe
dfs = pd.concat(dfl, ignore_index=True)
Run Code Online (Sandbox Code Playgroud)

但是,我的内存分析告诉我,即使在提取每个块后释放内存,列表也会越来越大并占用该内存,导致可用 RAM 净净无增益。

很想听听作者/其他人怎么说。