如何在不耗尽内存的情况下从sql查询创建大Pandas数据帧?

2024-04-24 19:04:19 发布

您现在位置:Python中文网/ 问答频道 /正文

从MS SQL Server数据库查询一个包含500万条记录的表时遇到问题。我想选择所有的记录,但我的代码在选择存储大量数据时似乎失败了。

这是有效的:

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

……但这不起作用:

sql = "SELECT TOP 2000000 * FROM MyTable" 
data = psql.read_frame(sql, cnxn)

它返回此错误:

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

我读到here从csv文件创建dataframe时存在类似问题,解决方法是使用如下“iterator”和“chunksize”参数:

read_csv('exp4326.csv', iterator=True, chunksize=1000)

有没有类似的从SQL数据库查询的解决方案?如果不是,你最喜欢的工作是什么?我应该用其他方法来读成块的记录吗?我读了一些关于在pandas中使用大数据集的讨论here,但是执行SELECT*查询似乎需要做很多工作。当然有一种更简单的方法。


Tags: csv数据方法from数据库pandasreadsql
3条回答

如注释中所述,从pandas 0.15开始,在read_sql中有一个chunksize选项来逐块读取和处理查询:

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

引用:http://pandas.pydata.org/pandas-docs/version/0.15.2/io.html#querying

更新:确保查看下面的答案,因为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)

也可能是整个数据帧太大,无法放入内存,在这种情况下,除了限制所选行或列的数量之外,您没有其他选择。

代码解决方案和备注。

# 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)

然而,我的内存分析告诉我,即使在提取每个块后释放内存,列表也会越来越大,占用内存,导致可用内存的净净收益没有增加。

想听听作者/其他人的意见。

相关问题 更多 >