2015-05-24 47 views
7

从psycopg2文档:Python的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的人来说是个大问题。

+0

你能避免所有的交通和做选择和更新在同一查询光标苦差事。发布真正的问题,很可能你会得到更好的答案。 –

+0

我想你的意思是用“update where”语句,对吧?在我的使用案例中,处理比这更复杂。 –

+0

我的意思是一个CTE查询。无论复杂程度如何。 –

回答

0

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

  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; 

而在代码:

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

cur2 = conn.cursor('curname') 
for record in cur2:  # or cur2.fetchone, fetchmany... 
    # do something with record 
    pass 
  • 是的,你应该打开新的游标,如果你想获得服务器端游标的行。
  • +0

    因此,与普通游标,只要我执行SQL,整个结果集将被加载到内存中?如果我无法访问数据库来创建服务器端对象,该怎么办?没有像JDBC结果集那样的东西吗?由于 –

    +0

    请参阅JDBC驱动程序示例,其中没有明确的服务器端游标需要创建:https://jdbc.postgresql.org/documentation/head/query.html#query-with-cursor –

    +0

    文档:当执行数据库查询,Psycopg光标通常会获取后端返回的所有记录,并将它们传送到客户端进程。如果查询返回了大量的数据,则客户端将分配相当大量的内存。 – kwarunek