Форум программистов, компьютерный форум, киберфорум
Наши страницы
Java: Базы данных
Войти
Регистрация
Восстановить пароль
 
Neo-X2006
0 / 0 / 0
Регистрация: 15.03.2016
Сообщений: 135
1

Получение и обработка данных из большой таблицы (200 млн строк)

09.07.2018, 14:12. Просмотров 194. Ответов 7

У меня есть большая таблица MySQL с порядка 200 млн записей.

Я делаю такой запрос, используя JDBC:

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public List<Pair<Long, String>> getUsersAll() throws SQLException {
        Connection cnn = null;
        CallableStatement cs = null;
        ResultSet rs = null;
        final List<Pair<Long, String>> res = new ArrayList<>();
        try {
            cnn = dataSource.getConnection();
            cs = cnn.prepareCall("select UserPropertyKindId, login from TEST.users;");
            rs = cs.executeQuery();
            while (rs.next()) {
                res.add(new ImmutablePair<>(rs.getLong(1), rs.getString(2)));
            }
            return res;
        } catch (SQLException ex) {
            throw ex;
        } finally {
            DbUtils.closeQuietly(cnn, cs, rs);
        }
    }

Дальше я должен обработать результат:

Java
1
2
3
4
5
6
7
List<Pair<Long, String>> users= dao.getUsersAll();
            if (CollectionUtils.isNotEmpty(users)) {
                for (List<Pair<Long, String>> partition : Lists.partition(users, 2000)) {
                    InconsistsUsers.InconsistsUsersCallable callable = new InconsistsUsers.InconsistsUsersCallable (new ArrayList<>(partition));
                    processExecutor.submit(callable);
                }
            }
Так как таблица очень большая и все данные выгружаются в память, падает с ошибкой:

Java
1
2
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet successfully received from the server was 105,619 milliseconds ago.
Как я могу получать данные частями, что не выгружать сразу все в память. Может быть использовать курсор и складывать данные в какую-нибудь неблокирующую очередь и по мере прихода в нее данных их разгребать? Как это лучше сделать?

Структуру базы я менять не могу, все манипуляции нужно сделать из Java кода.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
09.07.2018, 14:12
Ответы с готовыми решениями:

Получение списка заголовков столбцов определённой таблицы из базе данных Oracle?
Нужно получить имена заголовков столбцов определённой таблицы, а можно ещё и...

Получение данных из textBox с свойством multiline с разных строк в разные поля таблицы
Никак не пойму как сделать что бы в бд добавлялись данные с каждой строки...

Работа с большой базой (>1 млн записей)
Товарищи, помогите! Я недавно перешел на C# 2005, меня особенно интересует...

Редактирование таблицы: разрешено редактировать только 200 строк
Извините за беспокойство. Прошу помощи.С Microsoft SQL Server 2008 никогда не...

Получение данных из текстового файла, чей вес от 200 Мб и больше
Здравствуйте, форумчане! Подскажите пожалуйста правильный метод получения...

7
korvin_
2206 / 1696 / 324
Регистрация: 28.04.2012
Сообщений: 6,004
09.07.2018, 14:25 2
Цитата Сообщение от Neo-X2006 Посмотреть сообщение
Как я могу получать данные частями, что не выгружать сразу все в память.
Очевидно делать partition не в коде по коллекции, а в БД при запросе на получение данных.
0
Neo-X2006
0 / 0 / 0
Регистрация: 15.03.2016
Сообщений: 135
09.07.2018, 14:35  [ТС] 3
Цитата Сообщение от korvin_ Посмотреть сообщение
Очевидно делать partition не в коде по коллекции, а в БД при запросе на получение данных.
Тогда возникнет другая проблема с производительностью, тк на больших лимитах и оффсетах запрос будет выполнятся очень долго.
0
korvin_
2206 / 1696 / 324
Регистрация: 28.04.2012
Сообщений: 6,004
09.07.2018, 16:53 4
Цитата Сообщение от Neo-X2006 Посмотреть сообщение
Тогда возникнет другая проблема с производительностью, тк на больших лимитах и оффсетах запрос будет выполнятся очень долго.
Тогда производи манипуляции по мере чтения ResultSet'а, например

Java
1
2
3
4
5
@FunctionalInterface
public interface UserConsumer {
 
    void accept(long userPropertyKindId, String login) throws SQLException;
}
Java
1
2
3
4
5
6
7
8
public void getUsersAll(UserConsumer consumer) throws SQLException {
 
    ...
        while (rs.next()) {
            consumer.accept(rs.getLong(1), rs.getString(2));
        }
    ...
}
Или делай Stream поверх ResultSet'а (возможно, существуют готовые реализации), только закрывать connection, statement и rs нужно будет в методе close стрима.
0
Neo-X2006
0 / 0 / 0
Регистрация: 15.03.2016
Сообщений: 135
09.07.2018, 17:30  [ТС] 5
Цитата Сообщение от korvin_ Посмотреть сообщение
Тогда производи манипуляции по мере чтения ResultSet'а, например
А разве в данном случае, он вычитает не все сразу данные?

Java
1
2
3
while (rs.next()) {
            consumer.accept(rs.getLong(1), rs.getString(2));
        }
Насколько правильно сделать так:

Java
1
2
stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);
Добавлено через 20 минут
Как вообще на стороне JDBC драйвера указать "Забирай данные пачками, по n элементов, а не грузи все сразу в паямять"?
0
korvin_
2206 / 1696 / 324
Регистрация: 28.04.2012
Сообщений: 6,004
09.07.2018, 20:31 6
Цитата Сообщение от Neo-X2006 Посмотреть сообщение
А разве в данном случае, он вычитает не все сразу данные?
Не обязательно, это зависит от драйвера и параметров Statement'а/ResultSet'а.

https://docs.oracle.com/javase/8/doc...FetchSize-int-
https://docs.oracle.com/javase/8/doc...FetchSize-int-

Цитата Сообщение от Neo-X2006 Посмотреть сообщение
Насколько правильно сделать так:

Java
1
stmt.setFetchSize(Integer.MIN_VALUE);
Вот так ни на сколько не правильно.

Цитата Сообщение от Neo-X2006 Посмотреть сообщение
"Забирай данные пачками, по n элементов, а не грузи все сразу в паямять"?
setFetchSize(n);

он и не грузит всё в память, он по-умолчанию работает с курсором. В зависимости от БД и драйвера, конечно.
Ты сам всё загружаешь сразу в память, в ArrayList.

Но вообще, с чего ты взял, что проблема в памяти?
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
не выглядит как проблема с памятью.
0
Neo-X2006
0 / 0 / 0
Регистрация: 15.03.2016
Сообщений: 135
10.07.2018, 09:29  [ТС] 7
Цитата Сообщение от korvin_ Посмотреть сообщение
setFetchSize(n);
Насколько удалось понять отсюда https://dev.mysql.com/doc/connector-...ion-notes.html, из коробки в MySQL это не работает.

Цитата Сообщение от korvin_ Посмотреть сообщение
Но вообще, с чего ты взял, что проблема в памяти?
Мониторинг показал, что после запуска данной выгрузки, выжралась вся память на сервере.
0
korvin_
2206 / 1696 / 324
Регистрация: 28.04.2012
Сообщений: 6,004
10.07.2018, 10:58 8
Цитата Сообщение от Neo-X2006 Посмотреть сообщение
из коробки в MySQL это не работает.
Работает, только настроить надо, там же написано:

Another alternative is to use cursor-based streaming to retrieve a set number of rows each time. This can be done by setting the connection property useCursorFetch to true, and then calling setFetchSize(int) with int being the desired number of rows to be fetched each time:

Java
1
2
3
4
conn = DriverManager.getConnection("jdbc:mysql://localhost/?useCursorFetch=true", "user", "s3cr3t");
stmt = conn.createStatement();
stmt.setFetchSize(100);
rs = stmt.executeQuery("SELECT * FROM your_table_here");
0
10.07.2018, 10:58
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.07.2018, 10:58

Создание большой таблицы из данных двух столбцов
Добрый день! Есть две достаточно большие колонки данных: примерно в 100 и в...

Обработка строк по условию, получение подстрок из строки! Консультация
Всем доброго времечка! Только начал изучать C#, так что сильно не пинать. ...

Получение и обработка данных с сайта
Приветствую. Планирую написать програмку для смартфона, которая должна просто...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru