szybszy insert do bazy

0

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

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?

1

Poszukaj pod nazwą bulk insert.

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

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.

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.

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?

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.

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ć

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


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

, a hibernate ogarnie?

0

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

@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);
        }
1

jak poprawić wydajność insertów?

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

1

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

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
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

1 użytkowników online, w tym zalogowanych: 0, gości: 1