2011-10-10 2 views
2

최대 절전 모드 및 일괄 업데이트에 대해 많은 논의가 있었지만, 여기서는 내 특정 시나리오에서 모든 전문가로부터 의견을 얻기를 바랍니다. Document 개체의 목록을 반복하고 각 문서에 대해 Document 개체의 속성으로 DOCUMENT_METADATA 테이블을 업데이트해야합니다.최대 절전 모드 및 일괄 업데이트

표준 JDBC 2.0 일괄 업데이트를 사용하면됩니다. 그러나 JDBC 사용은 응용 프로그램 전체에서 Hibernate를 사용하기 위해 제 자리에있는 소프트웨어 표준에 위배되며 예외를 만들지 않을 것입니다.

Hibernate를 사용하기 위해서 Document 객체의 문서 ID가 주어 졌을 때 DocumentMetadata 객체를 먼저 가져와야한다. 반복하고 DocumentMetadata 속성을 설정 한 다음 테이블을 업데이트해야한다.

내가 내가 N 수 없어요 최상의 경우로, n 개의 레코드

for each document { 
    //fetch DocumentMetadata object given the id from Document 
    //invoke setter on DocumentMetadata object 
    em.persist(DocumentMetadata); 
    if (count % 50 == 0) { 
    em.flush(); //flush a batch of updates and release memory: 
    em.clear(); 
    } 

} 

(I는 한 번에 약 10,000 개의 레코드를 실행한다)와 같은 뭔가를 할 수는 최대 절전 모드 접근 방식 = 1 업데이트를 선택 위? 내 테이블의 크기 (DOCUMENT_METADATA 테이블에 100 개 이상의 열과 1 백만 개의 레코드가 있음)를 감안할 때 JDBC 접근 방식으로 성능 문제가 발생할 수 있습니다.

의견이 있으십니까?

감사 콥

+0

기술적으로 정확하게 "최대 절전 모드"를 사용하고 있지 않습니다. JPA를 사용 중입니다. JPA 구현은 단지 Hibernate 일 것이다. JPA 컨텍스트에서이 질문을 할 수 있습니다. – BalusC

답변

2

hvgotcodes (일괄 처리 업데이트 사용 방법에 대한 최대 절전 모드 문서 및 메모리 문제없이 단일 트랜잭션에서 수천 개의 엔티티를 처리하는 방법을 알려주는) 뛰어난 조언 외에도 최적화를 사용하면 DocumentMetaData는 하나씩보다는 청크 단위로 나타납니다.

청크 크기는 JDBC 일괄 처리 크기와 동일해야합니다. 그리고 N 개의 문서 ID를 (예를 들어) 20 개의 청크로 분할하고 where id in (:idsOfChunk) 절을 사용해야합니다.

마지막으로, persist에 대한 호출이 유용하지 않다는 것을 지적하고자합니다. 엔티티 관리자를 사용하여 데이터베이스에서로드 된 엔티티가 첨부되고이 엔티티에 대한 모든 변경 사항이 자동으로 데이터베이스에 기록됩니다. 플러시 시간.

+0

방금 ​​DocumentMetaData가 레코드를 검색하기 위해 ID가 아닌 여러 열이 필요하다는 것을 알았습니다 (여러 PK가 있음). DocumentMetaDataPK 객체 컬렉션을 (: idsOfChunk)에 전달할 수 있습니까? 그렇지 않은 경우, 하나 이상의 키가 관련되어있을 때 청크로 가져 오는 다른 전략이 있습니까? – phewataal

+0

예, 정상적으로 작동합니다. 생성 된 SQL은 다음 버그에서 설명하는 것과 같습니다. https://hibernate.onjira.com/browse/HSEARCH-306 –

+0

컬렉션의 요소 하나만 사용하여 DocumentMetaDataPK 객체 컬렉션을 (: idsOfChunk)에 전달하려고했습니다. Hibernate가 SQL을 select로 뱉어 낸다.DOCMETADATA legacy0_ (legacy0_.DOC_ID, legacy0_.DOC_TYPE_ID, legacy0_.DOC_REF_ID, legacy0_.EFF_DATE)에서 (?,?,?,?)에 있지만 어쨌든 예외가 발생합니다. "예기치 않은 토큰 :, 문 [select ..... ] ". 나는 soemthing 명백한가 누락 되었습니까? – phewataal

3

JPA, 절대적으로 일괄 작업을 지원 최대 절전 모드. jdbc로 무엇을 하든지 상관없이 this으로하십시오.

1

이것은 일괄 저장/업데이트하기위한 코드입니다. 나는 우리가 삽입 될 레코드의 배치 제한을 가지고 있기 때문에 이런 방식으로하고있다. 컬렉션에 25k 개의 항목이 있으면 1000의 일괄 처리로 삽입됩니다.

private static int BATCH_SIZE = 1000;

private void saveBulkEntries(
     final Collection<? extends MyObject> entries, 
     final String insertSql) { 
    if (entries.isEmpty()) { 
     return; 
    } 

    // Create a new session independent of the current hibernate session 
    // This avoids problems with the job transactions 
    StatelessSession session = this.hibernateTemplate.getSessionFactory() 
      .openStatelessSession(); 

    Transaction transaction = null; 

    Long entryCounter = 0L; 

    PreparedStatement batchUpdate = null; 
    try { 
     transaction = session.beginTransaction(); 
     batchUpdate = session.connection().prepareStatement(insertSql); 

     for (MyObject entry : entries) { 
      entry.addEntry(batchUpdate); 
      batchUpdate.addBatch(); 

      if (++entryCounter % BATCH_SIZE == 0) { 
       // Reached limit for uncommitted entries, so commit 
       batchUpdate.executeBatch(); 
      } 
     } 

     // Commit any entries that have not been committed yet 
     batchUpdate.executeBatch(); 
     batchUpdate.close(); 
     batchUpdate = null; 
    } 
    catch (HibernateException ex) { 
     transaction.rollback(); 
     transaction = null; 
    } 
    catch (SQLException ex) { 
     transaction.rollback(); 
     transaction = null; 
    } 
    finally { 
     if (transaction != null) { 
      transaction.commit(); 
     } 

     if (batchUpdate != null) { 
      try { 
       batchUpdate.cancel(); 
       batchUpdate.close(); 
      } 
      catch (SQLException ex) { 

      } 
     } 

     session.close(); 
    } 
} 
+0

답변이 업데이트되었습니다. – vsingh