Mam coś takiego:

    List<Data> dataList = stepts.stream()
        .flatMap(step -> step.getPartialDataList().stream())
        .collect(Collectors.toList());

Więc łączę w dataList wiele list z każdego kroku.

Mój problem polega na tym, że dataList może napotkać OutOfMemoryError . Jakieś sugestie, jak mogę wsadować dataList i zapisać partie w bazie danych?

Moim prymitywnym pomysłem jest:

    for (Step step : steps) {
        List<Data> partialDataList = step.getPartialDataList();

        if (dataList.size() + partialDataList.size() <= MAXIMUM_SIZE) {
            dataList.addAll(partialDataList);
        } else {
            saveIntoDb(dataList);
            dataList = new ArrayList<>();
        }
    }

PS: Wiem, że jest ten post, ale różnica polega na tym, że mogę nie być w stanie przechowywać w pamięci całych danych.

LE: getPartialDataList bardziej przypomina createPartialDataList ()

5
UnguruBulan 19 listopad 2019, 19:36
Czy wykonujesz inne operacje na danych przed zapisaniem partii w bazie danych?
 – 
vphilipnyc
19 listopad 2019, 19:52
może? czy próbowałeś?
 – 
Eugene
19 listopad 2019, 19:57
Co może być istotne dla dalszego pytania, o jakim rozmiarze danych mówimy tutaj dla List<Data>? Jak jest zaimplementowany getPartialDataList? Czy trzyma kursor nad odczytami z danych?
 – 
Naman
19 listopad 2019, 20:00
Nie, po prostu to oszczędzam
 – 
UnguruBulan
20 listopad 2019, 00:38
@Eugene, może, tak. Próbuję rozgryźć wszystkie narożniki z prod env.
 – 
UnguruBulan
20 listopad 2019, 00:38

1 odpowiedź

Jeśli Twoim problemem jest OutOfMemoryError, prawdopodobnie nie powinieneś tworzyć dodatkowych pośrednich struktur danych, takich jak listy lub strumienie, przed zapisaniem w bazie danych.

Ponieważ Step.getPartialDataList() już zwraca List<Data>, dane są już w pamięci, chyba że masz własną implementację List. Wystarczy użyć wstawiania wsadowego JDBC:

PreparedStatement ps = c.prepareStatement("INSERT INTO data VALUES (?, ?, ...)");
for (Step step : steps) {
    for (Data data : step.getPartialDataList()) {
        ps.setString(1, ...);
        ps.setString(2, ...);
        ...
        ps.addBatch();
    }   
}
ps.executeBatch();

Nie ma potrzeby wcześniejszego dzielenia na mniejsze partie dzięki dataList. Najpierw sprawdź, co obsługuje Twoja baza danych i sterownik JDBC, zanim dokonasz przedwczesnych optymalizacji.

Należy pamiętać, że w przypadku większości baz danych właściwym sposobem wstawiania dużej ilości danych jest zewnętrzne narzędzie, a nie JDBC, np. JDBC. PostgreSQL ma COPY.

5
Karol Dowbecki 19 listopad 2019, 20:12
Najlepszym przypadkiem byłoby zrobienie zbiorczego wstawiania ze wszystkimi danymi. Ale w środowisku produkcyjnym może istnieć niewielka szansa na uzyskanie OutOfMemory. Na step.getPartialDataList() stworzę dane w locie, może nazewnictwo tutaj nie jest najlepsze. Ale z pewnością całe dane nie są w pamięci
 – 
UnguruBulan
20 listopad 2019, 00:44
Twierdzę, że ta odpowiedź jest nadal właściwa dla twojego przypadku użycia. Nie możesz przetwarzać jednocześnie mniej danych niż wynik jednego getPartialDataList()
 – 
MyStackRunnethOver
20 listopad 2019, 03:07
Chcę przetworzyć więcej danych niż wynik getPartialDataList()
 – 
UnguruBulan
20 listopad 2019, 10:30