#python #mysql #python-3.x #pandas #sqlalchemy
#python #mysql #python-3.x #панды #sqlalchemy
Вопрос:
Я использую MySQL с pandas и sqlalchemy. Однако он работает чрезвычайно медленно. Выполнение такого простого запроса, как этот, занимает более 11 минут для таблицы с 11 миллионами строк. Какие действия могли бы улучшить эту производительность? Упомянутая таблица не имеет первичного ключа и была проиндексирована только по одному столбцу.
from sqlalchemy import create_engine
import pandas as pd
sql_engine_access = 'mysql pymysql://root:[password]@localhost')
sql_engine = create_engine(sql_engine_access, echo=False)
script = 'select * from my_database.my_table'
df = pd.read_sql(script, con=self.sql_engine)
Комментарии:
1. Вы извлекаете эти строки из облачного экземпляра или из-за относительно медленного сетевого подключения? Один миллион строк в минуту — это 16,7 тысячи строк в секунду, что не так уж и медленно (примерно половина скорости моего локального подключения к локальной сети).
2. все записи были извлечены с помощью команды выполнения sqlachemy из python. Для этого потребовалось более 12 часов (для извлечения около 11 миллионов строк и 58 столбцов). Сервер установлен на том же компьютере, на котором был запущен код python. Нет доступа к локальной сети или облаку. Этот компьютер имеет 32 ГБ памяти и процессор AMD с 12 ядрами, использующий MS Windows 10 pro.
3. Я также заметил, что диск интенсивно используется во время этих процессов
Ответ №1:
Вы можете попробовать наш инструмент connectorx ( pip install -U connectorx
). Он реализован в Rust и нацелен на повышение производительности pandas.read_sql
. API в основном такой же, как у pandas
. Например, в вашем случае код будет выглядеть так:
import connectorx as cx
conn_url = "mysql://root:[password]@localhost:port/my_database"
query = "select * from my_table"
df = cx.read_sql(conn_url, query)
Если в результате вашего запроса числовой столбец равномерно распределен, как ID, вы также можете еще больше ускорить процесс, используя несколько ядер, подобных этому:
df = cx.read_sql(conn_url, query, partition_on="ID", partition_num=4)
Это разделило бы весь запрос на четыре небольших запроса путем фильтрации по ID
столбцу и connectorx
выполняло бы их параллельно. Вы можете проверить здесь для получения дополнительной информации об использовании и примерах.
Вот результат теста, загружающий 60 миллионов строк x 16 столбцов из MySQL в фрейм данных pandas с использованием 4 ядер:
Ответ №2:
Хотя, возможно, это не единственная причина низкой производительности, одним из факторов, способствующих этому, является то, что PyMySQL ( mysql pymysql://
) может быть значительно медленнее, чем mysqlclient ( mysql mysqldb://
) при больших нагрузках. В очень неформальном тесте (без многократных запусков, без усреднения, без перезапуска сервера) Я видел следующие результаты, используя df.read_sql_query()
локальную базу данных MySQL:
извлеченные строки | mysql mysqldb (секунды) | mysql pymysql (секунды) |
---|---|---|
1_000_000 | 13.6 | 54.0 |
2_000_000 | 25.9 | 114.1 |
3_000_000 | 38.9 | 171.5 |
4_000_000 | 62.8 | 217.0 |
5_000_000 | 78.3 | 277.4 |
Комментарии:
1. Спасибо, Томпсон, за ваш ответ и за улучшение моего вопроса. На самом деле, я изменил на «mysql mysqldb //», и мой запрос перешел к 4 mind вместо 11. Это намного лучше, хотя я считаю, что еще есть возможности для повышения производительности с помощью других действий.