我在python中使用 psycopg2 模块从postgres数据库中读取,我需要对列中的所有行进行一些操作,该行有超过100万行。
我想知道cur.fetchall()
会失败或导致我的服务器停机吗? (因为我的RAM可能不会那么大,无法容纳所有数据)
q="SELECT names from myTable;"
cur.execute(q)
rows=cur.fetchall()
for row in rows:
doSomething(row)
更聪明的方法是什么?
答案 0 :(得分:22)
考虑使用server side cursor:
执行数据库查询时,Psycopg游标通常会获取 后端返回的所有记录,将它们转移到 客户流程。如果查询返回了大量数据,a 比例大量的内存将由客户端分配。
如果数据集太大而无法在客户端上进行实际处理 方面,可以创建服务器端游标。使用这种 光标有可能只传送给客户端一个受控制的 数据量,以便可以检查大型数据集 把它完全留在记忆中。
以下是一个例子:
cursor.execute("DECLARE super_cursor BINARY CURSOR FOR SELECT names FROM myTable")
while True:
cursor.execute("FETCH 1000 FROM super_cursor")
rows = cursor.fetchall()
if not rows:
break
for row in rows:
doSomething(row)
答案 1 :(得分:20)
fetchall()
提取到arraysize
限制,因此为了防止对数据库的大量攻击,您可以以可管理的批次获取行,或者只是单步执行游标直到其耗尽:
row = cur.fetchone()
while row:
# do something with row
row = cur.fetchone()
答案 2 :(得分:20)
Burhan指出的解决方案只通过获取单行来减少大型数据集的内存使用量:
row = cursor.fetchone()
但是,我注意到逐行获取行的速度显着减慢。我通过互联网连接访问外部数据库,这可能是它的原因。
拥有服务器端游标并获取一串行被证明是最高性能的解决方案。您可以更改sql语句(如在alecxe答案中),但也有使用psycopg2提供的功能的纯python方法:
cursor = conn.cursor('name_of_the_new_server_side_cursor')
cursor.execute(""" SELECT * FROM table LIMIT 1000000 """)
while True:
rows = cursor.fetchmany(5000)
if not rows:
break
for row in rows:
# do something with row
pass
您可以在psycopg2 wiki
中找到有关服务器端游标的更多信息答案 3 :(得分:2)
以下是simple server side cursor使用fetchmany
管理速度的代码。
原则是在Psycopg2中使用命名游标并给它一个好的itersize
一次加载许多行,就像fetchmany
一样,但只有一个循环{ {1}}执行隐式for rec in cursor
。
使用此代码,我可以在1小时内和200兆内存中查询数十亿行表中的1.5亿行。
答案 4 :(得分:0)
不确定是否需要命名的游标是否适合而不需要交互地向前/向后滚动?我在这里可能是错的。
fetchmany
循环很乏味,但我认为这是最好的解决方案。为了使生活更轻松,您可以使用以下内容:
from functools import partial
from itertools import chain
# from_iterable added >= python 2.7
from_iterable = chain.from_iterable
# util function
def run_and_iterate(curs, sql, parms=None, chunksize=1000):
if parms is None:
curs.execute(sql)
else:
curs.execute(sql, parms)
chunks_until_empty = iter(partial(fetchmany, chunksize), [])
return from_iterable(chunks_until_empty)
# example scenario
for row in run_and_iterate(cur, 'select * from waffles_table where num_waffles > %s', (10,)):
print 'lots of waffles: %s' % (row,)