迭代DB表中所有行的最佳方法

时间:2010-09-24 08:14:56

标签: python mysql database

我经常编写很少的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)    

最好的办法是什么? 你会怎么做?

6 个答案:

答案 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() 中的订阅者: