Pandas: to_sql слишком медленный

Созданный на 1 февр. 2017  ·  24Комментарии  ·  Источник: pandas-dev/pandas

Образец кода,

df_name.to_sql('table_name',
                          schema = 'public',
                          con = engine,
                          index = False,
                          if_exists = 'replace')

Описание проблемы

Я пишу фрейм данных на 500 000 строк в базу данных postgres AWS, и на проталкивание данных уходит очень и очень много времени.

Это довольно большой SQL-сервер, и у меня отличное интернет-соединение, поэтому я исключил их как способствующие возникновению проблемы.

Для сравнения, csv2sql или использование cat и piping в psql в командной строке намного быстрее.

IO SQL Usage Question

Самый полезный комментарий

Добавьте этот код под engine = create_engine(connection_string) :

from sqlalchemy import event

@event.listens_for(e, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
    if executemany:
        cursor.fast_executemany = True
        cursor.commit()

В моем коде функция to_sql выполнялась 7 минут, а теперь она занимает всего 5 секунд;)

Все 24 Комментарий

см. здесь: http://stackoverflow.com/questions/33816918/write-large-pandas-dataframes-to-sql-server-database

с SQLServer вам нужно импортировать через csv с массовой загрузкой для эффективности

вы можете найти это полезным: http://odo.pydata.org/en/latest/perf.html

ODO не работает для меня, он генерирует ошибки, которые я не смог исправить, но d6tstack работал нормально https://github.com/d6t/d6tstack/blob/master/examples-sql.ipynb. Вы можете выполнить предварительную обработку с помощью pandas, и он использует postgres COPY FROM для быстрого импорта. Хорошо работает с RDS postgres.

Добавьте этот код под engine = create_engine(connection_string) :

from sqlalchemy import event

@event.listens_for(e, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
    if executemany:
        cursor.fast_executemany = True
        cursor.commit()

В моем коде функция to_sql выполнялась 7 минут, а теперь она занимает всего 5 секунд;)

Спасибо @llautert!
Это очень помогло!

# dont forget to import event
from sqlalchemy import event, create_engine

engine = create_engine(connection_string)

@event.listens_for(engine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
    if executemany:
        cursor.fast_executemany = True
        cursor.commit()

Я попытался запустить это исправление, но получил сообщение об ошибке:

AttributeError: 'psycopg2.extensions.cursor' object has no attribute 'fast_executemany'

Кто-нибудь знает, что происходит?

Привет, @ tim-sauchuk, тоже столкнулся с той же ошибкой, хотя я нашел решение, которое отлично работает, которое включает в себя небольшое редактирование файла pandas.io.sql.py (просто удалите файл .pyc из __pycache__ перед повторным импортом чтобы убедиться, что он записывает новую версию в сжатый файл)

https://github.com/pandas-dev/pandas/issues/8953

Привет, @ tim-sauchuk, тоже столкнулся с той же ошибкой, хотя я нашел решение, которое отлично работает, которое включает в себя небольшое редактирование файла pandas.io.sql.py (просто удалите файл .pyc из pycache перед

8953

Проблема № 8953, упомянутая @ bsaunders23, также показывает способ «обезьяньего патча» (исправления во время выполнения). Я попробовал, и набор данных из 20 тыс., Загрузка которого заняла 10+ минут, заняла всего 4 секунды.

Спасибо @llautert!
Это очень помогло!

# dont forget to import event
from sqlalchemy import event, create_engine

engine = create_engine(connection_string)

@event.listens_for(engine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
    if executemany:
        cursor.fast_executemany = True
        cursor.commit()

Кто-нибудь знает, как я могу реализовать это решение внутри класса с экземпляром self.engine?

Кто-нибудь знает, как я могу реализовать это решение внутри класса с экземпляром self.engine?

Работает для меня, ссылаясь на self.engine

Пример:

    self.engine = sqlalchemy.create_engine(connectionString, echo=echo)
    self.connection = self.engine.connect()

    @event.listens_for(self.engine, 'before_cursor_execute')
    def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
        print("Listen before_cursor_execute - executemany: %s" % str(executemany))
        if executemany:
            cursor.fast_executemany = True
            cursor.commit()

У меня не работает. Какие панды и версию sqlalchemy вы используете?

Я пробовал запускать sqlalchemy: 1.2.4-py35h14c3975_0 и 1.2.11-py35h7b6447c_0

но я получаю

AttributeError: объект 'psycopg2.extensions.cursor' не имеет атрибута 'fast_executemany'

@ dean12 @llautert

Как в этом контексте выглядит вызов функции? Или, другими словами, что вы используете в качестве аргументов для успешной загрузки таблицы?

<# dont forget to import event
from sqlalchemy import event, create_engine

engine = create_engine(connection_string)

@event.listens_for(engine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
    if executemany:
        cursor.fast_executemany = True
        cursor.commit()>``

Я пробовал запускать sqlalchemy: 1.2.4-py35h14c3975_0 и 1.2.11-py35h7b6447c_0

но я получаю

AttributeError: объект 'psycopg2.extensions.cursor' не имеет атрибута 'fast_executemany'

Вы используете psycopg2, драйвер postgresql. Эта проблема и исправление относятся к Microsoft SQL Server с использованием драйвера pyodbc.

как насчет добавления параметра 'dtype'

Кто-нибудь знает, как я могу реализовать это решение внутри класса с экземпляром self.engine?

Работает для меня, ссылаясь на self.engine

Пример:

    self.engine = sqlalchemy.create_engine(connectionString, echo=echo)
    self.connection = self.engine.connect()

    @event.listens_for(self.engine, 'before_cursor_execute')
    def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
        print("Listen before_cursor_execute - executemany: %s" % str(executemany))
        if executemany:
            cursor.fast_executemany = True
            cursor.commit()

Вы узнали как?

Я думаю, что правильным ответом должно быть использование https://docs.sqlalchemy.org/en/13/dialects/postgresql.html#psycopg2 -batch-mode-fast-execution, если вы пытаетесь сэкономить pandas dataframe в postgres

Новая версия pandas содержит параметр method который можно выбрать как "multi". Это заставляет код работать намного быстрее.

fast_executemany теперь можно выполнить за один шаг (sqlalchemy> = 1.3.0):

engine = sqlalchemy.create_engine(connection_string, fast_executemany=True)

Может, стоит упомянуть об этом где-нибудь в документации или на примере? Это частный случай, не связанный с пандами, но это небольшое дополнение, которое во многих случаях может значительно улучшить производительность.

Новая версия pandas содержит параметр method который можно выбрать как "multi". Это заставляет код работать намного быстрее.

Вы могли подумать, что установки параметра chunksize будет достаточно для выполнения пакетной вставки to_sql но нет.

Альтернативой для пользователей MS SQL является также использование turbodbc.Cursor.insertmanycolumns , я объяснил это в связанной публикации StackOverflow: https://stackoverflow.com/a/62671681/1689261

Будущим читателям предлагается два варианта использования batch_mode для to_sql. Ниже приведены две комбинации:

create_engine(connection_string, executemany_mode='batch', executemany_batch_page_size=x)

или же

create_engine(connection_string, executemany_mode='values', executemany_values_page_size=x)

Подробную информацию об этих аргументах можно найти здесь: https://docs.sqlalchemy.org/en/13/dialects/postgresql.html#psycopg2 -fast-execution-helpers

Для пользователей postgres я рекомендую установить method на вызываемый объект:

вызываемый с подписью (pd_table, conn, keys, data_iter): это можно использовать для реализации более производительного метода вставки, основанного на определенных функциях внутреннего диалекта.

и вызовите функцию из примера кода здесь https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html#insertion -method и

Использование COPY FROM действительно намного быстрее 🚀

Была ли эта страница полезной?
0 / 5 - 0 рейтинги