Похоже, в Psycopg есть специальная команда для выполнения COPY:
psycopg2 COPY с использованием cursor.copy_from () зависает с большими входными данными
Есть ли способ получить доступ к этой функции с помощью SQLAlchemy?
Похоже, в Psycopg есть специальная команда для выполнения COPY:
psycopg2 COPY с использованием cursor.copy_from () зависает с большими входными данными
Есть ли способ получить доступ к этой функции с помощью SQLAlchemy?
Возможно, вам придется просто использовать psycopg2, чтобы раскрыть эту функциональность, и отказаться от возможностей ORM. Думаю, я все равно не вижу преимущества ORM в такой операции, поскольку это прямая массовая вставка и работа с отдельными объектами в стиле ORM не имеет большого смысла.
принятый ответ правильный, но если вы хотите больше, чем просто комментарий EoghanM, для меня сработало следующее: КОПИРОВАНИЕ таблицы в CSV ...
from sqlalchemy import sessionmaker, create_engine
eng = create_engine("postgresql://user:pwd@host:5432/db")
ses = sessionmaker(bind=engine)
dbcopy_f = open('/tmp/some_table_copy.csv','wb')
copy_sql = 'COPY some_table TO STDOUT WITH CSV HEADER'
fake_conn = eng.raw_connection()
fake_cur = fake_conn.cursor()
fake_cur.copy_expert(copy_sql, dbcopy_f)
sessionmaker
не требуется, но если у вас есть привычка создавать движок и сеанс одновременно, чтобы использовать raw_connection
, вам нужно разделить их (если нет способа получить доступ к движку через объект сеанса, который я не знаю). Строка sql, предоставленная для copy_expert
, также не единственный способ сделать это, существует базовая функция copy_to
, которую вы можете использовать с подмножеством параметров, которые вы могли бы передать в обычный запрос COPY
TO. Общая производительность команды мне кажется быстрой, копируя таблицу из ~ 20000 строк.
http://initd.org/psycopg/docs/cursor.html#cursor.copy_to http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.raw_connection
fake_conn.commit()
- person Michael; 06.01.2017
Если ваш движок настроен со строкой подключения psycopg2 (которая используется по умолчанию, поэтому либо "postgresql://..."
, либо "postgresql+psycopg2://..."
), вы можете создать курсор psycopg2 из сеанса SQL Alchemy, используя
cursor = session.connection().connection.cursor()
который вы можете использовать для выполнения
cursor.copy_from(...)
Курсор будет активен в той же транзакции, что и текущий сеанс. Если произойдет commit
или rollback
, при дальнейшем использовании курсора с throw psycopg2.InterfaceError
вам придется создать новый.
connection.copy_from_table
, но он недоступен для курсора. Если я получу необработанное соединение, как в других ответах, оно не будет в той же транзакции.
- person tommyip; 20.01.2021
Ты можешь использовать:
def to_sql(engine, df, table, if_exists='fail', sep='\t', encoding='utf8'):
# Create Table
df[:0].to_sql(table, engine, if_exists=if_exists)
# Prepare data
output = cStringIO.StringIO()
df.to_csv(output, sep=sep, header=False, encoding=encoding)
output.seek(0)
# Insert data
connection = engine.raw_connection()
cursor = connection.cursor()
cursor.copy_from(output, table, sep=sep, null='')
connection.commit()
cursor.close()
Я вставляю 200000 строк за 5 секунд вместо 4 минут
df
?
- person EoghanM; 14.06.2017
pandas.DataFrame
имеет to_sql
, но этот метод здесь не используется. Вместо этого для сохранить df
в текстовом потоке в памяти, output
, который затем передается psycopg2
с помощью _7 _ а>.
- person Jonas Dahlbæk; 24.07.2018
CREATE TABLE ...
будет содержать соответствующие столбцы (или завершится ошибкой, если таблица уже существует), но не будет вставлять какие-либо данные.
- person Jonas Dahlbæk; 09.08.2018
Если вы начинаете с SQLAlchemy, вам нужно сначала перейти к механизму подключения (также известному по имени свойства bind
в некоторых объектах SQLAlchemy):
engine = create_engine('postgresql+psycopg2://myuser:password@localhost/mydb')
# or
engine = session.engine
# or any other way you know to get to the engine
Из движка вы можете изолировать соединение psycopg2:
# get a psycopg2 connection
connection = engine.connect().connection
# get a cursor on that connection
cursor = connection.cursor()
Вот несколько шаблонов для оператора COPY, которые можно использовать с cursor.copy_expert()
, более полным и гибким вариантом, чем copy_from()
или copy_to()
, как указано здесь: https://www.psycopg.org/docs/cursor.html#cursor.copy_expert.
# to dump to a file
dump_to = """
COPY mytable
TO STDOUT
WITH (
FORMAT CSV,
DELIMITER ',',
HEADER
);
"""
# to copy from a file:
copy_from = """
COPY mytable
FROM STDIN
WITH (
FORMAT CSV,
DELIMITER ',',
HEADER
);
"""
Узнайте, что означают приведенные выше параметры и другие, которые могут быть интересны в вашей конкретной ситуации https://www.postgresql.org/docs/current/static/sql-copy.html.
ВАЖНОЕ ПРИМЕЧАНИЕ. Ссылка на документацию cursor.copy_expert()
указывает на использование STDOUT для записи в файл и STDIN для копирования из файла. Но если вы посмотрите на синтаксис в руководстве PostgreSQL, вы заметите, что вы также можете указать файл для записи или из него непосредственно в операторе COPY. Не делайте этого, вы, скорее всего, просто напрасно тратите свое время, если вы не работаете с правами root (кто запускает Python как root во время разработки?). Просто делайте то, что указано в документации psycopg2, и укажите STDIN или STDOUT в своем заявлении с помощью cursor.copy_expert()
, все должно быть хорошо.
# running the copy statement
with open('/path/to/your/data/file.csv') as f:
cursor.copy_expert(copy_from, file=f)
# don't forget to commit the changes.
connection.commit()
Вам не нужно опускаться до psycopg2, использовать raw_connection или курсор.
Просто выполните sql как обычно, вы даже можете использовать параметры привязки с _ 1_:
engine.execute(text('''copy some_table from :csv
delimiter ',' csv'''
).execution_options(autocommit=True),
csv='/tmp/a.csv')
Вы можете отказаться от execution_options(autocommit=True)
, если этот PR будет принят