Я пытался прочитать очень большую таблицу 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?
Для тех, кто использует 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)
Другим вариантом может быть использование модуля multiprocessing
, деление запроса вверх и отправка его на несколько параллельных процессов, а затем объединение результатов.
Не зная много о pandas
chunking - я думаю, вам нужно будет выполнять рубинг вручную (что зависит от данных)... Не используйте 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)
Вероятно, более приятные способы сделать это (и не прошли надлежащую проверку и т.д.). Будьте заинтересованы, чтобы узнать, как это происходит, если вы попробуете это.
Вы можете попробовать использовать другой соединитель mysql. Я бы порекомендовал попробовать mysqlclient
который является самым быстрым соединителем mysql (на мой взгляд, значительным запасом).
pymysql
- это чистый клиент mysql python, тогда как mysqlclient
- оболочка вокруг (намного быстрее) библиотек C.
Использование в основном такое же, как pymsql
:
import MySQLdb
connection = MySQLdb.connect(user='xxx', password='xxx', database='xxx', host='xxx')
Подробнее о различных разъемах здесь: Какая разница между MySQLdb, mysqlclient и соединителем MySQL/Python?
SELECT *
для всей таблицы, может быть лучше другая структура данных (т.е. не MySQL)? В противном случае, наличие правильных индексов может иметь большое значение (оператор EXPLAIN
может помочь вам в этом и дать рекомендации по хорошим настройкам).