Самый быстрый способ прочитать огромную таблицу MySQL в Python

0

Я пытался прочитать очень большую таблицу 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?

Теги:
pandas
numpy

3 ответа

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)
0

Другим вариантом может быть использование модуля multiprocessing, деление запроса вверх и отправка его на несколько параллельных процессов, а затем объединение результатов.

Не зная много о pandas chunking - я думаю, вам нужно будет выполнять рубинг вручную (что зависит от данных)... Не используйте LIMIT/OFFSET - производительность будет ужасной.

Это может быть не очень хорошая идея, в зависимости от данных. Если есть полезный способ разделить запрос (например, если это временные ряды или какой-то подходящий индексный столбец для использования, это может иметь смысл). Я привел два примера ниже, чтобы показать разные случаи.

Пример 1

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) 

Пример 2.

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)

Вероятно, более приятные способы сделать это (и не прошли надлежащую проверку и т.д.). Будьте заинтересованы, чтобы узнать, как это происходит, если вы попробуете это.

  • 0
    Я думаю, что я не совсем понимаю, как работают эти примеры ... скажем, первый. Вы отображаете и вызываете функцию работника для каждого элемента списка col_x_categories. Но где мы определяем y и col_x_categories? И я предположил, что эта операция карты распараллелена для n процессов.
0

Вы можете попробовать использовать другой соединитель 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?

  • 0
    Спасибо @djmac за это предложение. Я попробую. Что я могу принять во внимание для ускорения процесса чтения в целом? Может быть, это решение не так хорошо оптимизировано?
  • 0
    Честно говоря, я думаю , что это в основном вид во многом зависит от структуры базы данных (и данные). Если вы действительно делаете SELECT * для всей таблицы, может быть лучше другая структура данных (т.е. не MySQL)? В противном случае, наличие правильных индексов может иметь большое значение (оператор EXPLAIN может помочь вам в этом и дать рекомендации по хорошим настройкам).
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню