- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
当生成大量结果集时,典型的 MySQLdb 库查询会使用大量内存并且在 Python 中执行不佳。例如:
cursor.execute("SELECT id, name FROM `table`")
for i in xrange(cursor.rowcount):
id, name = cursor.fetchone()
print id, name
有一个可选的游标,一次只能获取一行,这确实加快了脚本的速度并大大减少了脚本的内存占用。
import MySQLdb
import MySQLdb.cursors
conn = MySQLdb.connect(user="user", passwd="password", db="dbname",
cursorclass = MySQLdb.cursors.SSCursor)
cur = conn.cursor()
cur.execute("SELECT id, name FROM users")
row = cur.fetchone()
while row is not None:
doSomething()
row = cur.fetchone()
cur.close()
conn.close()
但我找不到任何有关将 SSCursor
与嵌套查询一起使用的信息。如果这是 doSomething()
的定义:
def doSomething()
cur2 = conn.cursor()
cur2.execute('select id,x,y from table2')
rows = cur2.fetchall()
for row in rows:
doSomethingElse(row)
cur2.close()
然后脚本抛出以下错误:
_mysql_exceptions.ProgrammingError: (2014, "Commands out of sync; you can't run this command now")
听起来好像 SSCursor
与嵌套查询不兼容。真的吗?如果是这样那就太糟糕了,因为使用标准游标时主循环似乎运行得太慢。
最佳答案
MySQLdb 用户指南中的the threadsafety
attribute 标题下讨论了这个问题。 (强调我的):
The MySQL protocol can not handle multiple threads using the sameconnection at once. Some earlier versions of MySQLdb utilized lockingto achieve a threadsafety of 2. While this is not terribly hard toaccomplish using the standard Cursor class (which uses
mysql_store_result()
), it is complicated by SSCursor (which usesmysql_use_result()
; with the latter you must ensure all the rows havebeen read before another query can be executed.
MySQL C API 函数的文档 mysql_use_result()
提供有关您的错误消息的更多信息:
When using
mysql_use_result()
, you must executemysql_fetch_row()
until aNULL
value is returned, otherwise, the unfetched rows arereturned as part of the result set for your next query. The C APIgives the errorCommands out of sync; you can't run this command now
if you forget to do this!
换句话说,您必须从任何无缓冲的游标(即使用 mysql_use_result()
而不是 mysql_store_result()
的游标中完全获取结果集 - 使用 MySQLdb,这意味着 SSCursor
和 SSDictCursor
),然后才能通过同一连接执行另一个语句。
在您的情况下,最直接的解决方案是打开第二个连接以在迭代无缓冲查询的结果集时使用。 (简单地从同一个连接获取缓冲游标是行不通的;在使用缓冲游标之前,您仍然必须越过未缓冲的结果集。)
如果您的工作流程类似于“遍历一个大结果集,对每一行执行 N 个小查询”,请考虑查看 MySQL 的存储过程,作为从不同连接嵌套游标的替代方法。您仍然可以使用 MySQLdb 调用过程并获得结果,尽管您肯定想要 read the documentation of MySQLdb's callproc()
method因为它不符合 Python 的 database API specs检索过程输出时。
第二种选择是坚持使用缓冲游标,但将您的查询分成批处理。这就是我去年为一个项目所做的事情,我需要遍历一组数百万行,使用内部模块解析一些数据,并执行一些 INSERT
和 UPDATE
处理每一行后查询。总体思路看起来像这样:
QUERY = r"SELECT id, name FROM `table` WHERE id BETWEEN %s and %s;"
BATCH_SIZE = 5000
i = 0
while True:
cursor.execute(QUERY, (i + 1, i + BATCH_SIZE))
result = cursor.fetchall()
# If there's no possibility of a gap as large as BATCH_SIZE in your table ids,
# you can test to break out of the loop like this (otherwise, adjust accordingly):
if not result:
break
for row in result:
doSomething()
i += BATCH_SIZE
关于您的示例代码,我要注意的另一件事是,您可以直接在 MySQLdb 中的游标上迭代,而不是在 xrange(cursor.rowcount)
fetchone()
。这在使用无缓冲游标时尤为重要,因为 rowcount
属性未定义并且会给出非常意外的结果(参见:Python MysqlDB using cursor.rowcount with SSDictCursor returning wrong count)。
关于python - 使用带有嵌套查询的 python MySQLDB SScursor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25772003/
我必须处理一个大型结果集(可能有数十万行,有时甚至更多)。 不幸的是,它们需要一次全部检索(在启动时)。 我正在尝试通过使用尽可能少的内存来做到这一点。 通过查看 SO,我发现使用 SSCursor
以下作品: class DB(): def __init__(self, host, user, password, db): self.conn = pymysql.con
当生成大量结果集时,典型的 MySQLdb 库查询会使用大量内存并且在 Python 中执行不佳。例如: cursor.execute("SELECT id, name FROM `table`")
我有一个从我的 MySQL 数据库中获取大量数据的查询,其中无法将所有数据加载到内存中。幸运的是,SQLAlchemy 允许我使用 MySQL 的 SSCursor 创建一个引擎,因此数据是流式传输的
我正在开发一个使用 CodeIgniter 进行数据库访问的应用程序。应用程序发出如下查询:$this->db->query("SELECT fields_list FROM table_name")
作为构建数据仓库的一部分,我必须查询大约 7500 万行的源数据库表。 我想对 7500 万行做一些处理,然后将结果添加到另一个数据库中。现在,这是相当多的数据,我主要通过两种方法取得了成功: 1)
我是一名优秀的程序员,十分优秀!