2015-01-27 2 views
4

Oracle JDBC (ojdbc14 10.2.x)를 사용하면 많은 행이 포함 된 쿼리를로드하는 데 시간이 오래 걸릴 수 있습니다 (지연 시간이 긴 환경입니다.) Oracle JDBC의 기본 프리 페치는 기본 크기 10 행마다 한 번 왕복 시간을 필요로 "10". 내가Oracle JDBC prefetch : RAM 부족 방지 방법

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

이 작업을 수행 할 수 있습니다.이를 방지하기위한 적극적인 프리 페치 크기를 설정하려고하고, 대신 내가 메모리 부족 예외를 얻을. 내가했다 setFetchSize는 각 행에 필요한만큼의 RAM을 사용하여 "많은 행"을 버퍼링한다고 가정합니다. -XMX 공간이 16G 인 경우에도 50 개의 스레드로 실행하면 메모리가 부족합니다. 누수처럼 :

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) 
    .... 

프리 페치를 가져 오지 만 RAM이 부족하지 않으면 어떻게해야합니까? 무슨 일 이니? https://stackoverflow.com/a/14317881/32453 기본적으로

답변

5

가, 나중에 ojdbc 항아리에 대한 오라클의 기본 전략은 반환 생각할 수있는 가능한 가장 큰 크기 수용합니다 "프리 페치"행 당 배열을 "미리 할당"하는 것입니다

SO에 가장 가까운 관련 항목이 있습니다 해당 쿼리에서. 그래서 제 경우에는 VARCHAR2 (4000)가 있었으므로 50 개의 스레드 * 3 열의 varchar2 * 4000이 기가 바이트 이상의 RAM [yikes] 이상으로 합쳐졌습니다. "배열을 미리 할당하지 말고 필요한 크기 만 사용하십시오"라고하는 옵션이없는 것 같습니다. Ojdbc는 preparedstatements 사이에 미리 할당 된 이러한 버퍼를 에 두어 재사용 할 수도 있습니다. 확실히 메모리 돼지.

수정 사항은 최대 실제 열 크기를 결정한 다음 쿼리를 (최대 크기가 50이라고 가정) select substr(column_name, 0, 50) 및 프로필로 바꾸고 실제로 상당한 속도 향상을 가져온만큼 setFetchSize의 높이로만 사용합니다.

할 수있는 다른 작업 : 프리 페치 행 수를 줄이고 Xmx 매개 변수를 늘리면 필요한 열만 선택하십시오.

프리 페치 400 이상을 사용하면 모든 쿼리에 대해 프리 페치 크기를 3 ~ 4K까지 향상시켜주는 대기 시간이 길어서 어떤 숫자가 적합한지를 프로파일 링해야하므로 성능이 크게 향상되었습니다.

드문 행을 실행할 때 다시 쿼리 할 수있는 희소 한 "정말로 긴"행에 대해 실제로 공격적으로 행동하기를 원한다고 가정합니다.

세부 사항 nauseum here