Python 游标是否执行加载所有数据
Python does cursor execute load all data
我正在尝试查询一个大数据(1000 万行)并试图防止内存不足,但不熟悉 Python 并且对 execute()、游标迭代器和 fetchone 的不同意见感到困惑()
我是否可以假设 cursor.execute() 不会将所有数据加载到内存中,只有当我调用 fetchone() 时它才会加载 1 行数据
from mysql.connector import MySQLConnection
def query():
conn = MySQLConnection(host=conf['host'],
conf['port'],
conf['user'],
conf['password'],
conf['database'])
cursor = conn.cursor(buffered=True)
cursor.execute('SELECT * FROM TABLE') # 10 million rows
这个游标迭代器是否与 fetchone() 相同?
for row in cursor:
print(row)
我的代码片段可以安全地处理 1000 万行数据吗?如果没有,我怎样才能安全地迭代数据而不会内存不足?
取自MySQL documentation:
The fetchone() method is used by fetchall() and fetchmany(). It is also used when a cursor is used as an iterator.
以下示例显示了两种处理查询结果的等效方法。第一个在 while 循环中使用 fetchone(),第二个使用游标作为迭代器:
# Using a while loop
cursor.execute("SELECT * FROM employees")
row = cursor.fetchone()
while row is not None:
print(row)
row = cursor.fetchone()
# Using the cursor as iterator
cursor.execute("SELECT * FROM employees")
for row in cursor:
print(row)
它还指出:
You must fetch all rows for the current query before executing new statements using the same connection.
如果您担心性能问题,您应该在 while 循环中使用 fetchmany(n)
,直到您像这样获取所有结果:
'An iterator that uses fetchmany to keep memory usage down'
while True:
results = cursor.fetchmany(arraysize)
if not results:
break
for result in results:
yield result
此行为符合 PEP249, which describes how and which methods db connectors should implement. A partial answer is given in this thread。
基本上,fetchall vs fetchmany vs fetchone 的实现取决于库的开发人员,具体取决于数据库功能,但是对于 fetchmany 和 fetchone,unfetched/remaining结果将保留在服务器端,直到另一个调用请求或游标对象销毁。
所以总而言之,我认为可以安全地假设调用 execute 方法不会,在这种情况下 (mysqldb),将查询中的所有数据转储到内存中。
我的第一个建议是使用 from mysql.connector import connect
,它默认使用 C 扩展 (CMySQLConnection
),而不是 from mysql.connector import MySQLConnection
(纯 Python)。
如果你出于某种原因想要使用纯Python版本,你可以在connect()
中传递use_pure=True
第二个建议是对结果进行分页,如果使用缓冲游标,它将从服务器获取整个结果集。我不知道你是否想要 1000 万行。
这里有一些参考资料:
https://dev.mysql.com/doc/refman/8.0/en/limit-optimization.html
https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursorbuffered.html
我正在尝试查询一个大数据(1000 万行)并试图防止内存不足,但不熟悉 Python 并且对 execute()、游标迭代器和 fetchone 的不同意见感到困惑()
我是否可以假设 cursor.execute() 不会将所有数据加载到内存中,只有当我调用 fetchone() 时它才会加载 1 行数据
from mysql.connector import MySQLConnection
def query():
conn = MySQLConnection(host=conf['host'],
conf['port'],
conf['user'],
conf['password'],
conf['database'])
cursor = conn.cursor(buffered=True)
cursor.execute('SELECT * FROM TABLE') # 10 million rows
这个游标迭代器是否与 fetchone() 相同?
for row in cursor:
print(row)
我的代码片段可以安全地处理 1000 万行数据吗?如果没有,我怎样才能安全地迭代数据而不会内存不足?
取自MySQL documentation:
The fetchone() method is used by fetchall() and fetchmany(). It is also used when a cursor is used as an iterator.
以下示例显示了两种处理查询结果的等效方法。第一个在 while 循环中使用 fetchone(),第二个使用游标作为迭代器:
# Using a while loop
cursor.execute("SELECT * FROM employees")
row = cursor.fetchone()
while row is not None:
print(row)
row = cursor.fetchone()
# Using the cursor as iterator
cursor.execute("SELECT * FROM employees")
for row in cursor:
print(row)
它还指出:
You must fetch all rows for the current query before executing new statements using the same connection.
如果您担心性能问题,您应该在 while 循环中使用 fetchmany(n)
,直到您像这样获取所有结果:
'An iterator that uses fetchmany to keep memory usage down'
while True:
results = cursor.fetchmany(arraysize)
if not results:
break
for result in results:
yield result
此行为符合 PEP249, which describes how and which methods db connectors should implement. A partial answer is given in this thread。
基本上,fetchall vs fetchmany vs fetchone 的实现取决于库的开发人员,具体取决于数据库功能,但是对于 fetchmany 和 fetchone,unfetched/remaining结果将保留在服务器端,直到另一个调用请求或游标对象销毁。
所以总而言之,我认为可以安全地假设调用 execute 方法不会,在这种情况下 (mysqldb),将查询中的所有数据转储到内存中。
我的第一个建议是使用 from mysql.connector import connect
,它默认使用 C 扩展 (CMySQLConnection
),而不是 from mysql.connector import MySQLConnection
(纯 Python)。
如果你出于某种原因想要使用纯Python版本,你可以在connect()
use_pure=True
第二个建议是对结果进行分页,如果使用缓冲游标,它将从服务器获取整个结果集。我不知道你是否想要 1000 万行。
这里有一些参考资料:
https://dev.mysql.com/doc/refman/8.0/en/limit-optimization.html
https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursorbuffered.html