Подтвердить что ты не робот

Что действительно делает метод Statement.setFetchSize(nSize) в драйвере JDBC SQL Server?

У меня есть эта действительно большая таблица с миллионами записей каждый день, и в конце каждого дня я извлекаю все записи предыдущего дня. Я делаю это так:

String SQL =  "select col1, col2, coln from mytable where timecol = yesterday";
Statement.executeQuery(SQL);

Проблема в том, что эта программа занимает примерно 2 ГБ памяти, потому что она принимает все результаты в памяти, а затем обрабатывает ее.

Я попытался установить Statement.setFetchSize(10), но он принимает точно такую ​​же память из ОС, это не имеет никакого значения. Для этого я использую драйвер JDBC Microsoft SQL Server 2005.

Есть ли способ прочитать результаты в небольших кусках, таких как драйвер базы данных Oracle, когда запрос выполняется, чтобы отображать только несколько строк, и при прокрутке вниз отображаются больше результатов?

4b9b3361

Ответ 1

В JDBC метод setFetchSize(int) очень важен для производительности и управления памятью в JVM, поскольку он контролирует количество сетевых вызовов из JVM в базу данных и соответственно количество ОЗУ, используемое для обработки ResultSet.

В случае если setFetchSize (10) вызывается и драйвер игнорирует его, возможно, есть только два варианта:

  • Попробуйте использовать другой драйвер JDBC, который будет отмечать подсказку размера выборки.
  • Посмотрите на свойства, специфичные для драйвера, на странице Connection (URL и/или карту свойств при создании экземпляра Connection).

RESULT-SET - это количество строк, упорядоченных в БД в ответ на запрос. ROW-SET - это кусок строк, которые извлекаются из RESULT-SET за один вызов из JVM в базу данных. Количество этих вызовов и итоговая RAM, необходимая для обработки, зависит от настройки размера выборки.

Итак, если RESULT-SET имеет 100 строк, а размер выборки - 10, будет создано 10 сетевых вызовов для извлечения всех данных, используя примерно 10 * {размер содержимого по размеру} ОЗУ в любой момент времени.

Размер выборки по умолчанию - 10, что довольно мало. В опубликованном случае кажется, что драйвер игнорирует настройку размера выборки, извлекает все данные за один вызов (потребность в большой ОЗУ, оптимальные минимальные сетевые вызовы).

Что происходит под ResultSet.next(), так это то, что он не выводит по одной строке за раз из RESULT-SET. Он извлекает это из (локального) ROW-SET и выбирает следующий ROW-SET (невидимо) с сервера, поскольку он исчерпывается на локальном клиенте.

Все это зависит от драйвера, поскольку этот параметр является лишь "подсказкой", но на практике я нашел, что это работает для многих драйверов и баз данных (проверено во многих версиях Oracle, DB2 и MySQL).

Ответ 2

Параметр fetchSize - это подсказка к драйверу JDBC как к множеству строк для извлечения в один проход из базы данных. Но водитель может игнорировать это и делать то, что сочтет нужным. Некоторые драйверы, такие как Oracle, извлекают строки в кусках, поэтому вы можете читать очень большие результирующие наборы, не требуя большого количества памяти. Другие драйверы просто читаются во всем результирующем наборе за один раз, и я предполагаю, что ваш драйвер делает.

Вы можете попробовать обновить свой драйвер до версии SQL Server 2008 (что может быть лучше) или с помощью драйвера jTDS с открытым исходным кодом.

Ответ 3

Вам нужно убедиться, что автоматическая фиксация в соединении отключена выключена, или setFetchSize не будет иметь эффекта.

dbConnection.setAutoCommit(false);

Изменить: вспомнил, что, когда я использовал это исправление, он был специфичным для Postgres, но, надеюсь, он все равно будет работать для SQL Server.

Ответ 4

Похоже, что mssql jdbc выполняет буферизацию всего набора результатов для вас. Вы можете добавить параметр строки подключения: selectMode = cursor или responseBuffering = adaptive. Если вы используете версию 2.0+ для драйвера mssql jdbc 2005 года, тогда буферизация ответа должна по умолчанию адаптироваться.

http://msdn.microsoft.com/en-us/library/bb879937.aspx

Ответ 5

Интерфейс выписки Doc

РЕЗЮМЕ: void setFetchSize(int rows)Дает драйвер JDBC подсказку относительно количество строк, которые нужно извлечь из базы данных, когда больше строк необходимо.

Прочтите эту книгу J2EE и далее By Art Taylor

Ответ 6

Мне кажется, что вы действительно хотите ограничить количество строк, возвращаемых в вашем запросе и странице, по результатам. Если это так, вы можете сделать что-то вроде:

select * from (select rownum myrow, a.* from TEST1 a )
where myrow between 5 and 10 ;

Вам просто нужно определить свои границы.

Ответ 7

Попробуйте следующее:

String SQL = "select col1, col2, coln from mytable where timecol = yesterday";

connection.setAutoCommit(false);
PreparedStatement stmt = connection.prepareStatement(SQL, SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY, SQLServerResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(2000);

stmt.set....

stmt.execute();
ResultSet rset = stmt.getResultSet();

while (rset.next()) {
    // ......