6

我有以下方法可以访问 mysql 数据库,并且查询在服务器中执行,而我无权更改有关增加内存的任何内容。我是生成器的新手,并开始阅读有关它的更多信息,并认为我可以将其转换为使用生成器。

def getUNames(self):
    globalUserQuery = ur'''SELECT gu_name FROM globaluser WHERE gu_locked = 0'''
    global_user_list = []
    try:
        self.gdbCursor.execute(globalUserQuery)
        rows = self.gdbCursor.fetchall()
        for row in rows:
            uName = unicode(row['gu_name'], 'utf-8')
            global_user_list.append(uName)
        return global_user_list
    except Exception, e:
        traceback.print_exc()

我使用此代码如下:

for user_name in getUNames():
...

这是我从服务器端得到的错误:

^GOut of memory (Needed 725528 bytes)
Traceback (most recent call last):
...
packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
OperationalError: (2008, 'MySQL client ran out of memory')

我应该如何使用生成器来避免这种情况:

while true:
   self.gdbCursor.execute(globalUserQuery)
   row = self.gdbCursor.fetchone()
   if row is None: break
   yield row

不确定以上是否是正确的方法,因为我期望我的数据库方法会产生一个列表。我认为最好的是从查询中获取块并返回一个列表,一旦完成,只要查询返回结果,生成器就会给出下一个集合。

4

1 回答 1

13

使用 MySQLdb,默认游标会在调用时将整个结果集加载到 Python 列表中cursor.execute(..)。对于可能导致 MemoryError 的大型查询,无论您是否使用生成器。

相反,使用SSCursor或 SSDictCursor。这些会将结果集保留在服务器端,并允许您通过客户端结果集中的项目进行交互:

import MySQLdb  
import MySQLdb.cursors as cursors
import traceback

def getUNames(self):
    # You may of course want to define `self.gdbCursor` somewhere else...
    conn = MySQLdb.connect(..., cursorclass=cursors.SSCursor)
    #                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    #                       Set the cursor class to SSCursor here
    self.gdbCursor = conn.cursor()

    globalUserQuery = ur'''SELECT gu_name FROM globaluser WHERE gu_locked = 0'''
    try:
        self.gdbCursor.execute(globalUserQuery)
        for row in self.gdbCursor:
            uName = unicode(row['gu_name'], 'utf-8')
            yield uName
    except Exception as e:
        traceback.print_exc()

关于默认值CursorSSCursor. 我知道的最好的来源是 Cursor Mixin 类本身的文档字符串:

默认光标使用CursorStoreResultMixIn

In [2]: import MySQLdb.cursors as cursors
In [8]: print(cursors.CursorStoreResultMixIn.__doc__)
This is a MixIn class which causes the entire result set to be
    stored on the client side, i.e. it uses mysql_store_result(). If the
    result set can be very large, consider adding a LIMIT clause to your
    query, or using CursorUseResultMixIn instead.

并且 SSCursor 使用CursorUseResultMixIn

In [9]: print(cursors.CursorUseResultMixIn.__doc__)
This is a MixIn class which causes the result set to be stored
    in the server and sent row-by-row to client side, i.e. it uses
    mysql_use_result(). You MUST retrieve the entire result set and
    close() the cursor before additional queries can be peformed on
    the connection.

由于我改成getUNames了生成器,所以会这样使用:

for row in self.getUnames():
    ...
于 2013-08-12T18:24:50.703 回答