62

我无法从 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

我在这里读到,从 csv 文件创建时存在类似的问题dataframe,解决方法是使用这样的“迭代器”和“块大小”参数:

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

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

4

5 回答 5

65

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

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

于 2015-04-08T18:22:48.623 回答
55

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

也有可能整个数据框太大而无法放入内存,在这种情况下,除了限制您选择的行数或列数之外,您别无选择。

于 2013-08-07T16:10:16.237 回答
13

代码解决方案和备注。

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

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

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

于 2019-08-26T16:44:41.403 回答
2

我发现处理这个问题的最好方法是利用 SQLAlchemy steam_results 连接选项

conn = engine.connect().execution_options(stream_results=True)

并将 conn 对象传递给 pandas

pd.read_sql("SELECT *...", conn, chunksize=10000)

这将确保游标在服务器端而不是客户端处理

于 2021-11-19T21:42:19.093 回答
0

如果要限制输出中的行数,只需使用:

data = psql.read_frame(sql, cnxn,chunksize=1000000).__next__()
于 2020-01-14T12:15:20.230 回答