python postgres我可以fetchall()100万行吗?

时间:2013-07-29 20:14:25

标签: python postgresql fetchall

我在python中使用 psycopg2 模块从postgres数据库中读取,我需要对列中的所有行进行一些操作,该行有超过100万行。

我想知道cur.fetchall()会失败或导致我的服务器停机吗? (因为我的RAM可能不会那么大,无法容纳所有数据)

q="SELECT names from myTable;"
cur.execute(q)
rows=cur.fetchall()
for row in rows:
    doSomething(row)

更聪明的方法是什么?

5 个答案:

答案 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,)