Pandas не могу записать все таблицы и строки в MySQL, используя SQLAlchemy - PullRequest
0 голосов
/ 21 апреля 2020

Я пытаюсь создать небольшое подмножество моих больших баз данных MS SQL Server на моем локальном диске в MySQL для аналитики / ML с использованием Python. Я успешно прочитал данные в Pandas фреймах данных, преобразовал все столбцы с типом данных объекта в строку, чтобы иметь дело только со строками типа float64, int64 и bool. Затем я записываю их в MySQL, используя dataframe.to_sql. Я использую SQLAlchemy для создания движка, и у меня есть Mysql-python-connector, чтобы сделать все в Python.

Проблема : при записи в локальную базу данных MySQL создаются все таблицы, но некоторые таблицы остаются пустыми, а в некоторых таблицах отсутствуют строки. Если я напишу тот же самый фрейм данных в SQLite, у меня не будет ни одной из этих проблем. Увеличение chunchsize помогло уменьшить количество пропущенных строк, а увеличение pool_recycle помогло уменьшить пустые таблицы, но не решило полностью ни одну из этих проблем. Особенно есть несколько конкретных c таблиц, которые никогда не заполняются. Анализ таблиц в MySQL показывает utf8mb4_0900_ai_ci как сопоставление таблиц, что в основном означает, что он использует utf8mb4 набор символов. Таблицы не очень большие, и самое большое, что у меня есть, это менее 200К строк и 50 столбцов. Процесс не занимает много времени, менее 10 минут для чтения и записи всех 22 таблиц.

Код:

import pandas as pd
import pyodbc 
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
import mysql.connector
import gc

def update_mysql_db(local_db_name:"database filename",
                    tables_to_update:"lists names of all the tables and their data"):

    '''Receives a list of pairs in the form of 
    (table name, table data in a datframe).
    Creates new tables in the local database with the data provided'''




    print(f"{len(tables_to_update)} tables will be updated/created")
    for table in tables_to_update:
        print('\n')
        print(f"reading {table[0]} dataframe")        

        try:
            table[1].to_sql(table[0].lower(),
                           create_engine('mysql+mysqlconnector://demo:Demo@localhost:3306/sqlalchemy',
                                        pool_recycle=36000, echo = False),
                            if_exists='replace',
                            index='True',
                            chunksize=5000,
                           index_label ='Index')

            print('Table {}.{} Created'.format(local_db_name,table[0].lower()))
        except ValueError as vx:
             print('Value Error : \n\n  ', vx)
        except Exception as ex:
              print('Exception : \n\n  ', ex)        


    gc.collect() 
    print('\n')
    print("Finished updating the local database")
    return None

def main():

    Local_db = 'sqlalchemy'
    update_mysql_db(Local_db,list_of_tablesnames_and_data)
    gc.collect()



if __name__ == "__main__":
    main()

Ошибки, которые я получаю:

reading SeminarEvaluationResponses dataframe
Exception during reset or similar
Traceback (most recent call last):
  File "C:\Sam\Anaconda\lib\site-packages\sqlalchemy\pool\base.py", line 693, in _finalize_fairy
    fairy._reset(pool)
  File "C:\Sam\Anaconda\lib\site-packages\sqlalchemy\pool\base.py", line 880, in _reset
    pool._dialect.do_rollback(self)
  File "C:\Sam\Anaconda\lib\site-packages\sqlalchemy\dialects\mysql\base.py", line 2302, in do_rollback
    dbapi_connection.rollback()
  File "C:\Sam\Anaconda\lib\site-packages\mysql\connector\connection_cext.py", line 386, in rollback
    self._cmysql.rollback()
_mysql_connector.MySQLInterfaceError: MySQL server has gone away
Exception : 

   MySQL server has gone away

Что еще: К сожалению, я не могу загрузить какие-либо фактические данные / базы данных / таблицы сюда, чтобы сделать код работоспособным. Я прыгаю, некоторые из вас, гуру, могут дать мне пару советов или указать мне правильное направление.

1 Ответ

1 голос
/ 21 апреля 2020

Похоже, что процесс может занять слишком много времени и время ожидания соединения. Судя по тому, сколько времени вы даете мне, сколько времени занимает написание этих данных, похоже, это так. Есть два варианта, которые не являются взаимоисключающими, поэтому вы можете сделать оба варианта, если это необходимо. Первый - увеличить время ожидания для вашего сервера MySQL. Вы можете сделать это в Python или MySQL Workbench, и этот ответ расскажет вам, как сделать это обоими способами.

Второй вариант, который немного сложнее, заключается в том, что вы можете переключиться с использования SQLAlchemy на непосредственное использование pyodb c для выполнения операций вставки. Само по себе это не быстрее, но позволяет вам превратить DataFrame, который вы пытаетесь сделать pu sh, в список кортежей, который быстрее, чем pu sh в запросе вставки, чем pu sh в DataFrame. с .to_sql(). Для вещей, которые SQLAlchemy обрабатывает автоматически, может потребоваться дополнительное кодирование, но это вариант для повышения вашей производительности. Тем не менее, я бы настоятельно рекомендовал попробовать первый сам по себе, чтобы убедиться, что это даже будет необходимо, прежде чем пытаться включить эту стратегию.

Для пропущенных строк я действительно не знаю, почему набор записей будет только частично вставлен в таблицу. Установлено ли для параметра autocommit значение True где-либо?

Наконец, этот ответ охватывает большую часть вопросов, и я не совсем точно оценил проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...