yield_per期间sqlalchemy游标错误

Spa*_*ide 13 python sqlalchemy

我收到以下错误:

Traceback (most recent call last):
    main()
    for item in session.query(Item).yield_per(10):
    fetch = cursor.fetchmany(self._yield_per)
    self.cursor, self.context)
    l = self.process_rows(self._fetchmany_impl(size))
    row = self._fetchone_impl()
    self.__buffer_rows()
    self.__rowbuffer = collections.deque(self.cursor.fetchmany(size))
sqlalchemy.exc.ProgrammingError: (ProgrammingError) named cursor isn't valid anymore None None
Run Code Online (Sandbox Code Playgroud)

我怀疑调用session.commit()会干扰.yield_per

sessionmaker_ = sessionmaker(autocommit=False, autoflush=False, bind=engine)
session = scoped_session(sessionmaker_)

def foo(item):
  # DO something to the item 
  session.add(item)
  session.commit()

def main():
  for item in session.query(Item).yield_per(5):
    foo(item)
Run Code Online (Sandbox Code Playgroud)

任何的想法?

zzz*_*eek 16

如果您还没有从DBAPI游标中获取所有行,那么在该游标的连接上调用commit()通常是个坏主意.在这种情况下,psycopg2(我猜这是你正在使用的DBAPI)无法在事务上维护命名游标的状态(这是它在你想要服务器缓冲行时使用的状态).

你应该在这里改变的一件事是你提交的频率.理想情况下,在整个操作完成之前,您不会提交任何内容.会话将根据需要自动刷新数据(好吧,如果你打开autoflush,我建议),或者你可以调用flush()来强制它,但这与实际提交事务无关.所有这些对commit()的调用都会使操作的效率低于它的效率,当然它会妨碍其他结果集的游标.如果您只是在循环结束时放置一个commit(),那么您将立即解决这两个问题.

如果你仍然需要在整个操作完成之前提交,或者即使没有,我也不赞成使用chunk而不是使用yield_per(),这很脆弱.http://www.sqlalchemy.org/trac/wiki/UsageRecipes/WindowedRangeQuery上的食谱显示了一种方法.尽管psycopg2为我们提供了更多的余地,但DBAPI并不适合处理总体上非常大的结果集.


eno*_*mad 5

上述问题可以通过再进行一次会话来解决

sessionmaker_ = sessionmaker(autocommit=False, autoflush=False, bind=engine)
session = scoped_session(sessionmaker_)
cool_session = scoped_session(sessionmaker_)

def foo(item):
   # DO something to the item 
   session.add(item)
   session.commit()

def main():
    for item in cool_session.query(Item).yield_per(5):
    item = session.merge(item, load=False)
    foo(item)
Run Code Online (Sandbox Code Playgroud)