在内存高效生成器中正确使用PyMySql的方法

5 投票
1 回答
2603 浏览
提问于 2025-04-18 11:55

我想写一个生成器函数,这个函数会在内存有限的系统上运行,使用PyMySql(或者MySQLDb)来逐个返回查询结果。下面的代码可以正常工作:

#execute a select query and return results as a generator
def SQLSelectGenerator(self,stmt):
    #error handling code removed
    cur.execute(stmt)

    row = ""
    while row is not None:
        row = self.cur.fetchone()
        yield row

不过,下面的代码也能正常工作,但它的表现有点让人摸不着头脑,不太清楚它是不是在执行fetchall()。我在Python的数据库API中找不到关于当你像列表一样迭代游标对象时到底发生了什么的具体说明:

#execute a select query and return results as a generator
def SQLSelectGenerator(self,stmt):
    #error handling code removed
    cur.execute(stmt)

 for row in self.cur:
    yield row

在这两种情况下,下面的代码都能成功打印出所有的行:

stmt = "select * from ..."
for l in SQLSelectGenerator(stmt):
    print(l)

所以我想知道第二种实现方式到底是好还是坏,它是调用了fetchall还是在用fetchone做一些复杂的操作。因为如果调用fetchall的话,系统会崩溃,因为数据有几百万行。

1 个回答

3

根据PyMySql的源代码,执行

for row in self.cur:
   yield row

这意味着你内部实际上是在重复执行fetchone(),就像你第一个例子中那样:

class Cursor(object):
    '''
    This is the object you use to interact with the database.
    '''
    ...
    def __iter__(self):
        return iter(self.fetchone, None)

所以我认为这两种方法在内存使用和性能上基本是一样的。你可以选择第二种方法,因为它更简洁、更简单。

撰写回答