Wygląda Psycopg ma niestandardowe polecenie dla wykonania COPY:SQLAlchemy, psycopg2 i PostgreSQL KOPIA
psycopg2 COPY using cursor.copy_from() freezes with large inputs
Czy istnieje sposób, aby uzyskać dostęp do tej funkcji z z SQLAlchemy?
Wygląda Psycopg ma niestandardowe polecenie dla wykonania COPY:SQLAlchemy, psycopg2 i PostgreSQL KOPIA
psycopg2 COPY using cursor.copy_from() freezes with large inputs
Czy istnieje sposób, aby uzyskać dostęp do tej funkcji z z SQLAlchemy?
Być może trzeba będzie po prostu użyć psycopg2, aby ujawnić tę funkcjonalność i zrezygnować z możliwości ORM. Wydaje mi się, że tak naprawdę nie widzę korzyści z ORM w takiej operacji, ponieważ jest to prosta, luźna wstawka i zajmowanie się pojedynczymi obiektami, a ORM nie miałoby sensu.
Akceptowane odpowiedź jest poprawna, ale jeśli chcesz więcej niż tylko komentarzem EoghanM by iść na następujących pracował dla mnie w kopiując tabelę się CSV ...
from sqlalchemy import sessionmaker, create_engine
eng = create_engine("postgresql://user:[email protected]: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
nie jest konieczne, ale jeśli masz zwyczaj tworzenia silnika i sesji w tym samym czasie, aby użyć raw_connection
, musisz je rozdzielić (chyba że jest jakiś sposób na uzyskanie dostępu do silnika przez obiekt sesji, którego nie znam). Ciąg sql podany pod adresem copy_expert
również nie jest jedyną drogą do tego celu. Istnieje podstawowa funkcja copy_to
, której można używać z podzestawem parametrów, które przeszły normalne zapytanie COPY
DO. Ogólna wydajność polecenia wydaje mi się szybka, kopiując tabelę z ~ 20000 wierszy.
http://initd.org/psycopg/docs/cursor.html#cursor.copy_to http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.raw_connection
Jeśli silnik jest skonfigurowany z ciągu połączenia psycopg2 (która jest domyślna, więc albo "postgresql://..."
lub "postgresql+psycopg2://..."
), można utworzyć psycopg2 kursor z sesji SQL Alchemy korzystając
cursor = session.connection().connection.cursor()
których można użyć, aby wykonać
cursor.copy_from(...)
Kursor będzie aktywny w tej samej transakcji, co aktualnie sesja. Jeśli pojawi się commit
lub rollback
, każde dalsze użycie kursora z wyrzuceniem psycopg2.InterfaceError
, musisz utworzyć nowy.
Nie musisz zrzucać do psycopg2, używać raw_connection ani kursora.
Wystarczy wykonać sql jak zwykle, można nawet użyć parametry wiążą się z text()
:
engine.execute(text('''copy some_table from :csv
delimiter ',' csv'''
).execution_options(autocommit=True),
csv='/tmp/a.csv')
można upuścić jeśli execution_options(autocommit=True)
this PR będą przyjmowane
Po prostu ujawnij, że jest to twoje repozytorium kodu, które wydaje się być – Drew
Nie, ten związany jako "ten PR" nie jest moim repozytorium, to normalne/oficjalne repozytorium dla sqlalchemy. OTOH PR jest oczywiście mój, to nie jest tajemnica: używam tej samej nazwy użytkownika na stackoverflow i bitbucket. W każdym razie natknąłem się na to pytanie, badając przykłady tej zmiany, a wszystko, co napisałem, jest poprawne. Mógłbym uniknąć połączenia z PR, ale (w przypadku, gdy zostanie zaakceptowany), ta odpowiedź zasugeruje przestarzały fragment, chyba że ja lub ktoś zapamięta go aktualizować po fakcie – berdario
Można użyć:
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()
Wkładam 200000 linii w 5 sekund zamiast 4 minut
Czy możesz podać kilka szczegółów na temat tego, co '' '' Obiektem df jest? – EoghanM
df to parsa danych –
Jeśli można dostać się do silnika masz wszystko, czego potrzeba, aby to zrobić:
engine = create_engine('postgresql+psycopg2://myuser:[email protected]/mydb')
# or
engine = session.engine
# or any other way you know to get to the engine
Teraz można pracować.
# isolate a connection
connection = engine.connect().connection
# get the cursor
cursor = connection.cursor()
Oto niektóre szablony oświadczenie KOPIA korzystać z cursor.copy_expert()
, bardziej kompletne i wszechstronne opcje niż copy_from()
lub copy_to()
, jak wskazano poniżej: http://initd.org/psycopg/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
);
"""
Sprawdź, co opcje powyżej średniej i innych, które mogą być interesujące dla danej sytuacji https://www.postgresql.org/docs/current/static/sql-copy.html.
WAŻNA INFORMACJA: Łącze do dokumentacji cursor.copy_expert()
wskazuje na użycie STDOUT do wypisania do pliku i STDIN do skopiowania z pliku. Ale jeśli spojrzysz na składnię podręcznika PostgreSQL, zauważysz, że możesz również określić plik do zapisania bezpośrednio w instrukcji COPY. Nie rób tego, prawdopodobnie tracisz czas, jeśli nie pracujesz jako root (który uruchamia Pythona jako root podczas programowania?) Po prostu rób to, co jest wskazane w dokumentach psycopg2 i określ STDIN lub STDOUT w swoim oświadczeniu z cursor.copy_expert()
, Powinno być dobrze.
# 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()
super - może dostać się do psycopg przez engine.raw_connection() – EoghanM