2016-10-11 2 views
1

나는 수백만 개의 레코드가있는 테이블을 가지고 있습니다. 시스템을 더 빠르게 만들기 위해 자바 코드에서 페이지 매김 개념을 구현해야한다. 한 번에 1000 개의 레코드를 가져 와서 처리 한 다음 다른 1000 개의 레코드를 선택하고 처리해야합니다. 나는 이미 몇 가지 시도를했으며 그 중 누구도 일하지 않고있다. 쿼리는 나에게 결과를 제공하지만, 쿼리가 SELECT * from TABLENAME Where ROWNUM BETWEEN 10 and 20을 때, 그것은 빈 결과 집합을 반환 SELECT * from TABLENAME Where ROWNUM BETWEEN 0 and 10 때, 위의 예에서Java에서 페이지 매김

1) String query = "select * from TABLENAME" + " WHERE ROWNUM BETWEEN %d AND  %d"; 
sql = String.format(query, firstrow, firstrow + rowcount); 

- 내가 노력 것들 중 일부는 다음과 같습니다. 심지어 DB에서 실행하려고했는데 빈 결과 집합을 반환하려고했습니다. 이유는 확실하지 않습니다.

2) preparedStatement.setFetchSize(100); Java 코드에서이 코드를 가져 왔지만 여전히 테이블의 모든 레코드를 가져옵니다. 이 문장을 추가하는 것은 어쨌든 내 코드에 영향을주지 않습니다.

도와주세요!

+0

왜? 왜 그냥 'ResultSet'을 반복하지 않고 데이터베이스 커서로 작업을하게할까요? –

+0

'setFetchSize'는 드라이버가 다음 _ (fetchSize) _'resultSet.next()'호출을 위해 한 번에 요청할 행의 수만 지정합니다. 그것은 여전히 ​​당신에게 모든 행을 제공합니다. 대신에'setMaxRows'를 찾고있을 것입니다. –

+0

백만 건 이상의 레코드를 가져 오려고하면 "Out of Memory"가됩니다. – user3845894

답변

4

실제로 결과를 페이지 매김하지 않고 결과를 일괄 적으로 처리하는 것처럼 들리는군요. 이 경우 setFetchSize를 사용하여 가져 오기 크기를 1000으로 설정하고 평소와 같이 결과 집합을 반복합니다 (resultset.next() 사용). 반복 할 때 결과를 처리하면됩니다. setFetchSize와 그 기능에 대해 설명하는 많은 리소스가 있습니다. 몇 가지 연구를 수행

을 오라클 매김을 위해이 작업을 수행하는 방법을 설명하는 많은 자원이있다. 웹 검색 만하십시오. 여기에 그것을 수행하는 방법에 대해 설명 자원의 커플 : 일관된 순서 (ORDER BY 절)를 정의하지 않는 경우

매김은 매우 유용하지 않습니다 이후 당신은 할 수 없습니다 반환되는 순서에 의존합니다. https://stackoverflow.com/a/10318244/908961

대답에서 당신이 당신의 결과를 얻을 선택의 서브를 할 필요가 12C 이전의 오라클을 사용하는 경우 :
이 답변은 BETWEEN 문이 작동하지 않는 이유를 설명합니다. 같은 뭔가 :

SELECT c.* 
FROM (SELECT c.*, ROWNUM as rnum 
     FROM (SELECT * FROM TABLENAME ORDER BY id) c) c 
WHERE c.rnum BETWEEN %d AND %d 

오라클 12C 이상을 사용하는 경우 더 큰 내가 새로운 OFFSETFETCH 구문을 사용하는 대신 rownum 만지작 추천 할 것입니다.첫 번째 위의 링크 또는 http://www.toadworld.com/platforms/oracle/b/weblog/archive/2016/01/23/oracle-12c-enhanced-syntax-for-row-limiting-a-k-a-top-n-queries

그래서 쿼리가 될 것을 당신이 여기 http://docs.oracle.com/javadb/10.10.1.2/ref/rrefjdbclimit.html을 설명 된대로 제한 키워드를 사용할 수 있습니다

String query = "select * from TABLENAME OFFSET %d ROWS FETCH NEXT 1000 ONLY"; 
String.format(query, firstrow); 

또는 사용하여 준비된 문

다른 방법
PreparedStatement statement = con.prepareStatement("select * from TABLENAME OFFSET ? ROWS FETCH NEXT 1000 ONLY"); 
statement.setInt(1, firstrow); 
ResultSet rs = statement.executeQuery(); 

처럼 및 참조 귀하의 검색어는 다음과 같습니다.

String query = "select * from TABLENAME { LIMIT 1000 OFFSET %d }"; 
String.format(query, firstrow); 
+0

답변이 '유용하지 않은 이유'에 대한 피드백을 제공하지 않으면 다운 투표의 요점은 무엇입니까? – bdrx

4

오라클에서 페이지 매김을 구현하는 일반적인 방법은 분석 윈도우 기능을 사용하는 것입니다. 행 순서를 정의하는 ORDER BY 절과 함께 row_number. 그런 다음 분석 함수가있는 쿼리가 인라인 뷰 (또는 "창")에 래핑되어 필요한 행 번호를 쿼리 할 수 ​​있습니다.

select rs.* from 
    (select t.*, 
    row_number() over (order by column_to_sort_by) as row_num 
    from my_table t 
) rs 
where rs.row_num >= 1 and rs.row_num < 1001 
order by rs.row_num 

는 JDBC 구현은 다음과 같이 수 :

public void queryWithPagination() throws SQLException { 
    String query = "select rs.* from" 
     + " (select t.*," 
     + " row_number() over (order by column_to_sort_by) as row_num" 
     + " from my_table t" 
     + ") rs" 
     + " where rs.row_num >= ? and rs.row_num < ?" 
     + " order by rs.row_num"; 

    final int pageSize = 1000; 
    int rowIndex = 1; 

    try (PreparedStatement ps = myConnection.prepareStatement(query)) { 

     do { 
     ps.setInt(1, rowIndex); 
     ps.setInt(2, rowIndex + pageSize); 
     rowIndex += pageSize; 
     } while (handleResultSet(ps, pageSize)); 
    } 
} 

private boolean handleResultSet(PreparedStatement ps, final int pageSize) 
     throws SQLException { 
    int rows = 0; 
    try (ResultSet rs = ps.executeQuery()) { 
     while (rs.next()) { 
      /* 
      * handle rows here 
      */ 
      rows++; 
     } 
    } 
    return rows == pageSize; 
} 

참고 표는 동안 변경되지 않은 상태로 유지해야한다고 여기 (column_to_sort_by에 의해 순서) my_table에서 처음 1000 개 행을 쿼리 예입니다 서로 다른 쿼리 실행에서 페이지 매김이 올바르게 작동 할 수 있도록 페이지를 읽습니다.

테이블에 메모리가 부족한 행이 많은 경우 일부 페이지를 읽은 후 목록을 제거/직렬화해야 할 수 있습니다.

편집 :

경우, 행의 순서는 다음, 모두 당신에게 중요하지 않습니다 - @bdrx는 그의 대답에 언급로 - 당신은 아마 매김을 필요로하지 않으며, 가장 빠른 해결책 SELECTWHERE 조건없이 테이블을 쿼리하는 것입니다. 제안 된대로 명령문의 패치 크기를 더 큰 값으로 조정하여 처리량을 향상시킬 수 있습니다.