2012-10-29 12 views

Odpowiedz

6

It doesn't look like it.

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.

+2

super - może dostać się do psycopg przez engine.raw_connection() – EoghanM

20

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

+0

To było niesamowite znalezisko. Zmniejszyło to mój czas oszczędzania danych z 8 godzin + na noc do zaledwie 4 minut. O mój! – trench

+0

Pracowałem dla mnie, ale musiałem zrobić 'fake_conn.commit()' na końcu – Michael

11

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.

3

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

+0

Po prostu ujawnij, że jest to twoje repozytorium kodu, które wydaje się być – Drew

+0

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

2

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

+0

Czy możesz podać kilka szczegółów na temat tego, co '' '' Obiektem df jest? – EoghanM

+0

df to parsa danych –

0

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() 
Powiązane problemy