【问题标题】:cursor.fetchall() vs list(cursor) in Pythonpython 中的 cursor.fetchall() 与 list(cursor)
【发布时间】:2013-07-25 12:44:43
【问题描述】:

这两种方法都返回查询返回项的列表,我是否在这里遗漏了什么,或者它们确实有相同的用法?

在性能方面有什么不同吗?

【问题讨论】:

    标签: python mysql-python database-cursor


    【解决方案1】:

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

    因此,即使你使用

    for row in cursor:
    

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

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

    import MySQLdb
    import MySQLdb.cursors as cursors
    
    conn = MySQLdb.connect(..., cursorclass=cursors.SSCursor)
    

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

    cursor = conn.cursor()
    cursor.execute('SELECT * FROM HUGETABLE')
    for row in cursor:
        print(row)
    

    并且这些行将从服务器中一个接一个地获取,因此不需要 Python 首先构建一个巨大的元组列表,从而节省内存。

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

    【讨论】:

      【解决方案2】:

      cursor.fetchall()list(cursor) 本质上是一样的。不同的选择是不检索列表,而只是遍历裸游标对象:

      for result in cursor:
      

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

      【讨论】:

      • 这对于大多数PEP 249 实现都是正确的,但不是 MySQLdb 或 PyMySQL,其中 list(cursor) 应该比 cursor.fetchall() 更受欢迎(因为后者不一致地返回列表或元组,而前者始终返回一个列表)并且大多数游标实现确实在您开始迭代它们时立即将整个结果集获取到内存中。
      【解决方案3】:

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

      for row in cursor:
          # ...
      

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

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

      【讨论】:

      • “在 cursor.fetchall() 上使用 list(cursor) 没有什么意义;最终效果确实是一样的,但是你浪费了一个流式传输结果的机会。” - 适用于 Python 数据库 API 的大多数实现。在 MySQLdb 或其继任者 PyMySQL 的特定情况下,这种情况远非如此,其中 cursor.fetchall() 具有不一致的返回类型(意味着始终使用 list(cursor) 会降低您搞砸并导致 TypeError 的可能性)并且大多数游标子类不进行流式处理当循环结束时,而不是在产生第一个结果之前将所有结果读入内存。
      • @MarkAmery:这就是为什么我仔细使用“一个好的数据库适配器实现”这个词。我在写这篇文章时怀疑现有的 MySQL 实现正在预取所有结果。
      【解决方案4】:

      使用DictCursor 时值得注意的一个(MySQLdb/PyMySQL 特定的)区别是list(cursor) 将始终为您提供一个列表,而cursor.fetchall() 为您提供一个列表除非结果set 是空的,在这种情况下,它会给你一个空元组。在 MySQLdb 中就是这种情况,并且在较新的 PyMySQL 中仍然是这种情况,因为向后兼容的原因,它是 will not be fixed。虽然这个isn't a violation of Python Database API Specification,它仍然令人惊讶,并且很容易导致错误地假设结果是一个列表,而不仅仅是一个序列而导致的类型错误。 p>

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

      【讨论】:

        【解决方案5】:

        您可以使用列表推导将元组中的项目放入列表中:

        conn = mysql.connector.connect()
        cursor = conn.cursor()
        sql = "SELECT column_name FROM db.table_name;"
        cursor.execute(sql)
        
        results = cursor.fetchall()
        # bring the first item of the tuple in your results here
        item_0_in_result = [_[0] for _ in results]
        
        

        【讨论】:

        • 这不是问题所在。而_ 作为名称是未使用的名称的约定。在这里,您使用它来访问一个令人困惑的元素。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-08-01
        • 1970-01-01
        • 2016-03-02
        • 1970-01-01
        • 2013-04-09
        • 1970-01-01
        • 2018-02-26
        相关资源
        最近更新 更多