szybszy insert do bazy

szybszy insert do bazy
MA
  • Rejestracja:około 7 lat
  • Ostatnio:około 2 miesiące
  • Postów:100
0

piszę sobie aplikacje w hibernate i mam problem z wydajnością przy insertowaniu do bazy danych.

Kopiuj
for(int a = 0 ; a<persons.size(); a++) {

               Person person = new Person();

                Gender gender = new Gender();

                gender.setName(persons.get(a).getGender());

                gender = genderRepository.save(gender);

                Country country = new Country();

                country.setName(persons.get(a).getCountry());

                country = countryRepository.save(country);

                person.setName(personss.get(a).getFirstName());
                person.setLastName(persons.get(a).getLastName());
                person.setAdditionalInfo(persons.get(a).getIdentifier());
                person.setGender(gender);

                Set<Country> countries = new HashSet();
                countries.add(country);
                person.setCountries(countries);

                personRepository.save(person);

jak poprawić wydajność insertów?

YA
Pokaż konfigurację hibernate'a.
Schadoow
  • Rejestracja:ponad 13 lat
  • Ostatnio:3 minuty
  • Postów:1068
1

Poszukaj pod nazwą bulk insert.

jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:7 minut
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
3

*Prawdopodobnie *(bo nie wiem tego na pewno).
Tworzenie nowej pełci (Gender) i kraju (Country) dla każdej osoby i wykonywanie na tym save raczej nie pomaga.

Chyba, że wprowadzasz nowatorską ideę: każdy ma własną unikatową płeć i jeden osobisty kraj


jeden i pół terabajta powinno wystarczyć każdemu
Koziołek
z tą pełcią dla każdego to bym uważał.
jarekr000000
@Koziołek: odpada ból z małżeństwami jednopłciowymi. Po prostu nie będzie takich.
Koziołek
I widzisz, problem się rozwiązał.
AK
Opluliście mi monitor. To tutaj się zgłasza, czy w "Hardware" ?
Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:14 dni
  • Lokalizacja:Stacktrace
  • Postów:6821
1

Po pierwsze włącz logowanie SQLi w konfiguracji Hibernate. To pomaga na wiele problemów wydajnościowych, bo nagle widać jak zły SQL został wygenerowany. W dodatku zło nie wynika z kiepskiej jakości Hibernate, ale z kiepskiej jakości kodu.

Po drugie, to jak pisał @jarekr000000 płcie zazwyczaj kończą się w okolicach 3, krajów mamy około 200. Ty jednak za każdym razem tworzysz nowe. Choć nie sądzę, by było to jakiś poważny problem. Jeden prosty insert czy trzy nie robi większej różnicy bazie danych (serio).

Po trzecie wspomniany bulk load, który będzie zbierał dane i wstawiał je na raz w postaci jednego jebitnego insertu.

Ale ja bym jednak zaczął od tych logów.


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
jarekr000000
Strzelam, że z tymi płciami tam nie idzie insert - tylko merge, a w konsekwensji refresh/select za każdym razem (zależy od primary key). Ale nie wiem, jednak nie moja działka.
AK
Płci według Wyroczni Tych Czasów już jest cztery.
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:4 dni
  • Postów:3277
0

To co pisze @jarekr000000 to prawda, do tego proponowałbym ręcznie sterować otwarciem i zatwierdzeniem transakcji grupując inserty po powiedzmy 100 rekordów. Jeżeli danych jest naprawdę dużo, to pozostaje specyficzny dla konkretnej bazy bulk insert.

MA
  • Rejestracja:około 7 lat
  • Ostatnio:około 2 miesiące
  • Postów:100
0

dziękuję za wskazówki, unikalność rekordów w tabeli płeć oraz krajów powinienem zapewnić sobie na poziomie bazy danych czy przy insercie sprawdzić czy dana płeć/kraj już występuje?

piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:4 dni
  • Postów:3277
0

Na obu poziomach. Z jednej strony baza powinna odrzucać błędne dane (np. zduplikowane wartości) z drugiej strony aplikacja tez nie powinna próbować wstawiać błędnych danych.

TT
  • Rejestracja:ponad 7 lat
  • Ostatnio:ponad 6 lat
  • Postów:69
0

Abstrahując od samego przyspieszania zapytań - po co w ogóle zapisujesz to na 3 razy?
Gender to pewnie enum, Country to też (chyba?) coś stałego co się dodaje do bazy raz i już zostaje.
Zakładam, że Country=Poland u Kowalskiego, to to samo co Country=Poland u innego Janusza.

Nie wystarczy zrobić

Kopiuj
@Entity
class Person {
    private Long id;
    private Gender gender;
    private List<Country> country;
    ...
}


for (Person p: persons) {
    personRepository.save(person);
}

, a hibernate ogarnie?

MA
tak masz racje, ale wymagania mam takie żeby były 3 tabele (þłeć,osoba,kraj)
TT
Kraj rozumiem jeśli to coś więcej niż enum, płci nie rozumiem w ogóle. Przedyskutował bym te wymagania ;-)
AK
z iloma unikalnymi / powtarzalnymi krajami powiązany jest człowiek? Sugerowałbym Set, jesli już
MA
  • Rejestracja:około 7 lat
  • Ostatnio:około 2 miesiące
  • Postów:100
0

poprawiłem sobie tak ten kod i wyglada to juz lepiej, jak teraz zapewnic unikalnosc rekordów?

Kopiuj
@Transactional
    public void  datapersistance(int limit) {
        List<migratedPerson> migratedPersons = repository.findPersons;
        for (migratedPerson personFromList : migratedPersons) {
            Person person = new Person();

            Gender gender = new Gender();
            gender.setName(personFromList.getGender());
            em.persist(gender);

            Country country = new Country();
            country.setName(personFromList.getCountry());
            em.persist(country);

            person.setName(personFromList.getFirstName());
            person.setLastName(personFromList.getLastName());
            person.setAdditionalInfo(personFromList.getIdentifier());
            person.setGender(gender);

            Set<Country> countries = new HashSet();
            countries.add(country);
            person.setCountries(countries);

            em.persist(person);
        }
edytowany 1x, ostatnio: masjav
AK
nie widzę aby ten kod był istotnie lepszy od pierwszej wersji, nic nie skorzystałeś z uwag kolegów. Dalej powołujesz nową płeć itd...
MA
rozwiązanie polega na dodawaniu ifologi, czy jest jakiś mądrzejszy sposób?
AK
tknąłęś się tego projektu, czy Koledzy mają Ci zrobić? Rozumiem masz to zrobić i wykazać się samodzielną pracą? Możliwości są dwie: a) albo encja Gender jest źle zaprojektowana (unikalność) i wyjątku nie ma, ale baza pokazuje czytelnie jakie to chore b) albo jest zaprojektowana dobrze, i nieprawdą jest, że program działa wolno, bo nie działa wcale, rzuca wyjątek.
jarekczek
  • Rejestracja:prawie 8 lat
  • Ostatnio:ponad 4 lata
  • Lokalizacja:Siemianowice Śląskie
  • Postów:500
1

jak poprawić wydajność insertów?

Skonfigurować batch update/insert wg Vlada. Cała paczka musi być w jednej transakcji.


Przeważnie ignoruję niezarejestrowanych użytkowników.
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:4 dni
  • Postów:3277
1

Tak z ciekawości - co oznacza "problem z wydajnością" konkretnie? Ile tych rekordów wstawiasz do bazy i w jakim czasie?

jarekr000000
To bardzo dobre pytanie.
MA
generalnie chciałbym móc w sensowym czasie wkładać ok 20-50k, chwilowo 100 zajmuję ok 15s, wiec bardzo kiepsko
piotrpo
Jak chcesz wrzucić 50k rekordów w rozsądnym czasie (np. 10 s), to żadne hajbernejty panie, tylko ordynarne połączenie JDBC i żadne transakcje, bulki i inne tylko trzeba takich rzeczy https://www.postgresql.org/docs/9.2/static/sql-copy.html
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:7 minut
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
0

wkładać ok 20-50k, chwilowo 100 zajmuję ok 15s, wiec bardzo kiepsko -

No bez przesady jak jest 100 rekordów na 15 sekund włożone, to na pewno nie jest to wynik problemów wydajnościowych hibernate tylko - albo jego niewłaściwego użycia, albo coś jest BARDZO źle skonfigurowane (baza?, hibernate?). Być może nawet problem jest gdzie indziej w kodzie.

  1. trzeba sprawdzić ile sama baza przetworzy - zrobić tych 100 insertów na boku.
  2. trzeba zobaczyć show_sql.
  3. trzeba zrobić profiling aplikacji, żeby zobaczyć co ona robi

jeden i pół terabajta powinno wystarczyć każdemu
edytowany 5x, ostatnio: jarekr000000
Klaudiusz Wojtkowiak
  • Rejestracja:ponad 6 lat
  • Ostatnio:prawie 4 lata
  • Postów:10
0

W przypadku zapisu do bazy danych, najbardziej obciążająca jest transakcja.

Rozpatrz, czy możesz zapisać w jednym insercie kilkadziesiąt - kilkaset insertów.
Możesz to zrobić pod warunkiem, że możesz trochę opóźnić zapis tych danych w bazce.

Np bez problemu możesz to zrobić w przypadku zapisu logów.

Taki bufor, który zapisujesz w jednej transakcji, powinien mieć obsłużone zamknięcie aplikacji (w predestroyu zapisz zawartość do bazy).
Powinien być obsłużony też procesem cyklicznym (np zapisz bufor co minutę).
Z procesami cyklicznymi uważaj aby niepotrzebnie nie potworzyć wątków - lepiej używać do tego odpowiedniej biblioteki.

Zarówno masowy zapis jak i cykliczne wyzwalanie masz dostępne w bibliotece Daobab, która jest rozrzeszeniem JPA: www.daobab.io


Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.