我正在使用python中的psycopg2模块读取postgres数据库,我需要对一列中的所有行进行一些操作,该列有超过100万行。
我想知道cur.fetchall()
是否会失败或导致我的服务器宕机?(因为我的RAM可能不足以容纳所有这些数据)
q="SELECT names from myTable;"
cur.execute(q)
rows=cur.fetchall()
for row in rows:
doSomething(row)
做这件事的更聪明的方法是什么?
我正在使用python中的psycopg2模块读取postgres数据库,我需要对一列中的所有行进行一些操作,该列有超过100万行。
我想知道cur.fetchall()
是否会失败或导致我的服务器宕机?(因为我的RAM可能不足以容纳所有这些数据)
q="SELECT names from myTable;"
cur.execute(q)
rows=cur.fetchall()
for row in rows:
doSomething(row)
做这件事的更聪明的方法是什么?
6条答案
按热度按时间wwwo4jvm1#
Burhan指出的解决方案通过只获取单行来减少大型数据集的内存使用:
行=游标.fetchone()
但是,我注意到逐个获取行的速度明显变慢,我通过互联网连接访问外部数据库,这可能是原因之一。
拥有服务器端游标和读取成束的行被证明是性能最好的解决方案,你可以修改sql语句(如alecxe answers),但也有纯粹的python方法使用psycopg2提供的特性:
在psycopg2 wiki中找到更多关于服务器端游标的信息吗
fiei3ece2#
考虑使用服务器端游标:
在执行数据库查询时,Psycopg游标通常会获取后端返回的所有记录,并将它们传输到客户端进程。如果查询返回了大量数据,客户端将按比例分配大量内存。
如果数据集太大,实际上无法在客户端处理,则可以创建服务器端游标。使用这种游标,可以仅向客户端传输受控量的数据,以便可以检查大型数据集,而无需将其完全保存在内存中。
下面是一个例子:
ivqmmu1c3#
fetchall()
的读取上限为arraysize
,因此,为了防止对数据库的大量访问,您可以在可管理的批处理中读取行,或者简单地遍历游标直到其耗尽:hyrbngr74#
下面是用于simple server side cursor的代码,具有
fetchmany
管理的速度。原则是在Psycopg2中使用 named cursor,并为它提供一个良好的
itersize
,以便像fetchmany
那样一次加载多行,但使用for rec in cursor
的单个循环执行隐式fetchnone()
。有了这个代码,我可以在1小时内从数十亿行的表中查询1.5亿行,内存为200兆。
baubqpgj5#
where (ordered_val = %(last_seen_val)s and primary_key > %(last_seen_pk)s OR ordered_val > %(last_seen_val)s)
扩充下一个查询至少可以说,这对库是一种误导,文档中应该有一个关于这一点的简介,我不知道为什么没有。
如果不需要交互式向前/向后滚动,不确定命名游标是否合适?我可能错了。
fetchmany
循环很繁琐,但我认为它是最好的解决方案。为了使工作更简单,可以使用以下代码:bejyjqdl6#
当我阅读评论和答案时,我想我应该为未来的读者澄清一些关于
fetchone
和服务器端游标的问题。使用普通游标(客户端),
Psycopg
获取后端返回的所有记录,并将它们传输到客户端进程。当您执行类似curs.execute('SELECT * FROM ...'
的查询时,所有记录都缓冲在客户端内存中。This question也证实了这点。
所有
fetch*
方法都是用于访问 * 此存储数据 * 的。**问:**那么
fetchone
如何帮助我们提高内存?**答:**它只从存储的数据中获取一条记录,创建一个Python对象,然后交给你Python代码,而
fetchall
将从这些数据中获取并创建 n 个Python对象,然后把它们都交给你。如果你的表有100万条记录,内存中的情况是这样的:
当然
fetchone
有帮助,但我们仍然在内存中有完整的记录,这就是服务器端游标发挥作用的地方:PostgreSQL也有自己的游标概念(有时也叫portal),当数据库游标被创建时,查询不一定被完全处理:服务器可能只在需要时才能生成结果。只有请求的结果才会被传输到客户端:如果查询结果非常大,但客户端只需要前几个记录,则可以只传输它们。...它们的界面是相同的,但在后台它们发送命令以控制服务器上光标的状态(例如,当获取新记录时或当使用scroll()移动时)。
因此,您不会在一个块中获得整个结果集。
缺点:
缺点是服务器需要跟踪部分处理的结果,因此会占用服务器上**更多的内存和资源。