Я хочу прочитать некоторые числовые (double, i.e. float64) данные из таблицы MySQL. Размер данных составляет ~ 200 тыс. Строк.
Ссылка 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): Как преобразовать результат SQL-запроса в pandas Структура данных?
Справочный код 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 секунд. Профилер говорит, что все время проведенное было в read_frame. Мне было интересно, может ли кто-нибудь дать мне несколько советов, как можно ускорить, по крайней мере, совпадение с кодом MATLAB. И если это вообще возможно в python.
EDIT:
Узкое место, кажется, находится внутри курсора .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 НЕ ПИМИСЛК EXECUTE! Я изменил его внутри файла "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?