来自psycopg2文档:
当执行数据库查询时,Psycopg游标通常会获取由后端返回的所有记录,并将它们传输到客户端进程。如果查询返回了大量数据,则客户端将分配相应数量的内存。如果数据集太大,无法在客户端上实际处理,则可以创建服务器端游标。
我想查询一个可能有成千上万行的表,并为每一行执行某些操作。普通游标是否会将整个数据集带到客户端?这听起来不太合理。代码大致如下:
conn = psycopg2.connect(url)
cursor = conn.cursor()
cursor.execute(sql)
for row in cursor:
do some stuff
cursor.close()
我希望这是一个流式操作。 另一个问题是关于游标的范围。在我的循环内,我想更新另一张表。我需要每次打开一个新的游标并关闭吗?每个项目更新应该在自己的事务中,因为我可能需要回滚。
for row in cursor:
anotherCursor = anotherConn.cursor()
anotherCursor.execute(update)
if somecondition:
anotherConn.commit()
else:
anotherConn.rollback
cursor.close()
========编辑:我对第一部分的回答如下========
好的,我将尝试回答我问题的第一部分。普通游标实际上会在调用execute之后立即带回整个数据集,甚至在开始迭代结果集之前。您可以通过检查每个步骤的进程内存占用量来验证这一点。但服务器端游标的需要实际上是由Postgres服务器而不是客户端引起的,并在此处记录:http://www.postgresql.org/docs/9.3/static/sql-declare.html
现在,从文档中并不立即显而易见,但是这种游标实际上可以在事务期间暂时创建。无需在数据库中明确创建一个返回refcursor的函数,具有特定SLQ语句等。使用psycopg2时,您只需要在获取游标时给出一个名称,然后将为该事务创建一个临时游标。因此,代替:
cursor = conn.cursor()
你只需要:
cursor = conn.cursor('mycursor')
就是这样,它能够起作用。我认为在使用JDBC时,在设置fetchSize时也会在幕后执行相同的操作。只是更加透明。请参见此处的文档:https://jdbc.postgresql.org/documentation/head/query.html#query-with-cursor
您可以通过在同一事务中查询pg_cursors视图来测试这是否有效。服务器端游标在获取客户端游标后出现,并且在关闭客户端游标后消失。因此,底线是:我很高兴对我的代码进行更改,但我必须说,对于那些没有太多Postgres经验的人来说,这是一个很大的坑。