我经常编写很少的Python脚本来遍历数据库表的所有行。 例如,向所有订阅者发送电子邮件。
我这样做
conn = MySQLdb.connect(host = hst, user = usr, passwd = pw, db = db)
cursor = conn.cursor()
subscribers = cursor.execute("SELECT * FROM tbl_subscriber;")
for subscriber in subscribers:
...
conn.close()
我想知道是否有更好的方法来执行此操作,因为我的代码可能会将数千行加载到内存中。
我认为用LIMIT
可以做得更好。
也许是这样的:
"SELECT * FROM tbl_subscriber LIMIT %d,%d;" % (actualLimit,steps)
最好的办法是什么? 你会怎么做?
答案 0 :(得分:38)
除非你有BLOB,否则成千上万的行应该不成问题。你知道吗?
另外,为什么要通过做类似
之类的事情给自己和整个家庭带来耻辱"SELECT * FROM tbl_subscriber LIMIT %d,%d;" % (actualLimit,steps)
当光标以避免SQL注入的方式替换你时?
c.execute("SELECT * FROM tbl_subscriber LIMIT %i,%i;", (actualLimit,steps))
答案 1 :(得分:16)
您不必修改查询,可以使用游标的 fetchmany 方法。我是这样做的:
def fetchsome(cursor, some=1000):
fetch = cursor.fetchmany
while True:
rows = fetch(some)
if not rows: break
for row in rows:
yield row
这样你就可以“SELECT * FROM tbl_subscriber;”但是你一次只能获取一些。
答案 2 :(得分:7)
基于libmysqlclient的大多数MySQL连接器会出于性能原因默认缓存客户端内存中的所有结果(假设您不会读取大型结果集)。
如果确实需要在MySQLdb中读取大结果,可以使用SSCursor来避免缓冲整个大型结果集。
http://mysql-python.sourceforge.net/MySQLdb.html#using-and-extending
SSCursor - 一个“服务器端”游标。像光标一样 但使用CursorUseResultMixIn。使用 只有你在处理 可能很大的结果集。
这确实会引入您必须小心的并发症。如果您没有从游标中读取所有结果,则第二个查询将引发ProgrammingError:
>>> import MySQLdb
>>> import MySQLdb.cursors
>>> conn = MySQLdb.connect(read_default_file='~/.my.cnf')
>>> curs = conn.cursor(MySQLdb.cursors.SSCursor)
>>> curs.execute('SELECT * FROM big_table')
18446744073709551615L
>>> curs.fetchone()
(1L, '2c57b425f0de896fcf5b2e2f28c93f66')
>>> curs.execute('SELECT NOW()')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.6/site-packages/MySQLdb/cursors.py", line 173, in execute
self.errorhandler(self, exc, value)
File "/usr/lib64/python2.6/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
raise errorclass, errorvalue
_mysql_exceptions.ProgrammingError: (2014, "Commands out of sync; you can't run this command now")
这意味着你必须在发出另一个之前总是从光标(可能还有多个结果集)中读取所有内容--MySQLdb不会为你做这个。
答案 3 :(得分:2)
首先,您可能不需要Select * from ...
也许只是为了得到一些东西就足够了:“从...中选择电子邮件”
无论如何会减少内存使用量:)
答案 4 :(得分:1)
你有实际的记忆问题吗?迭代游标时,会一次一个地获取结果(您的DB-API实现可能决定预取结果,但它可能会提供一个函数来设置预取结果的数量)。
答案 5 :(得分:0)
RS_1st = win32com.client.Dispatch(r'ADODB.Recordset') RS_1st.Open(“SELECT colA_, colB_, colC_ FROM tbl_subscriber “, Conn, CursorType = 3, LockType = 1)
对于 numpy.transpose(RS_1st.GetRows()).tolist() 中的 colA_、colB_、colC_:
或
对于 numpy.transpose(RS_1st.GetRows()).tolist() 中的 arrCol_:
或
cursor.execute("SELECT * FROM tbl_subscriber;")
对于 cursor.fetchall() 中的订阅者: