Как записать фрейм данных в таблицу Postgres без использования движка SQLAlchemy? - PullRequest
0 голосов
/ 01 ноября 2019

У меня есть фрейм данных, который я хочу записать в базу данных Postgres . Эта функциональность должна быть частью Flask приложения.

На данный момент я запускаю эту часть вставки в виде отдельного скрипта, создав SQLAlchemy engine и передавэто df.to_sql() для записи фрейма данных в таблицу базы данных.

Но когда я интегрирую эту функцию в приложение Flask, у меня уже есть существующие подключения к базе данных Postgres , которые былисозданный с использованием Пул соединений Psycopg2 .

При просмотре документации df.to_sql() упоминается, что он использует механизм SQLAlchemy . Я не вижу другого механизма подключения. https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_sql.html#pandas-dataframe-to-sql

Мой вопрос: зачем мне нужен этот движок SQLAlchemy, когда у меня есть существующие соединения. Почему я не могу их использовать?

1 Ответ

3 голосов
/ 01 ноября 2019

Вы можете использовать эти соединения и избежать SQLAlchemy. Это будет звучать довольно неинтуитивно, но это будет намного быстрее, чем обычные вставки (даже если вы отбросили ORM и сделаете общий запрос, например, с executemany). Вставки выполняются медленно, даже с необработанными запросами, но вы увидите, что COPY упоминается несколько раз в Как повысить производительность вставки в PostgreSQL . В этом случае мои мотивы для подхода ниже:

  1. Использование COPY вместо INSERT
  2. Не доверяйте Пандам генерировать правильный SQL для этой операции (хотя, как отметил Илья Эверила, этот подход на самом деле добавил к Пандам в V0.24 )
  3. Не записывайте данные на диск, чтобы создать настоящий объект файла;сохранить все это в памяти

Предлагаемый подход с использованием cursor.copy_from():

import csv
import io
import psycopg2

df = "<your_df_here>"

# drop all the columns you don't want in the insert data here

# First take the headers
headers = df.columns

# Now get a nested list of values
data = df.values.tolist()

# Create an in-memory CSV file
string_buffer = io.StringIO()
csv_writer = csv.writer(string_buffer)
csv_writer.writerows(data)

# Reset the buffer back to the first line
string_buffer.seek(0)

# Open a connection to the db (which I think you already have available)
with psycopg2.connect(dbname=current_app.config['POSTGRES_DB'], 
                      user=current_app.config['POSTGRES_USER'],
                      password=current_app.config['POSTGRES_PW'], 
                      host=current_app.config['POSTGRES_URL']) as conn:
    c = conn.cursor()

    # Now upload the data as though it was a file
    c.copy_from(string_buffer, 'the_table_name', sep=',', columns=headers)
    conn.commit()

Это должно быть на несколько порядков быстрее, чем на самом деле вставка.

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