2014-01-16 4 views
1

У меня есть этот код, этот код в основном устанавливает лимиты в PreparedStatement, чтобы избежать загрузки всех данных таблицы.OutOfMemoryError произошел в драйвере Oracle, когда setFetchSize в PreparedStatement

PreparedStatement pstmt = null; 
    ResultSet rs = null; 
    try { 
     pstmt = con.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); 
     if (getDataSheet().isPagingEnabled()) { 
      pstmt.setFetchSize(getDataSheet().getPageSize() + 1); 
     } 

     if (getDataSheet().isDisableTotalRowsCount() && maxRecords >= 0) { 
      if (getDataSheet().isPagingEnabled()) { 
       pstmt.setMaxRows(getCurrentPageSize()); 
      } else { 
       pstmt.setMaxRows(maxRecords); 
      } 
     } 

     //the rest of code. 

    } catch(Exception ex) { 
     //handle exception 
    } 

Этот код просто работает нормально для всех поставщиков БД, за исключением одного случая, в драйвере Oracle, если я использовал setFetchSize в PreparedStatement, а размер страницы более чем 20000 водитель бросить OutOfMemoryError

Caused by: java.lang.OutOfMemoryError: Java heap space 
at oracle.jdbc.driver.PhysicalConnection.getCharBuffer(PhysicalConnection.java:7018) 
at oracle.jdbc.driver.OracleStatement.prepareAccessors(OracleStatement.java:907) 
at oracle.jdbc.driver.T4CTTIdcb.receiveCommon(T4CTTIdcb.java:261) 
at oracle.jdbc.driver.T4CTTIdcb.receive(T4CTTIdcb.java:127) 
at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:992) 
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:194) 
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:791) 
at oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStatement.java:866) 
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1186) 
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3387) 
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3431) 
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1203) 

любая идея, почему это происходит в Oracle? есть ли какие-либо мысли сделать на уровне БД? спасибо в продвинутом состоянии.

+2

Почему вы хотите получить 20 тыс. Строк за один раз? Использование размера выборки - это выборка рядов строк, выполнение чего-то с ней, затем выборка другой партии - таким образом, ограничение числа обращений к БД. Это ** не ** означает получение всех строк в одной массивной партии в памяти. –

ответ

6

Вопреки тому, что вы, кажется, думаете, setFetchSize не ограничивает количество извлеченных записей, он определяет (или подсказывает), сколько записей должен быть предварительно запрограммирован и кэширован. Исключением является MySQL, который всегда выполняет предварительную выборку всех записей, если вы не установили размер выборки в Integer.MIN_VALUE.

Драйвер просто извлекает столько строк, что память исчерпается.

+0

Да, я вижу, у меня было недоразумение для 'setFetchSize', Ok, тогда это лучшая практика или лучший номер' setFetchSize (Integer.MIN_VALUE) '? – Salah

+0

@JUBA Нет, вы должны использовать разумное число (от 1 до 500); эффект может варьироваться в зависимости от драйвера и базы данных (и я бы посоветовал проверить, действительно ли это повышает производительность). 'Integer.MIN_VALUE' - глупый взлом только для MySQL! –