2008-11-12 4 views
3

G!Oracle DB에서 수백만 행 중에서 선택하는 가장 좋은 방법

저는 1 천 5 백만 행을 가진 테이블에서 쿼리하고자하는 단어가 백만 가지입니다. 단어와 함께 동의어의 결과가 각 쿼리 후에 처리됩니다.

테이블은 다음과 같습니다

synonym  word 
    --------------------- 
    ancient  old 
    anile  old 
    centenarian old 
    darkened  old 
    distant  far 
    remote  far 
    calm   gentle 
    quite  gentle 

이것은 현재 자바에서 수행하는 방법이다 :

.... 
PreparedStatement stmt; 
ResultSet wordList; 
ResultSet syns; 
... 

stmt = conn.prepareStatement("select distinct word from table"); 
wordList = stmt.executeQuery(); 

while (wordList.next()) { 
    stmt = conn.prepareStatement("select synonym from table where word=?"); 
    stmt.setString(1, wordList.getString(1)); 
    syns = stmt.executeQuery(); 

    process(syns, wordList.getString(1)); 
} 
... 

이 느린 믿을 수 없다. 이런 일을하는 가장 빠른 방법은 무엇입니까?

건배, 크리스

+0

단어 열에 색인이 있다고 가정합니까? – JeeBee

+0

예, 단어 열에 색인이 있습니다. – chris

답변

4

두 아이디어 :

가) 어떻게 그것을 하나 개의 쿼리 만들기에 대한 : process 방법은로 취급 할 필요가 당신 경우

select synonym from table where word in (select distinct word from table) 

B) 또는를, 한 단어의 동의어 집합을 왜 word으로 정렬하고 word 때마다 process이 새로 시작합니까? 그 쿼리는 다음과 같습니다

select word, synonym 
from table 
order by word 
+0

나는 나의 querstion을 세련했다. 각 단어 뒤에 처리가 이루어져야합니다. – chris

+0

그러면 모든 동의어가 원본 테이블에 표시된 순서대로 반환됩니다. 또한 단어 자체를 반환하지 않습니다. "in (테이블에서 다른 단어 선택)"은 속도가 느려지는 역할 만합니다. – configurator

+0

여기에 두 가지 옵션이 있습니다. 옵션 b에 대한 쿼리를 추가했습니다 – sblundy

5
  1. '단어'컬럼에 인덱스가 있는지 확인하십시오.

  2. 두 번째 prepareStatement를 word 루프 외부로 이동하십시오. 새 문을 만들 때마다 데이터베이스에서 쿼리를 컴파일하고 최적화합니다. 그러나이 경우 쿼리는 동일하므로이 작업이 필요하지 않습니다.

  3. 위의 내용은 sblundy과 같습니다.

3

어쨌든 모두 쿼리하는 경우 루프 내의 동의어를 쿼리하는 이유는 무엇입니까? 단일 select word, synonym from table order by word을 사용하고 Java 코드의 단어로 분할해야합니다.

1
PreparedStatement stmt; 
ResultSet syns; 
... 

stmt = conn.prepareStatement("select distinct " + 
          " sy.synonm " + 
          "from " + 
          " table sy " + 
          " table wd " + 
          "where sy.word = wd.word"); 
syns = stmt.executeQuery(); 
process(syns); 
0

문제가 해결되었습니다. 중요한 점은 테이블을 단어별로 정렬 할 수 있다는 것입니다. 따라서 전체 테이블을 쉽게 반복 할 수 있습니다. 이처럼 :

.... 
Statement stmt; 
ResultSet rs; 
String currentWord; 
HashSet<String> syns = new HashSet<String>(); 
... 

stmt = conn.createStatement(); 
rs = stmt.executeQuery(select word, synonym from table order by word); 

rs.next(); 
currentWord = rs.getString(1); 
syns.add(rs.getString(2)); 

while (rs.next()) { 
    if (rs.getString(1) != currentWord) { 
     process(syns, currentWord); 
     syns.clear(); 
     currentWord = rs.getString(1); 
    } 
    syns.add(rs.getString(2)); 
} 
... 
1

관련 그러나 비 관련 :

while (wordList.next()) { 
    stmt = conn.prepareStatement("select synonym from table where word=?"); 
    stmt.setString(1, wordList.getString(1)); 
    syns = stmt.executeQuery(); 

    process(syns, wordList.getString(1)); 
} 

당신은 루프 밖에서 그의 prepareStatement 전화를 이동해야합니다 :

성명을 준비하는 요점에 dB입니다
stmt = conn.prepareStatement("select synonym from table where word=?"); 
while (wordList.next()) { 
    stmt.setString(1, wordList.getString(1)); 
    syns = stmt.executeQuery(); 

    process(syns, wordList.getString(1)); 
} 

compile/cache/etc 명령문을 반복적으로 사용하기 때문에. 많은 쿼리를 수행하려는 경우 명시 적으로 결과 세트를 정리하여 커서가 부족하지 않도록해야 할 수도 있습니다.

1

응용 프로그램과 데이터베이스 간의 컨텍스트 전환을 줄이려면 명령문 개체의 setFetchSize 메서드를 활용하는 것도 고려해야합니다. 백만 레코드를 처리하려는 경우 setFetchSize (someRelativelyHighNumberLike1000)를 사용해야합니다. 이것은 자바에게 한번에 하나씩 잡는 대신 오라클에서 더 많은 레코드가 필요할 때마다 최대 1000 개의 레코드를 가져 오도록 지시합니다. 이는 일종의 일괄 처리 작업을위한 최악의 시나리오입니다. 이렇게하면 프로그램 속도가 향상됩니다. 또한, 리팩토링과 단어/동의어의 일괄 처리를하고 고려

  1. 로 1
  2. 과정 1
  3. 반복

이보다 느린

  1. 50을 페치 페치/100/1000
  2. 프로세스 50/100/1000
  3. ,451,515,반복

  • 은 보유하고있는 50/100/1000 [또는 그러나 많은 당신이 한 번에 검색] 당신이 그들을 처리 할 때까지 몇 가지 배열 구조입니다.

  • 관련 문제