Ugo*_*goL 6 python mysql numpy pandas
我试图读取一个由数百万行组成的非常大的 MySQL 表。我使用过Pandas库和chunks. 请参阅下面的代码:
import pandas as pd
import numpy as np
import pymysql.cursors
connection = pymysql.connect(user='xxx', password='xxx', database='xxx', host='xxx')
try:
with connection.cursor() as cursor:
query = "SELECT * FROM example_table;"
chunks=[]
for chunk in pd.read_sql(query, connection, chunksize = 1000):
chunks.append(chunk)
#print(len(chunks))
result = pd.concat(chunks, ignore_index=True)
#print(type(result))
#print(result)
finally:
print("Done!")
connection.close()
Run Code Online (Sandbox Code Playgroud)
实际上,如果我限制要选择的行数,执行时间是可以接受的。但是如果只想选择最少的数据(例如100 万行),那么执行时间会急剧增加。
也许有更好/更快的方法从python中的关系数据库中选择数据?
另一种选择可能是使用该multiprocessing模块,将查询划分并将其发送到多个并行进程,然后连接结果。
如果对分块了解不多pandas- 我认为您必须手动进行分块(这取决于数据)...不要使用 LIMIT / OFFSET - 性能会很糟糕。
这可能不是一个好主意,具体取决于数据。如果有一种有用的方法来分割查询(例如,如果它是一个时间序列,或者有某种适当的索引列可供使用,那么它可能是有意义的)。我在下面举了两个例子来展示不同的情况。
import pandas as pd
import MySQLdb
def worker(y):
#where y is value in an indexed column, e.g. a category
connection = MySQLdb.connect(user='xxx', password='xxx', database='xxx', host='xxx')
query = "SELECT * FROM example_table WHERE col_x = {0}".format(y)
return pd.read_sql(query, connection)
p = multiprocessing.Pool(processes=10)
#(or however many process you want to allocate)
data = p.map(worker, [y for y in col_x_categories])
#assuming there is a reasonable number of categories in an indexed col_x
p.close()
results = pd.concat(data)
Run Code Online (Sandbox Code Playgroud)
import pandas as pd
import MySQLdb
import datetime
def worker(a,b):
#where a and b are timestamps
connection = MySQLdb.connect(user='xxx', password='xxx', database='xxx', host='xxx')
query = "SELECT * FROM example_table WHERE x >= {0} AND x < {1}".format(a,b)
return pd.read_sql(query, connection)
p = multiprocessing.Pool(processes=10)
#(or however many process you want to allocate)
date_range = pd.date_range(start=d1, end=d2, freq="A-JAN")
# this arbitrary here, and will depend on your data /knowing your data before hand (ie. d1, d2 and an appropriate freq to use)
date_pairs = list(zip(date_range, date_range[1:]))
data = p.map(worker, date_pairs)
p.close()
results = pd.concat(data)
Run Code Online (Sandbox Code Playgroud)
可能有更好的方法来做到这一点(并且尚未经过适当的测试等)。如果你尝试一下,就有兴趣知道它是如何进行的。
您可以尝试使用不同的 mysql 连接器。我建议尝试mysqlclient哪个是最快的 mysql 连接器(我相信有相当大的优势)。
pymysql是一个纯 python mysql 客户端,而它mysqlclient是(更快的)C 库的包装器。
用法基本相同pymsql:
import MySQLdb
connection = MySQLdb.connect(user='xxx', password='xxx', database='xxx', host='xxx')
Run Code Online (Sandbox Code Playgroud)
在此处阅读有关不同连接器的更多信息:MySQLdb、mysqlclient 和 MySQL 连接器/Python 有何区别?