Python psycopg2游标

Naz*_* K. 8 python psycopg2 cursor python-2.7

来自psycopg2文档:

执行数据库查询时,Psycopg游标通常会获取后端返回的所有记录,并将它们传输到客户端进程.如果查询返回了大量数据,则客户端将分配大量内存.如果数据集太大而无法在客户端实际处理,则可以创建服务器端游标.

我想查询一个可能有数千行的表,并为每个行执行一些操作.普通游标实际上会将整个数据集带到客户端吗?这听起来不太合理.代码是这样的:

conn = psycopg2.connect(url)
cursor = conn.cursor()
cursor.execute(sql)
for row in cursor:
    do some stuff
cursor.close()
Run Code Online (Sandbox Code Playgroud)

我希望这是一个流媒体操作.第二个问题是关于游标的范围.在我的循环中,我想更新另一个表.我是否需要打开一个新光标并每次关闭?每个项目更新都应该在自己的事务中,因为我可能需要进行回滚.

for row in cursor:
    anotherCursor = anotherConn.cursor()
    anotherCursor.execute(update)
    if somecondition:
        anotherConn.commit()
    else:
        anotherConn.rollback
cursor.close()
Run Code Online (Sandbox Code Playgroud)

========编辑:我对第一部分的回答========

好的,我会尝试回答我问题的第一部分.在调用execute之前,正常游标实际上会带来整个数据集,甚至在开始迭代结果集之前.您可以通过在每个步骤检查进程的内存占用量来验证这一点.但是对服务器端游标的需求实际上是由于postgres服务器而不是客户端,并在此处记录:http://www.postgresql.org/docs/9.3/static/sql-declare.html

现在,从文档中可以立即看出这一点,但实际上可以在事务持续期间临时创建这些游标.不需要显式创建一个在数据库中返回refcursor的函数,具有特定的SLQ语句等.使用psycopg2,您只需在获取游标时给出一个名称,并为该事务创建一个临时游标.所以代替:

 cursor = conn.cursor()
Run Code Online (Sandbox Code Playgroud)

你只需要:

 cursor = conn.cursor('mycursor')
Run Code Online (Sandbox Code Playgroud)

这就是它,它的工作原理.在设置fetchSize时,我假设在使用JDBC时完成了同样的事情.它只是更透明一点.请参阅此处的文档:https://jdbc.postgresql.org/documentation/head/query.html#query-with-cursor

您可以通过查询同一事务中的pg_cursors视图来测试这是否有效.获取客户端游标后出现服务器端游标,关闭客户端游标后消失.所以底线:我很高兴对我的代码进行更改,但我必须说这对于没有经历过postgres的人来说是一个很大的难题.

kwa*_*nek 5

事实上,你已经回答了这个问题;)。

  1. 是的,您应该使用服务器端光标来获取记录流 http://initd.org/psycopg/docs/usage.html#server-side-cursors

来自文档:

CREATE FUNCTION reffunc(refcursor) RETURNS refcursor AS $$
BEGIN
    OPEN $1 FOR SELECT col FROM test;
    RETURN $1;
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

并在代码中:

cur1 = conn.cursor()
cur1.callproc('reffunc', ['curname'])

cur2 = conn.cursor('curname')
for record in cur2:     # or cur2.fetchone, fetchmany...
    # do something with record
    pass
Run Code Online (Sandbox Code Playgroud)
  1. 是的,如果您想使用服务器端游标获取行,您应该打开新游标。