我试图读取一个由几百万行组成的非常巨大的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()
实际上,如果我限制要选择的行数,则执行时间是可以接受的。但是,如果只选择最少的数据(例如 1百万行),则执行时间将大大增加。
也许有更好/更快的方法从python中的关系数据库中选择数据?
答案 0 :(得分:0)
您可以尝试使用其他mysql连接器。我建议尝试使用mysqlclient
,它是最快的mysql连接器(我相信相当可观)。
pymysql
是一个纯python mysql客户端,而mysqlclient
则包装了(更快)的C库。
用法基本上与pymsql
相同:
import MySQLdb
connection = MySQLdb.connect(user='xxx', password='xxx', database='xxx', host='xxx')
在此处了解有关不同连接器的更多信息:What's the difference between MySQLdb, mysqlclient and MySQL connector/Python?
答案 1 :(得分:0)
另一种选择可能是使用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)
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)
执行此操作的方法可能更好(并且没有经过适当的测试等)。有兴趣知道如何尝试。
答案 2 :(得分:0)
对于使用Windows且无法安装MySQLdb的用户。我正在使用这种方式从巨大的表中获取数据。
import mysql.connector
i = 1
limit = 1000
while True:
sql = "SELECT * FROM super_table LIMIT {}, {}".format(i, limit)
cursor.execute(sql)
rows = self.cursor.fetchall()
if not len(rows): # break the loop when no more rows
print("Done!")
break
for row in rows: # do something with results
print(row)