2009-10-01 32 views
8

Próbuję wykonać zapytanie postgresql która zwraca dużą wynik:JDBC + duży zapytań PostgreSQL rozdawać pamięci

connection.setAutoCommit(false); 
st = connection.createStatement(
    ResultSet.CONCUR_READ_ONLY, 
    ResultSet.TYPE_FORWARD_ONLY 
); 
st.setFetchSize(100); 
logMemory(); 
System.out.println("start query "); 
rs = st.executeQuery(queryString); 
System.out.println("done query "); 
logMemory(); 

ale ten zużywa dużo pamięci:

Free memory; 4094347680 (= 3905 mb). 
start query 
done query 
Free memory; 2051038576 (= 1956 mb). 

(wydrukowano za pomocą Runtime.getRuntime(). freeMemory())

Do tej pory działa, ale baza danych będzie dużo większa. Nigdy nie potrzebuję całego wyniku w pamięci; Potrzebuję tylko przetworzyć każdy wiersz, zapisać wyniki na dysku i przejść do następnego wiersza.

Wiem, że "setFetchSize" jest tylko podpowiedź, ale byłoby dziwne, gdyby postgresql/jdbc zignorował go, jak to jest przez wieki.

Jakikolwiek sposób obejścia tego? Jedynym moim dotychczasowym pomysłem jest utworzenie skryptu wsadowego przesyłającego wynik zapytania do dysku, a następnie przeanalizowanie pliku z Java ...

+0

Po prostu ciekawy, jaki jest maksymalny rozmiar sterty, z którego korzystasz? Czy używasz domyślnie? –

+1

To jest -Xmx4096M-Xms4096M, jest to maszyna o rozmiarze 8 GB. – kresjer

Odpowiedz

7

Ouch, to jeden z najbardziej nieprzyjemnych błędów przy użyciu JDBC, które widziałem. Należy zmienić

st = connection.createStatement(
    ResultSet.CONCUR_READ_ONLY, 
    ResultSet.TYPE_FORWARD_ONLY 
); 

do

st = connection.createStatement(
    ResultSet.TYPE_FORWARD_ONLY, 
    ResultSet.CONCUR_READ_ONLY 
); 

Może po prostu

st = connection.createStatement(); 

będzie działać jak dobrze (jak już spełnione inne kryteria dla kursora).

+0

co to za błąd? czy to prawdziwy wyciek pamięci czy coś innego się dzieje? Czy myślisz, że to tylko postgres? – rogerdpack

+0

@rogerdpack OP zmienił parametry metody dla 'createStatement'. Oba parametry są "int'-s", ale oznaczają różne rzeczy. Nie jest to więc żaden błąd w implementacji JDBC. –

9

Here są wytycznymi dla zapewnienia, że ​​zestaw wyników jest faktycznie pobierany za pomocą kursora . Wygląda na to, że trafiłeś na wszystkie znane w twoim kodzie, ale nie określiłeś instrukcji, więc może być kilka zawiązanych razem ze średnikami (mało prawdopodobne, przez wygląd twojego kodu). Musisz używać protokołu V3 (wersja 7.4 lub nowsza). Czy wszystkie te rzeczy odnoszą się do twojej sprawy?

+0

Tak, próbowałem włączyć/wyłączyć wszystkie wytyczne. Oświadczenie to po prostu Wybierz hh.data, hh.customer_ID z dataTable hh dołącz PH klienta na hh.customer_ID = PH.customer_ID; i jest postgresql 8.3 i używam postgresql-8.3-603.jdbc4.jar. – kresjer

+0

Jestem zaskoczony. Powiedziałbym, że następnym najlepszym krokiem jest publikowanie w grupach, które koncentrują się na Postgresql. Prawdopodobnie istnieją pewne inne nieoczywiste rzeczy, które powodują/mogą wymuszać na połączeniu użycie kursora. Otworzyłem kod źródłowy JDBC (co jest miłe w open source) i zobacz, co się dzieje w twoim scenariuszu. – Yishai

+1

Wielkie dzięki za odpowiedź. Walczyłem z tym problemem przez cały dzień, dopóki nie znalazłem wymogu dla 'conn.setAutoCommit (false)' na cytowanej stronie. – jutky

Powiązane problemy