python postgres我可以获取100万行吗?
我正在使用python中的psycopg2模块从postgres数据库中读取数据,我需要对一列中的所有行执行一些操作,该列有100多万行 我想知道是python postgres我可以获取100万行吗?,python,postgresql,fetchall,Python,Postgresql,Fetchall,我正在使用python中的psycopg2模块从postgres数据库中读取数据,我需要对一列中的所有行执行一些操作,该列有100多万行 我想知道是cur.fetchall()失败还是导致我的服务器停机?(因为我的RAM可能没有那么大,无法容纳所有数据) 最聪明的方法是什么?考虑使用: 执行数据库查询时,Psycopg游标通常会获取 后端返回的所有记录,将它们传输到 客户端进程。如果查询返回大量数据,则 客户端将按比例分配大量内存 如果数据集太大,无法在客户端上实际处理 在服务器端,可以创建服务
cur.fetchall()
失败还是导致我的服务器停机?(因为我的RAM可能没有那么大,无法容纳所有数据)
最聪明的方法是什么?考虑使用:
执行数据库查询时,Psycopg游标通常会获取
后端返回的所有记录,将它们传输到
客户端进程。如果查询返回大量数据,则
客户端将按比例分配大量内存
如果数据集太大,无法在客户端上实际处理
在服务器端,可以创建服务器端游标。用这种
对于游标,只能将受控的
大量的数据,因此可以在没有
把它完全记住
下面是一个例子:
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)
fetchall()
获取到最大限度,因此,为了防止对数据库的大量命中,您可以在可管理的批处理中获取行,或者只需单步遍历光标,直到其耗尽:
row = cur.fetchone()
while row:
# do something with row
row = cur.fetchone()
Burhan指出的解决方案通过只获取单行来减少大型数据集的内存使用: row=cursor.fetchone() 然而,我注意到一行一行地获取数据的速度明显减慢。我通过互联网连接访问外部数据库,这可能是原因之一 事实证明,使用服务器端游标和获取行束是最有效的解决方案。您可以更改sql语句(如在alecxe answers中),但也有使用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
您可以在中找到有关服务器端游标的更多信息,以下是以fetchmany管理的速度使用的代码 其原理是在Psycopg2中使用命名游标,并为其提供一个良好的
itersize
,以一次加载多行,就像fetchmany
一样,但在游标中为rec使用一个循环,该循环执行隐式fetchnone()
使用这段代码,我可以在1小时内查询数十亿行表中的1.5亿行和200兆内存。不需要交互地向前/向后滚动,就不能确定命名光标是否合适?我可能错了
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,)
我认为更明智的方法是找到一种方法来处理数据库服务器端的所有行。如果您发现自己从数据库中获取了一百万行,那么您的方法可能有问题。@mustaccio,这不是一个好的观点。您不知道OP问题背后的业务逻辑和数据集是什么。谢谢,Burhan Khalid给出的答案和这种方法的优点是什么?Burhan的答案看起来更简单,也会起作用。但是,让服务器在迭代循环的每个步骤上为您提供控制数量的数据是一种方法。对于我来说,如果没有您,二进制关键字PsycopG2不支持二进制游标,如以下链接中所述:。如果有人知道如何通过psycopg2实际使用二进制游标,而不仅仅是命名游标。当我重新启动代码时,光标从它处理过的最后一条记录开始,而不是从DB的开始。如何将光标指向表的开头。您能定义“抓取”吗?因为查询仍然完全执行,所以数据存储在某个地方。在数据库上,它仍然是一个查询,所以我不明白fetchone或fetchmany如何节省内存。好问题@StevenWade,这样做不会减少db实例的内存消耗,没错。然而,我理解这个问题是为了避免连接到数据库并获取数据的实例的内存消耗。那么它如何减少应用程序中的内存呢?它是否在数据包级别将其分解?它必须限制以某种方式返回的数据量。它不会中断查询,并且所有结果不能一次全部返回,否则不会减少内存使用。
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,)