【发布时间】:2014-04-06 02:25:55
【问题描述】:
我想从 MySQL 表中读取一些数字(双精度,即 float64)数据。数据的大小约为 200k 行。
MATLAB 参考:
tic;
feature accel off;
conn = database(...);
c=fetch(exec(conn,'select x,y from TABLENAME'));
cell2mat(c.data);
toc
经过的时间约为 1 秒。
在 python 中做同样的事情,使用这里的几个例子(我都试过了,即使用 pandas read_frame、frame_query 和 __processCursor 函数): How to convert SQL Query result to PANDAS Data Structure?
参考python代码:
import pyodbc
import pandas.io.sql as psql
import pandas
connection_info = "DRIVER={MySQL ODBC 3.51 \
Driver};SERVER=;DATABASE=;USER=;PASSWORD=;OPTION=3;"
cnxn = pyodbc.connect(connection_info)
cursor = cnxn.cursor()
sql = "select x,y from TABLENAME"
#cursor.execute(sql)
#dataframe = __processCursor(cursor, dataframe=True)
#df = psql.frame_query(sql, cnxn, coerce_float=False)
df = psql.read_frame(sql, cnxn)
cnxn.close()
大约需要 6 秒。 Profiler 说所有花费的时间都在 read_frame 中。 我想知道是否有人可以给我一些提示,这将如何加速以至少匹配 MATLAB 代码。如果这在 python 中是可能的。
编辑:
瓶颈似乎在 cursor.execute (在 pymysql 库中)或 cursor.fetchall() 在 pyodbc 库中。最慢的部分是逐个元素(逐行、逐列)读取返回的 MySQL 数据并将其转换为之前由同一库推断的数据类型。
到目前为止,我已经设法通过这个非常肮脏的解决方案将其加速到接近 MATLAB:
import pymysql
import numpy
conn = pymysql.connect(host='', port=, user='', passwd='', db='')
cursor = conn.cursor()
cursor.execute("select x,y from TABLENAME")
rez = cursor.fetchall()
resarray = numpy.array(map(float,rez))
finalres = resarray.reshape((resarray.size/2,2))
上面的 cur.execute 不是 pymysql 执行的! 我已经在文件“connections.py”中修改了它。首先,函数 def _read_rowdata_packet,现在改为:
rows.append(self._read_row_from_packet(packet))
替换为
self._read_string_from_packet(rows,packet)
这里 _read_string_from_packet 是 _read_row_from_packet 的简化版,代码如下:
def _read_string_from_packet(self, rows, packet):
for field in self.fields:
data = packet.read_length_coded_string()
rows.append(data)
这是一个超级肮脏的解决方案,可将加速时间从 6 秒缩短到 2.5 秒。我想知道,是否可以通过使用不同的库/传递一些参数来避免所有这些?
因此解决方案是批量读取整个 MySQL 对字符串列表的回复,然后批量类型转换为数字数据类型,而不是逐个元素地进行。 python中是否已经存在类似的东西?
【问题讨论】:
-
stackoverflow.com/questions/7061824/… 上的答案建议使用
fetchall,后跟np.fromiter(可能会进行一些调整)。 -
感谢 hpaulj,我已经测试过了 - 与其他方法相同(慢)的速度。我认为的问题是将数据从网络导入本机 python 数据类型。因此,在 MySQLdb 和 pymysql 中,这都发生在 cursor.execute() 中,如果我理解正确,这是一个不正确的实现,因为在简单地执行 SQL 语句后,不应将任何内容“提取”到本机数据类型中。
标签: python mysql numpy pandas mysql-python