2011-02-23 17 views
5

Wprowadzam tabelę PostgreSQL z ~ 11.000.000 wierszy, które zostały wybrane wcześniej z innej bazy danych. Używam Pythona i psycopg2. Cały proces trwa około 1,5 godziny. Jednak po ~ 30 minutach otrzymuję wyjątek "nieoczekiwane zamknięcie połączenia". Kod źródłowy wygląda następująco:Połączenie PostgreSQL zamyka się nieoczekiwanie podczas wykonywania dużej wstawki

incursor = indb.cursor() 
incursor.execute("SELECT ...") 
indb.commit() # (1) close transaction 
outcursor = outdb.cursor() 
rows = 0 
for (col1, col2, col3) in incursor: # incursor contains ~11.000.000 rows 
    outcursor.execute("INSERT ...", (col1, col2, col3)) # This fails after ~30 minutes 
    row += 1 
    if row % 100 == 0: # (2) Write data every 100 rows 
     outcursor.close() 
     outdb.commit() 
     outcursor = outdb.cursor() 
incursor.close() 
outcursor.close() 
outdb.commit() 

włożeniu (1) i (2) po pierwszych próbach że nie, zakładając, że otwarta transakcja ma górny limit czasowy ~ 30 minut lub że kursor ma górny limit w toku wkładki. Wydaje się, że żadne z tych założeń nie jest prawdziwe, a błąd leży gdzie indziej.

Obie bazy danych są przechowywane na komputerze VirtualBox, który łączę za pośrednictwem przekazywania portów z hosta. Uruchomę program na hoście.

Obie bazy danych służą wyłącznie do celów testowych i nie mają innych połączeń do zarządzania. Być może muszę przerobić problem, aby obejść ten problem, ale potrzebuję bardzo czasochłonnych wstawek w innym miejscu (działającym przez około dni), więc jestem bardzo zaniepokojony niektórymi ukrytymi ograniczeniami czasowymi w psycopg2 lub PostgreSQL.

+1

Problem, że problem może tkwić w zmiennej work_mem w konfiguracji. AFAIK ta zmienna określa maksymalną pamięć dozwoloną dla jednego połączenia. Sprawdź, czy dzienniki powinny zawierać wpis o tym, co jest nie tak – Voooza

+0

Ale wtedy instrukcja SELECT w ogóle nie działałaby, czyż nie? Ale tracę połączenie z 'outdb'. – WolfgangA

+0

Użyj opcji "KOPIUJ" lub większych transakcji. Wykonywanie tylko 100 rekordów w ramach jednej transakcji daje około 110.000 transakcji do wykonania całej pracy. Pojedynczy dysk o prędkości 7400 obr./min może obsłużyć tylko 120 zatwierdzeń na sekundę (chyba że jest to spowodowane pamięcią podręczną, co powoduje, że nie jest ona wiarygodna). Twój obecny problem brzmi jak problem z siecią. –

Odpowiedz

4

Nie znam żadnego takiego "ukrytego" limitu czasu w samym Postgresql. PostgreSQL ma statement_timeout, ale jeśli trafisz, powinieneś uzyskać ERROR: canceling statement due to statement timeout w dzienniku serwera (i będzie on również rejestrował anulowane polecenie). Nie mogę mówić o psycopg2. Zdecydowanie sprawdź dziennik serwera pod kątem wszystkiego, co wygląda na trafne.

Może to problem sieciowy? Długoletnia instrukcja będzie połączeniem TCP, które pozostanie bezczynne przez długi czas. Być może przekazywanie portów usuwa połączenia, które są bezczynne przez ponad 30 minut? Może twoje połączenia TCP nie używają keepalive. Postgresql ma kilka ustawień do tuningu TCP keepalive (tcp_keepalives_interval itp.) I może być również potrzebna konfiguracja jądra/sieci, aby upewnić się, że są rzeczywiście włączone.

np. Po prostu próbowałem połączyć się z moją własną maszyną i domyślnie 7200, czyli 2 godziny. Jeśli przekierowanie portu zostanie przerwane po 30 minutach, ustawienie domyślne nie zostanie wykonane. Możesz zastąpić ustawienie używane w łańcuchu połączenia klienta (zakładając, że możesz bezpośrednio przekodować ciąg conninfo) lub ustawić zmienną GUC we właściwościach użytkownika/bazy danych lub postgresql.conf.

zobacz:

+0

Wielkie dzięki za linki! – WolfgangA

0

Aby wstawić millons wierszy, będę wyglądać za pośrednictwem oficjalnej guide do wypełniania i db rozważ użycie opcji copy.

0

Mam komendy django admin, które aktualizują tysiące tysięcy wierszy. Po pewnym czasie widzę ten sam błąd. Uważam, że użycie pamięci przekracza limit. Nie wiesz jednak, jak ręcznie sterować transakcją za pomocą poleceń.

Powiązane problemy