该方案使用了 Kieth 的fromiter技术,但更直观地处理 SQL 结果的二维表结构。此外,它通过避免 python 数据类型中的所有重塑和扁平化来改进 Doug 的方法。使用结构化数组,我们几乎可以直接从 MySQL 结果读取到 numpy,几乎完全删除了 python 数据类型。我说“几乎”是因为fetchall迭代器仍然产生 python 元组。
虽然有一个警告,但这并不是什么大问题。您必须提前知道列的数据类型和行数。
知道列类型应该很明显,因为您知道查询大概是什么,否则您总是可以使用 curs.description 和 MySQLdb.FIELD_TYPE.* 常量的映射。
知道行数意味着您必须使用客户端游标(这是默认设置)。我对 MySQLdb 和 MySQL 客户端库的内部结构知之甚少,但我的理解是,当使用客户端游标时,整个结果都会被提取到客户端内存中,尽管我怀疑实际上涉及到一些缓冲和缓存。这意味着对结果使用双倍内存,一次用于游标副本,一次用于数组副本,因此如果结果集很大,最好尽快关闭游标以释放内存。
严格来说,您不必提前提供行数,但这样做意味着数组内存是预先分配一次的,而不是随着更多行从迭代器进来而不断调整大小,这意味着提供巨大的性能提升。
有了这个,一些代码
import MySQLdb
import numpy
conn = MySQLdb.connect(host='localhost', user='bob', passwd='mypasswd', db='bigdb')
curs = conn.cursor() #Use a client side cursor so you can access curs.rowcount
numrows = curs.execute("SELECT id, rating FROM video")
#curs.fetchall() is the iterator as per Kieth's answer
#count=numrows means advance allocation
#dtype='i4,i4' means two columns, both 4 byte (32 bit) integers
A = numpy.fromiter(curs.fetchall(), count=numrows, dtype=('i4,i4'))
print A #output entire array
ids = A['f0'] #ids = an array of the first column
#(strictly speaking it's a field not column)
ratings = A['f1'] #ratings is an array of the second colum
有关如何指定列数据类型和列名的信息,请参阅 dtype 的 numpy 文档和上面有关结构化数组的链接。