Python数据库API:fetchone vs fetchmany vs fetchall

87

今天我和一些同事讨论了Python的db-api中fetchone、fetchmany和fetchall的区别。

虽然每个API的具体实现可能会影响它们的使用场景,但总的来说,fetchone、fetchmany和fetchall分别适合哪些使用场景呢?

换句话说,以下三个方法是否等价?如果不是,其中有一个优于其他方法吗?在哪些情况下使用?

cursor.execute("SELECT id, name FROM `table`")
for i in xrange(cursor.rowcount):
    id, name = cursor.fetchone()
    print id, name


cursor.execute("SELECT id, name FROM `table`")
result = cursor.fetchmany()
while result:
    for id, name in result:
        print id, name
    result = cursor.fetchmany()


cursor.execute("SELECT id, name FROM `table`")
for id, name in cursor.fetchall():
    print id, name
3个回答

23
根据官方psycopg2文档fetchone() 获取查询结果集的下一行,返回单个元组或在没有更多数据可用时返回None:
>>> cur.execute("SELECT * FROM test WHERE id = %s", (3,))
>>> cur.fetchone()

(3, 42, 'bar')

如果上一次执行execute*()方法未产生任何结果集或尚未发出调用,则会引发ProgrammingError。

fetchmany([size=cursor.arraysize])

获取查询结果的下一组行,返回元组列表。当没有更多行可用时,返回空列表。

每次调用要获取的行数由参数指定。如果未给出,则游标的数组大小确定要获取的行数。该方法应尝试获取由大小参数指示的尽可能多的行。如果由于指定的行数不可用而无法实现此目标,则可能返回较少的行:

>>> cur.execute("SELECT * FROM test;")
>>> cur.fetchmany(2)
[(1, 100, "abc'def"), (2, None, 'dada')]
>>> cur.fetchmany(2)
[(3, 42, 'bar')]
>>> cur.fetchmany(2)
[]

如果上一次调用execute*()未产生任何结果集或尚未发出调用,则会引发ProgrammingError。
请注意,大小参数涉及性能考虑。为了获得最佳性能,通常最好使用arraysize属性。如果使用大小参数,则最好使其保留从一个fetchmany()调用到下一个的相同值。
列表项
fetchall()
获取查询结果的所有(剩余)行,并将它们作为元组列表返回。如果没有更多记录可获取,则返回空列表。
>>> cur.execute("SELECT * FROM test;")
>>> cur.fetchall()
[(1, 100, "abc'def"), (2, None, 'dada'), (3, 42, 'bar')]

如果上一次执行execute*()没有生成任何结果集或者还没有发出调用,则会引发ProgrammingError。

20

我认为这确实取决于具体实现,但您可以通过查看MySQLdb源代码来了解差异。根据选项,mysqldb fetch* 将当前行集保留在内存或服务器端,因此fetchmany与fetchone在此具有一定的灵活性,以了解在Python内存中保存什么以及在数据库服务器端保存什么。

PEP 249没有提供太多详细信息,因此我猜这是为了优化数据库相关事物,而确切的语义是由具体实现定义的。


8
我发现这些方法使用的内存量不同,其中fetchall()方法使用的内存最多。 - Marc Maxmeister
这三个获取命令也让我感到困惑。如果涉及的Python正在运行在与mySQL服务器相同的服务器上,那该怎么办? - SMGreenfield
2
我的困惑在于 SQL 查询可以使用 LIMIT,那么 fetchonefetchmany 的目的是什么?实际上,如果您选择了没有限制的查询,您将获得整个表。如果我仍然只使用 fetchone,这是否意味着大量行从服务器传输到客户端而没有任何理由?在这种情况下,当始终更有效的是使用 LIMIT 1 时,为什么要使用 fetchone - CMCDragonkai

12

这些是实现特定的。

  • fetchall

将从表中获取所有结果。 当表的大小较小时,这将工作得更好。 如果表的大小更大,则在这些情况下fetchall将失败。

将使用大多数内存。

如果在网络上执行查询,则可能会导致一些问题。

  • fetchmany

fetchmany将仅获取所需数量的结果。 您可以生成结果并处理。 fetchmany 的简单实现代码示例。

   while True:
    results = cursor.fetchmany(arraysize)
    if not results:
        break
    for result in results:
        yield result

3
从Python 3.3版本开始,使用yield from results来替代for循环应该会更好。 - ebk
@ebk 源代码或解释? - danielcaballero88
1
@khawabonga 请查看PEP 380这个答案 - ebk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接