2015-01-27 7 views
4

Использование Oracle java JDBC (ojdbc14 10.2.x), загрузка запроса со многими строками занимает вечно (среда с высокой задержкой. По-видимому, это предварительная выборка по умолчанию в Oracle JDBC - размер по умолчанию «10», который требует круглого времени поездки один раз за 10 строк. Я пытаюсь установить агрессивный размер предварительной выборки, чтобы избежать этого.Предварительная выборка Oracle JDBC: как избежать исчерпания ОЗУ

PreparedStatement stmt = conn.prepareStatement("select * from tablename"); 
statement.setFetchSize(10000); 
ResultSet rs = statement.executeQuery(); 

Это может работать, но вместо этого я получить из исключения памяти. у меня был предположил, что setFetchSize скажет ему буферизировать «многие строки» по мере их поступления, используя столько же ОЗУ, сколько требует каждая строка. Если я запускаю 50 потоков, даже с 16G -XMX-пространством, у него заканчивается память. как утечка:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 
    at java.lang.reflect.Array.newArray(Native Method) 
    at java.lang.reflect.Array.newInstance(Array.java:70) 
    at oracle.jdbc.driver.BufferCache.get(BufferCache.java:226) 
    at oracle.jdbc.driver.PhysicalConnection.getCharBuffer(PhysicalConnection.java:7422) 
    at oracle.jdbc.driver.OracleStatement.prepareAccessors(OracleStatement.java:983) 
    at oracle.jdbc.driver.T4CTTIdcb.receiveCommon(T4CTTIdcb.java:273) 
    at oracle.jdbc.driver.T4CTTIdcb.receive(T4CTTIdcb.java:144) 
    at oracle.jdbc.driver.T4C8Oall.readDCB(T4C8Oall.java:771) 
    at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:346) 
    at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:186) 
    at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:521) 
    at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:205) 
    at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:861) 
    at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1145) 
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1267) 
    at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3449) 
    at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3493) 
    at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1491) 
    .... 

Что я могу сделать, чтобы по-прежнему получать предварительную выборку, но не выходить из ОЗУ? Что происходит?

Ближайший соответствующий пункт на SO это: https://stackoverflow.com/a/14317881/32453

ответ

5

В принципе, стратегия по умолчанию оракула для более поздних ojdbc банок является «предварительно выделить» массив в «упреждающей» строке, которая приспосабливает для самого большого размера, предположительно, можно вернуть из этого запроса. Так что в моем случае у меня был VARCHAR2 (4000), поэтому 50 нитей * 3 столбца файла varchar2 * 4000 добавляли до более чем гигабайт оперативной памяти [yikes]. Кажется, нет возможности сказать «не предварительно выделять этот массив, просто используйте необходимый размер». Ojdbc даже сохраняет эти предварительно распределенные буферы вокруг между подготовленными состояниями, чтобы он мог их повторно использовать. Определенно, болото памяти.

Исправление должно определять максимальный фактический размер столбца, а затем заменить запрос (при условии, что 50 - это максимальный размер) select substr(column_name, 0, 50), а также профиль и использовать только с высоким значением setFetchSize, поскольку на самом деле были сделаны значительные улучшения скорости.

Другие действия, которые вы можете выполнить: уменьшить количество строк предварительной выборки, увеличить параметр Xmx, выбрать только нужные столбцы.

Как только мы смогли использовать, по крайней мере, предварительную выборку 400 [убедитесь, что у вас есть профиль, чтобы узнать, какие цифры подходят для вас, с высокой задержкой мы увидели улучшения до размера выборки 3-4K] по всем запросам, производительность значительно улучшилась.

Я полагаю, что если вы хотите быть действительно агрессивным против редких «очень длинных» строк, вы можете повторно запросить, когда вы столкнетесь с этими [редкими] строками.

Подробнее ad nauseum here

 Смежные вопросы

  • Нет связанных вопросов^_^