거대한 테이블에서 모든 레코드를 검색 할 때 OOM (메모리 외) 오류를 피하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/1107732

문제

거대한 테이블을 사용자 정의 XML 파일로 변환하는 작업이 주어집니다. 나는이 직업에 Java를 사용할 것입니다.

단순히 "Select * From Customer"를 발행하면 결국 OOM을 유발하는 막대한 양의 데이터를 반환 할 수 있습니다. 레코드를 사용할 수있게되면 즉시 레코드를 처리 할 수있는 방법이 있습니까? SQL 검색 프로세스 중에 그 후 메모리에서 레코드를 제거 할 수 있습니까?

--- 2009 년 7 월 13 일에 편집

내 질문을 자세히 설명하겠습니다. 1 DB 서버와 1 개의 응용 프로그램 서버가 있습니다. 응용 프로그램에서 선택 쿼리를 발행하면 데이터가 DB 서버에서 App Server로 이동합니다.

나는 (내가 틀렸다면 나를 수정한다) resultset은 쿼리에서 모든 레코드를받을 때까지 기다려야한다고 믿는다. 1000 리코드 테이블의 경우 Fetch Size를 4로 설정하더라도 App Server의 힙 메모리에 1000 개의 레코드가 있습니다. 맞습니까? 페치 크기는/DB 서버에서 왕복 수에만 영향을 미칩니다.

내 질문은, App Server에 도착한 직후 4 개 (또는 숫자) 레코드에서 처리를 시작하고 App Server에서 메모리를 확보하도록 처분하는 방법입니다.

도움이 되었습니까?

해결책

나는 당신이 같은 솔루션을 사용할 수 있다고 생각합니다 이 하나. 스크롤 가능한 결과 세트.

다른 팁

조금 더 많은 정보로 더 도움이되는 답변을 얻을 수 있습니다.

MySQL을 사용하는 경우 :

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
       java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);

~에서 http://www.oracle.com/technology/tech/java/sqlj_jdbc/htdocs/jdbc_faq.html:

java.util.Properties info = new java.util.Properties();
info.put ("user", "scott");
info.put ("password","tiger");
info.put ("defaultRowPrefetch","15");
getConnection ("jdbc:oracle:oci:@",info);

JDBC를 사용하는 경우 한 번에 하나의 레코드를 반복하는 커서와 함께 결과 세트를 사용할 수 있습니다. XML을 구축하기 위해 DOM을 사용하지 않고 XML을 한 번에 하나의 레코드에 XML로 작성해야합니다.

내 경험을 통해 배운 경험의 한 가지 규칙은 데이터베이스에서 응용 프로그램 서버로 모든 데이터를 가져 오지 않는다는 것입니다. 당신이 할 수있는 한 가지는 데이터를 페이지에 페이지를 구현하는 것입니다.

약 1000-5000 레코드가 포함 된 데이터의 한 페이지를 가져와 처리 한 다음 다음 페이지의 데이터를 다시 가져올 수 있습니다.

전체 테이블을 내보내는 개념. (전문가에게 주석 : 나는 그 결점을 알고 있습니다.)

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
public class FullTableExport {
    public static String toXML(String s) {
        if (s != null) {
            StringBuilder b = new StringBuilder(s.length());
            for (int i = 0, count = s.length(); i < count; i++) {
                char c = s.charAt(i);
                switch (c) {
                case '<':
                    b.append("&lt;");
                    break;
                case '>':
                    b.append("&gt;");
                    break;
                case '\'':
                    b.append("&#39;");
                    break;
                case '"':
                    b.append("&quot;");
                    break;
                case '&':
                    b.append("&amp;");
                    break;
                default:
                    b.append(c);
                }
            }
            return b.toString();
        }
        return "";
    }
    public static void main(String[] args) throws Exception {
        String table = "CUSTOMER";
        int batch = 100;

        Class.forName("oracle.jdbc.driver.OracleDriver");
        Connection conn = DriverManager.getConnection(
            "jdbc:oracle:thin:@server:orcl", "user", "pass");
        PreparedStatement pstmt = conn.prepareStatement(
            "SELECT /*+FIRST_ROWS(" + batch + ") */ * FROM " + table);
        ResultSet rs = pstmt.executeQuery();
        rs.setFetchSize(batch);
        ResultSetMetaData rsm = rs.getMetaData();
        File output = new File("result.xml");
        PrintWriter out = new PrintWriter(new BufferedWriter(
            new OutputStreamWriter(
            new FileOutputStream(output), "UTF-8")), false);
        out.printf("<?xml version='1.0' encoding='UTF-8'?>%n");
        out.printf("<table name='%s'>%n", toXML(table));
        int j = 1;
        while (rs.next()) {
            out.printf("\t<row id='%d'>%n", j++);
            for (int i = 1; i <= rsm.getColumnCount(); i++) {
                out.printf("\t\t<col name='%s'>%s</col>%n", 
                    toXML(rsm.getColumnName(i)), 
                    toXML(rs.getString(i)));
            }
            out.printf("\t</row>%n");
        }
        out.printf("</table>%n", table);
        out.flush();
    }
}

편집하다 단점 (감사합니다 @JS) :

  • OJDBC 이외의 외부 라이브러리는 없습니다
  • 아무것도 닫히지 않습니다
  • 일반적인 예외가 발생합니다
  • 주요 방법입니다
  • XML 생성을위한 인쇄 사용
  • 오라클 특정 SQL
  • 일반 텍스트 비밀번호
  • 일부 열은 문자열 표현에서 어색해 보입니다
  • UTF-8은 너무 국제적입니다
  • XML 구조 발자국이 큽니다

OOM 오류가 발생하는 단계에서 데이터 검색 또는 XML 파일로 데이터를 처리하는 단계는 무엇입니까?

데이터 검색이라면 데이터를 배치로 가져옵니다. 총 행 수를 먼저 받고 기본 키에 따라 선택을 주문하고 선택한 행을 씹을 수있는 크기로 제한하십시오.

XML 파일을 작성하는 경우 각 고객의 XML 노드를 System.out.println으로 보내면 메모리를 유지하지 마십시오. Commad Line을 통해 프로그램을 시작하고 모든 출력을 파일로 리디렉션합니다.

java MyConverter > results.txt

레코드를 통과하면 모든 것이 파일에 저장됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top