2012-03-13 8 views
3

SQL Server 데이터베이스에 많은 수의 큰 행을 삽입해야하는 Java 프로그램이 있습니다. 행의 수는 800k이고, 각 행의 크기는 약 200 바이트입니다.자바 스레드를 사용하여 데이터베이스에 병렬 삽입

현재는 일괄 처리로 50 개로 나누어 진 다음 각 일괄 처리가 하나의 명령문을 사용하여 삽입됩니다. (우리는 JTDS 로깅을 통해 각 배치에 대해 하나의 sp_exec 호출이 사용되었음을 확인했습니다.) 배치 크기를 25와 250 사이로 조정해도 큰 효과가없는 것 같고 50이 최적입니다.

나는 배치를 (말하자면) 5 개의 그룹으로 나누고 스레드를 사용하여 각 그룹을 병렬로 처리하는 방법을 실험했다. 이 속도는 상당히 빠릅니다. 5 스레드로 두 배 이상 빠릅니다.

제 질문은 스레드 사용을 강력하게 만드는 것입니다. 특히 일} 처리에 실패하면 예외가 _ 생합니다. 그 예외를 잡아서 호출자에게 넘기고 싶습니다. 다른 스레드가 끝내기 전에 (중단되었거나 완료되었는지) 100 % 확신하고 싶습니다. 나중에 프로그램에서 예외를 복구 할 때 예기치 않은 행이 테이블에 계속 도착하지 않기를 원하기 때문입니다.

는 여기에 내가 무슨 짓을했는지의 :

/** Method to insert a single batch. */ 
private void insertBatchPostings(Collection<Posting> postings) throws PostingUpdateException 
{ 
    // insert the batch using a single INSERT invokation 
    // throw a PostingUpdateException if anything goes wrong 
} 

private static final int insertionThreads = 5; 

/** Method to insert a collection of batches in parallel, using the above. */ 
protected void insertBatchPostingsThreaded(Collection<Collection<Posting>> batches) throws PostingUpdateException 
{ 
    ExecutorService pool = Executors.newFixedThreadPool(insertionThreads); 
    Collection<Future> futures = new ArrayList<Future>(batches.size()); 

    for (final Collection<Posting> batch : batches) { 
     Callable c = new Callable() { 
      public Object call() throws PostingUpdateException { 
       insertBatchPostings(batch); 
       return null; 
      }    
     }; 
     /* So we submit each batch to the pool, and keep a note of its Future so we can check it later. */ 
     futures.add(pool.submit(c)); 
    } 

    /* Pool is running, indicate that no further work will be submitted to it. */ 
    pool.shutdown(); 

    /* Check all the futures for problems. */ 
    for (Future f : futures) { 
     try { 
      f.get(); 
     } catch (InterruptedException ex) { 
      throw new PostingUpdateException("Interrupted while processing insert results: " + ex.getMessage(), ex); 
     } catch (ExecutionException ex) { 
      pool.shutdownNow(); 
      throw (PostingUpdateException) ex.getCause(); 
     } 
    } 
} 

이 나는 ​​모든 스레드가 휴면 보장 할 반환 무렵.

질문

은 (내가 부탁 해요 정확히 명확히하기 위해 노력하고있어.)

  1. 위의 코드가 완전히 견고, 그 어떤 스레드 삽입에 insertBatchPostingsThreaded 후 계속 작동 보고?
  2. Java 동시성 기능을 사용하여보다 효율적이고 간편하게 사용할 수있는 방법이 있습니까? 내 코드는 나에게 너무 복잡해 보입니다 (가장자리가없는 경우 의혹을 제기 함).
  3. 하나의 스레드가 실패하자마자 실패하게하는 가장 좋은 방법은 무엇입니까?

나는 자연적인 자바 프로그래머가 아니기 때문에 나는 그 사실을 광고하지 않는 무언가로 끝나기를 바라고있다. :)

+0

아우. 코드를 읽기 쉽도록 generics를 사용할 수 있습니까? –

+0

배치 삽입에 대한 @Edmund 테이블 인덱스를 비활성화하면 속도가 향상됩니다. 인덱스 재 계산을 트리거해야합니다. – hidralisk

+0

@ 루이스 (Loois) - 정확하게 작동하는지 확인하기 위해 작업 프로그램에서 축 어적으로 복사했습니다. 기존 앱입니다. 그러나 나는 그것을 현대 자바로 번역하려고 시도했다. for 루프가 당신에게 가장 불쾌감을 준다고 추측하지만 컬렉션 유형도 변환했습니다. – Edmund

답변

1

구아바의 Futures.successfulAsList은 선물 목록을 입력으로 사용하고 미래의 "그 값은 모든 성공적인 입력 선물의 가치를 포함하는 목록입니다." Future을 생성 한 후 get()으로 전화 한 다음 원래의 미래의 목록을 검토하여 오류가 없는지 확인할 수 있습니다.

+0

내 다른 요구 사항 (나는 질문에 추가했습니다)은 실패한 경우 풀의 나머지 작업을 취소하거나 중단하여 빠르게 실패 할 수 있다는 것입니다. 구아바에 도움이 될만한 것이 있습니까? – Edmund

+0

아. 나는 다른 모든 스레드가 실패하기를 바라는 것을 보지 못했습니다. 그럼에도 불구하고, 모든 미래에 콜백을 추가하여 'ListenableFuture'를 사용하여 다른 모든 미래를 취소하는 것은 어렵지 않을 것입니다 ... –

+0

그러면 ListenableFuture가 리스너를 호출하여 풀의 shutdownNow를 호출할까요? Java 소스를 보면 shutdownNow가 대기중인 모든 작업을 취소하는 것으로 보이므로 이미 내 코드에서이를 수행합니다.하지만 코드를 Guava의 코드를 사용하여 정리할 수 있다면 그 모든 작업을 수행 할 수 있습니다. – Edmund

관련 문제