Il "problema" sembra essere stato la conversione del tipo che si verifica dal tipo decimal di MySQL al decimal.Decimal di Python che MySQLdb, pymysql e pyodbc fanno sui dati. Modificando il file converters.py (nelle ultime righe) in MySQLdb per avere:
conversions[FIELD_TYPE.DECIMAL] = float
conversions[FIELD_TYPE.NEWDECIMAL] = float
invece di decimal.Decimal sembra risolvere completamente il problema e ora il codice seguente:
import MySQLdb
import numpy
import time
t = time.time()
conn = MySQLdb.connect(host='',...)
curs = conn.cursor()
curs.execute("select x,y from TABLENAME")
data = numpy.array(curs.fetchall(),dtype=float)
print(time.time()-t)
Funziona in meno di un secondo! Che cosa è divertente, decimale. Il decimale non è mai sembrato essere il problema nel profiler.
Una soluzione simile dovrebbe funzionare nel pacchetto pymysql. pyodbc è più complicato:è tutto scritto in C++, quindi dovresti ricompilare l'intero pacchetto.
AGGIORNAMENTO
Ecco una soluzione che non richiede la modifica del codice sorgente di MySQLdb:Python MySQLdb restituisce datetime.date e decimale La soluzione quindi per caricare dati numerici nei panda:
import MySQLdb
import pandas.io.sql as psql
from MySQLdb.converters import conversions
from MySQLdb.constants import FIELD_TYPE
conversions[FIELD_TYPE.DECIMAL] = float
conversions[FIELD_TYPE.NEWDECIMAL] = float
conn = MySQLdb.connect(host='',user='',passwd='',db='')
sql = "select * from NUMERICTABLE"
df = psql.read_frame(sql, conn)
Batte MATLAB di un fattore di ~4 nel caricamento di 200k x 9 tabelle!