PyMySQL 的 fetchone() 有缓冲吗?

Is PyMySQL's fetchone() buffered?

我正在执行可能产生数千行的数据库查询。

最简单的方法是遍历 fetchall():

import pymysql

sql_command = "SELECT * FROM table WHERE some_condition;"
connection = pymysql.connect(...)
cursor = connection.cursor()
nof_affected_rows = cursor.execute(sql_command)
for row in cursor.fetchall():
    # process row

不过,这里怕内存耗尽。因此,另一种天真的方法是迭代 fetchone,一次一个元素。

import pymysql

sql_command = "SELECT * FROM table WHERE some_condition;"
connection = pymysql.connect(...)
cursor = connection.cursor()
nof_affected_rows = cursor.execute(sql_command)
while True:
    row = cursor.fetchone()
    if not row:
        break
    # process row

现在一位同事认为我应该使用 fetchmany(),因为它会一次检索多个元素,从而避免往返。同时我会控制内存消耗。

这是真的吗? fetchone() 是否缓冲。如果有缓冲,扩展到哪个?

PyMySQL 在执行查询时急切地下载所有元素。

不幸的是,我无法在文档中找到明确的陈述。因此我做了一个小实验。

我开始 IPython 并执行了以下代码片段:

import pymysql

sql_command = "SELECT * FROM table WHERE some_condition;"
connection = pymysql.connect(...)
cursor = connection.cursor()
nof_affected_rows = cursor.execute(sql_command)

这导致了大约。要加载 450000 行。

在一个单独的终端中,我使用 htop 监控了 IPython 的内存消耗。内存消耗从 0.1% 上升到 7.3%,相当于大约。 2.2GiB 内存。

我断开网络后,我仍然能够从 Cursor 中检索所有元素。

因此我得出结论,所有行都在 cursor.execute() 处检索。因此,在 PyMySQL 中,是使用 fetchonefetchmany 还是 fetchall 的问题归结为哪个更方便。

您可以使用SSCursor

cursor = connection.cursor(pymysql.cursors.SSCursor)
cursor.execute(sql_command)
for row in cursor:  # Cursor is iterable. You don't have to call `fetch*()` methods.
    # process row