如何不使用SQLAlchemy引擎将数据帧写入Postgres表?

时间:2019-11-01 18:29:37

标签: python pandas postgresql sqlalchemy

我有一个要写入 Postgres 数据库的数据框。此功能必须是 Flask 应用的一部分。

现在,我通过创建 SQLAlchemy引擎并将其传递到from bs4 import BeautifulSoup import requests source = requests.get("https://www.google.com/search?q=online+education").text for soup in BeautifulSoup(source, 'lxml'): headline = soup.find("div", class_="BNeawe vvjwJb AP7Wnd") print(headline) 并将数据帧写入数据库表中,将该插入部分作为单独的脚本运行。 / p>

但是当我将此功能集成到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 个答案:

答案 0 :(得分:3)

您可以使用这些连接并避免使用SQLAlchemy。这听起来似乎不太直观,但是它将比常规插入快得多(即使您要删除ORM并进行常规查询(例如,使用executemany)也是如此。即使使用原始查询,插入也很慢,但是您会看到How to speed up insertion performance in PostgreSQL中多次提到COPY。在这种情况下,我采用以下方法的动机是:

  1. 使用COPY代替INSERT
  2. 不信任Pandas可以为此操作生成正确的SQL(尽管,正如IljaEverilä指出的那样,这种方法实际上得到了added to Pandas in 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()

这应该比实际插入要快几个数量级。