2011-09-08 31 views
15

Muszę spożywać dość duże ilości danych z codziennego pliku CSV. Plik CSV zawiera około 120 000 rekordów. Powoduje to spowolnienie indeksowania podczas korzystania ze stanu hibernacji. Zasadniczo wygląda na to, że hibernacja wykonuje SELECT przed każdym pojedynczym INSERT (lub UPDATE) przy użyciu saveOrUpdate(); dla każdej instancji utrzymywanej przez saveOrUpdate(), SELECT jest wydawane przed faktycznym INSERT lub UPDATE. Mogę zrozumieć, dlaczego to robi, ale jest to strasznie nieefektywne w przetwarzaniu zbiorczym i szukam alternatyw.Wstawianie zbiorcze LUB aktualizowanie za pomocą hibernacji?

Jestem przekonany, że problem z wydajnością leży w sposobie, w jaki używam do tego hibernacji, ponieważ dostałem kolejną wersję działającą z natywnym SQL (który parsuje CSV w ten sam sposób) i jego dosłownie działającymi kółkami wokół nowej wersji)

Tak więc, do faktycznego pytania, czy hibernacja jest alternatywą dla mysqlów "INSERT ... ON DUPLICATE "istnieje składnia?

Lub, jeśli zdecyduję się na natywny SQL dla tego, czy mogę zrobić natywny SQL w ramach transakcji hibernacji? Czy to oznacza, że ​​obsługuje zatwierdzanie/wycofywanie zmian?

+0

co masz na myśli przez „hibernacji robi SELECT przed każdym wkładki (lub aktualizacji) przy użyciu saveOrUpdate().” ?czy możesz opublikować kod, którego używasz do zapisywania danych? przy okazji zapisy 120k to ogromne dane! – Rakesh

+0

Właśnie znalazłem artykuł o [przetwarzaniu wsadowym w hibernacji] (http://onetouchcode.com/2016/08/21/batch-processing-example-in-hibernate/) – Shailendra

Odpowiedz

22

Istnieje wiele możliwych wąskich gardeł w operacjach masowych. Najlepsze podejście zależy w dużym stopniu od tego, jak wyglądają Twoje dane. Zajrzyj do sekcji Hibernate Manual przetwarzania wsadowego.

Jako minimum, upewnij się, że są za pomocą następującego wzoru (skopiowany z instrukcji):

Session session = sessionFactory.openSession(); 
Transaction tx = session.beginTransaction(); 

for (int i=0; i<100000; i++) { 
Customer customer = new Customer(.....); 
session.save(customer); 
    if (i % 20 == 0) { //20, same as the JDBC batch size 
     //flush a batch of inserts and release memory: 
     session.flush(); 
     session.clear(); 
    } 
} 

tx.commit(); 
session.close(); 

Jeśli mapowanie pliku płaskiego do bardzo skomplikowanego wykresu obiektu może trzeba uzyskać bardziej oszczędny , ale podstawową zasadą jest to, że musisz znaleźć równowagę pomiędzy przesuwaniem sporej wielkości fragmentów danych do bazy danych z każdym opróżnianiem/zatwierdzaniem i unikaniem eksplozji rozmiaru pamięci podręcznej poziomu sesji.

Na koniec, jeśli nie potrzebujesz Hibernate, aby obsłużyć jakiekolwiek kolekcje lub kaskadowanie w celu poprawnego wstawienia danych, rozważ użycie StatelessSession.

+0

Spłukiwam rozliczenia w mojej sesji, nie mam problemy z pamięcią z kodem. Mam problemy z dodatkowym wyborem! : P Przeczytałem instrukcję, nic nie mogę znaleźć. Dane są bardzo proste, nie wymaga kaskadowania. Po prostu muszę pozbyć się, dla tego zadania, zbędnego selekcji, która nazywa się 120K razy: P – JustDanyul

+0

@JustDanyul jaki jest przybliżony procent nowych jednostek w tej operacji (tj. Jaki procent zaznaczeń jest w rzeczywistości niepotrzebny)? Czy używasz wersjonowania? – jcwayne

+0

rzeczywisty procent będzie różnił się z dnia na dzień. Jednak żaden z wybranych nie powinien być konieczny. Większość dzisiejszych baz danych (nawet "zabawkowych", takich jak SQLite) zapewnia funkcjonalność, która pozwoli automatycznie aktualizować rekord, jeśli dane już istnieją. (bez konieczności odpytywania najpierw, aby dowiedzieć się, czy istnieje).) – JustDanyul

0

"Dodatkowy" wybór polega na wygenerowaniu niepowtarzalnego identyfikatora dla danych.

Przejście do generowania sekwencji HiLo i można zmniejszyć liczbę odwiedzin sekwencji do bazy danych o numer rozmiaru alokacji. Należy pamiętać, że nastąpi przerwa w kluczy podstawowych, chyba że dostosowanie wartości sekwencji dla generatora HiLo

1

Jeśli używasz sekwencję lub natywną generator Hibernate użyje wybierz, aby uzyskać ID:

<id name="id" column="ID"> 
    <generator class="native" /> 
</id> 

Ty należy używać Hilo lub generator seqHiLo:

<id name="id" type="long" column="id"> 
    <generator class="seqhilo"> 
     <param name="sequence">SEQ_NAME</param> 
     <param name="max_lo">100</param> 
    </generator> 
</id> 
3

Od Hibernate Batch Processing przypadku aktualizacji użyłem następujące:

Session session = sessionFactory.openSession(); 
Transaction tx = session.beginTransaction(); 

ScrollableResults employeeCursor = session.createQuery("FROM EMPLOYEE") 
            .scroll(); 
int count = 0; 

while (employeeCursor.next()) { 
    Employee employee = (Employee) employeeCursor.get(0); 
    employee.updateEmployee(); 
    seession.update(employee); 
    if (++count % 50 == 0) { 
     session.flush(); 
     session.clear(); 
    } 
} 
tx.commit(); 
session.close(); 

Ale dla wkładki i pójdzie na jcwayne odpowiedzi

Powiązane problemy