cursor.fetchall()vs Python中的list(cursor)

NZa*_*Zal 35 python cursor mysql-python

两种方法都返回查询返回项的列表,我在这里错过了什么吗?
或者他们确实有相同的用法?
任何性能差异?

unu*_*tbu 71

如果您使用的是默认光标a MySQLdb.cursors.Cursor,则整个结果集将在完成时存储在客户端(即Python列表中)cursor.execute().

因此,即使你使用

for row in cursor:
Run Code Online (Sandbox Code Playgroud)

你不会减少内存占用.整个结果集已经存储在一个列表中(参见self._rowsMySQLdb/cursors.py).

但是,如果您使用SSCursor或SSDictCursor:

import MySQLdb
import MySQLdb.cursors as cursors

conn = MySQLdb.connect(..., cursorclass=cursors.SSCursor)
Run Code Online (Sandbox Code Playgroud)

然后结果集存储在服务器 mysqld中.现在你可以写了

cursor = conn.cursor()
cursor.execute('SELECT * FROM HUGETABLE')
for row in cursor:
    print(row)
Run Code Online (Sandbox Code Playgroud)

并且这些行将从服务器逐个获取,因此不需要Python首先构建庞大的元组列表,从而节省内存.

否则,正如其他人已经说过的那样,cursor.fetchall()并且list(cursor)基本上是相同的.


Amb*_*ber 11

cursor.fetchall()并且list(cursor)基本上是相同的.不同的选择是不检索列表,而只是循环遍历裸光标对象:

for result in cursor:
Run Code Online (Sandbox Code Playgroud)

如果结果集很大,这可能会更有效,因为它不必获取整个结果集并将其全部保存在内存中; 它可以逐步获得每个项目(或以较小的批次批量处理).

  • 大多数 [PEP 249](https://www.python.org/dev/peps/pep-0249) 实现都是如此,但不是 MySQLdb 或 PyMySQL,其中 `list(cursor)` 应该比 `cursor 更受欢迎.fetchall()`(因为后者不一致地返回列表或元组,而前者一致地返回列表)并且大多数游标实现 *do* 在您开始迭代它们时立即将整个结果集提取到内存中。 (4认同)

Mar*_*ers 5

list(cursor)之所以有效,是因为游标是可迭代的;您也可以cursor在循环中使用:

for row in cursor:
    # ...
Run Code Online (Sandbox Code Playgroud)

一个好的数据库适配器实现将从服务器批量获取行,节省所需的内存占用,因为它不需要将完整的结果集保存在内存中。cursor.fetchall() 必须返回完整列表。

使用list(cursor)over没有什么意义cursor.fetchall();最终效果确实是一样的,但你浪费了一个机会来传输结果。

  • @MarkAmery:这就是为什么我小心地使用“一个好的数据库适配器实现”这个词。当我写这篇文章时,我怀疑现有的 MySQL 实现正在预取所有结果。 (2认同)

Mar*_*ery 5

使用 a 时值得注意的一个(MySQLdb/PyMySQL 特定)差异DictCursor是,它list(cursor)总是为您提供一个列表,而 while 则为cursor.fetchall()您提供一个列表,除非结果集为空,在这种情况下,它会为您提供一个空元组。MySQLdb 中就是这种情况,并且在较新的PyMySQL中仍然是这种情况,由于向后兼容性原因,它不会被修复。虽然这并不违反 Python 数据库 API 规范,但它仍然令人惊讶,并且很容易因错误地假设结果是列表不仅仅是序列而导致类型错误。

鉴于上述情况,我建议始终偏爱list(cursor),cursor.fetchall()以避免在结果集为空的边缘情况下陷入神秘的类型错误。