Python DB-API:fetchone与fetchmany与fetchall


72

我今天刚刚和一些同事讨论了python的db-api fetchone vs fetchmany vs fetchall。

我确定每个应用程序的用例都取决于我正在使用的db-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

Answers:


18

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

PEP 249并没有提供太多细节,所以我想这是根据数据库来优化事物,而确切的语义是由实现定义的。


7
我发现这些使用的内存量有所不同,fetchall()使用的内存最多。
Marc Maxmeister 2012年

这三个获取命令也让我挠头。如果有问题的Python作为mySQL服务器在同一服务器上运行怎么办?
SMGreenfield

在这里,我的困惑来源于这样的事实,一个SQL SELECT查询可以有LIMIT,所以有什么目的fetchonefetchmany?实际上,如果您选择无限制的查询,则将获得整个表。如果我仍然只使用fetchone它,是否意味着无缘无故地将大量行从服务器传输到客户端?在那种情况下,为什么在使用fetchone时为什么会使用LIMIT 1总是效率更高。
CMCDragonkai

13

fetchone()

获取查询结果集的下一行,返回一个元组,如果没有更多数据可用,则返回None:

>>> cur.execute("SELECT * FROM test WHERE id = %s", (3,))
>>> cur.fetchone()

(3, 42, 'bar')

如果先前对execute *()的调用未产生任何结果集或尚未发出任何调用,则会引发ProgrammingError。

fetchmany([size = cursor.arraysize])

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

每个调用要获取的行数由参数指定。如果未给出,则游标的arraysize确定要获取的行数。该方法应尝试获取由size参数指示的尽可能多的行。如果由于指定的行数不可用而无法执行此操作,则可能会返回较少的行:

>>> 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属性。如果使用了size参数,则最好从一个fetchmany()调用到下一个调用保留相同的值。

项目清单

fetchall()

提取查询结果的所有(剩余)行,并将它们作为元组列表返回。如果没有更多记录可获取,则返回一个空列表。

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

如果先前对execute *()的调用未产生任何结果集或尚未发出任何调用,则会引发ProgrammingError。


10

这些是特定于实现的。

  • fetchall

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

将占用大部分内存。

如果在网络上进行查询,将会引起一些问题。

  • 取货

fetchmany将仅获得所需数量的结果。您可以产生结果和过程。fetchmany实现的简单代码段。

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

1
从Python 3.3开始,使用yield from results消除for循环应该更好。
ebk
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.