Psycopg2, Postgresql, Python: najszybszy sposób na bulk-insert

Szukam najskuteczniejszego sposobu na masowe wstawianie kilku milionów krotek do bazy danych. Używam Pythona, PostgreSQL i psycopg2 .

Stworzyłem długą listę tulpes, które należy wstawić do bazy danych, czasami z modyfikatorami jak geometryczne Simplify.

Naiwnym sposobem na to byłoby formatowanie listy poleceń INSERT, ale są trzy inne metody, o których czytałem:

  1. za pomocą pyformat styl wiązania dla wstawianie parametryczne
  2. używając executemany na liście krotek i
  3. za pomocą zapisu wyników do pliku i za pomocą COPY.

Wydaje się, że pierwszy sposób jest najbardziej skuteczny, ale byłbym wdzięczny za spostrzeżenia i fragmenty kodu mówiące mi, jak to zrobić dobrze.

Author: Community, 2010-02-16

8 answers

Tak, zagłosowałbym za COPY, pod warunkiem, że można zapisać plik na dysku twardym serwera (NIE Dysku, na którym działa aplikacja), ponieważ COPY odczyta tylko serwer.

 13
Author: Andy Shellam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-16 09:41:02

Jest Nowy Podręcznik psycopg2 zawierający przykłady wszystkich opcji.

Opcja COPY jest najbardziej efektywna. Następnie wykonywany. Następnie wykonaj z pyformat.

 10
Author: piro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-16 10:18:57

Z mojego doświadczenia {[0] } nie jest wcale szybszy niż samodzielne uruchamianie wielu wstawek, najszybszym sposobem jest samodzielne sformatowanie pojedynczego INSERT z wieloma wartościami, może w przyszłości executemany poprawi się, ale na razie jest to dość powolne

Podklasuję a list i przeciążam metodę append, więc gdy lista osiągnie określony rozmiar formatuję INSERT, aby ją uruchomić

 7
Author: FlashDD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-02 12:14:24

Możesz użyć nowej biblioteki upsert :

$ pip install upsert

(być może będziesz musiał pip install decorator najpierw)

conn = psycopg2.connect('dbname=mydatabase')
cur = conn.cursor()
upsert = Upsert(cur, 'mytable')
for (selector, setter) in myrecords:
    upsert.row(selector, setter)

Gdzie selector jest obiektem dict podobnym do {'name': 'Chris Smith'} i setter jest obiektem dict podobnym do { 'age': 28, 'state': 'WI' }

Jest to prawie tak szybkie, jak pisanie niestandardowego kodu INSERT [/UPDATE] i uruchamianie go bezpośrednio za pomocą psycopg2... i nie wybuchnie, jeśli rząd już istnieje.

 6
Author: Seamus Abshere,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-27 01:27:02

Pierwszy i drugi będą używane razem, a nie osobno. Trzeci byłby jednak najbardziej wydajnym serwerem, ponieważ serwer wykonałby całą ciężką pracę.

 1
Author: Ignacio Vazquez-Abrams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-16 09:39:15

Po kilku testach, unnest często wydaje się być niezwykle szybką opcją, o czym dowiedziałem się od @Clodoaldo Neto's ' s odpowiedź na podobne pytanie.

data = [(1, 100), (2, 200), ...]  # list of tuples

cur.execute("""CREATE TABLE table1 AS
               SELECT u.id, u.var1
               FROM unnest(%s) u(id INT, var1 INT)""", (data,))

Jednak, to może być trudne z bardzo dużych danych .

 1
Author: n1000,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:09

Każdy, kto używa SQLAlchemy, mógł wypróbować wersję 1.2, która dodała obsługę bulk insert do korzystania z psycopg2.dodatki.execute_batch () zamiast executemany podczas inicjalizacji silnika za pomocą use_batch_mode = True jak:

engine = create_engine(
    "postgresql+psycopg2://scott:tiger@host/dbname",
    use_batch_mode=True)

Http://docs.sqlalchemy.org/en/latest/changelog/migration_12.html#change-4109

Wtedy ktoś musiałby użyć SQLalchmey nie będzie próbował różnych kombinacji sqla i psycopg2 i direct SQL razem.

 1
Author: user2189731,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-02 02:06:31

Bardzo podobne pytanie: Bulk insert with SQLAlchemy ORM


Wszystkie drogi prowadzą do Rzymu , ale niektóre z nich przecina góry, wymaga promów, ale jeśli chcesz dostać się tam szybko po prostu autostradą.


W tym przypadku autostradą jest użycie execute_batch () funkcji psycopg2 . Dokumentacja mówi to najlepiej:

Obecna implementacja executemany() jest (używając niezwykle dobroczynnego niedopowiedzenia) nie szczególnie wydajny. Funkcje te mogą być użyte do przyspieszenia powtarzającego się wykonywania instrukcji względem zestawu parametrów. Zmniejszając liczbę serwerów, wydajność może być o rząd wielkości lepsza niż przy użyciu executemany().

W moim własnym teście execute_batch()jest około dwa razy szybszy niż executemany() i daje możliwość skonfigurowania page_size do dalszego poprawiania (jeśli chcesz wycisnąć ostatnie 2-3% wydajności ze sterownika).

Ta sama funkcja można je łatwo włączyć, jeśli używasz SQLAlchemy, ustawiając use_batch_mode=True jako parametr, gdy tworzysz instancję z create_engine()

 0
Author: chjortlund,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-13 14:27:06