2017-05-22 2 views
1

그래서 EMF/Texo 조합을 사용하여 생성되고 주석 처리 된 많은 수의 클래스가 있습니다. JPA/Eclipselink를 사용하여 SQL Server 데이터베이스에 저장합니다.JPA/Eclipselink/Texo의 대량 삽입이 순수 JDBC 삽입보다 속도가 느린 이유는 무엇입니까?

많은 수의 개체를 유지해야 할 때 성능이 저하됩니다. 따라서 프레임 워크 (foo)와 일반 JDBC 대량 삽입 (bar)을 사용하여 대량 삽입의 성능을 비교하는 두 개의 테스트 케이스 (TestBulkInserts.java 참조)를 작성했습니다.

평균 크기 미만의 대량 삽입물 인 10000 개의 개체를 삽입 할 때. foo는()과 바()주고 다음 시간 :

, 독일 - 기간 JPA/TEXO는 : 같은 큰 차이가 왜 궁금하네요 892ms

(:

, 독일 - 기간 일반 JDBC를 19.620ms 더 많은 요인 20!). 크기가 커지면 악화됩니다.

DatabaseObject 클래스는 PersistableObjectClass.java (아래 참조)를 확장하며 Texo + EMF를 사용하여 (각각의 DAO 클래스를 포함하여) 생성됩니다.

필요한 연결 세부 정보를 제외하고 persistence.xml에 특정 설정을 추가하지 않았습니다.

TestBulkInserts.java :

import java.sql.Connection; 
import java.sql.Date; 
import java.sql.DriverManager; 
import java.sql.PreparedStatement; 
... 
import com.ownproject.loader.generated.DbModelPackage; 
import com.ownproject.loader.DatabaseObject; 
import com.ownproject.loader.dao.DatabaseObjectDao; 
import javax.persistence.Persistence; 
import org.eclipse.emf.texo.server.store.EntityManagerProvider; 
import org.junit.Test; 

public class TestBulkInserts { 

private static final int NUM_LOOPS = 10000; 

@Test 
public void foo() { 
    TestMethods.connectTestDBandEMF(); 
    // basically does this 
    // DbModelPackage.initialize(); 
    // EntityManagerProvider.getInstance().setEntityManagerFactory(Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_TEST)); 

    Stopwatch sw = Stopwatch.createStarted(); 

    DatabaseObjectDao dao = new DatabaseObjectDao(); 
    dao.getEntityManager().getTransaction().begin(); 
    for (int i = 0; i < NUM_LOOPS; i++) { 
    DatabaseObject dbo = new DatabaseObject(); 
    dbo.setString(UUID.randomUUID().toString()); 
    dbo.setInsert_time(Date.valueOf(LocalDate.now())); 
    dao.insert(dbo); 
    } 
    dao.getEntityManager().getTransaction().commit(); 

    sw.stop(); 
    System.out.println(String.format("Duration JPA/Texo: %,dms", sw.elapsed(TimeUnit.MILLISECONDS))); 
    } 

@Test 
public void bar() throws ClassNotFoundException, SQLException { 
    Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); 
    String connectionUrl = "jdbc:sqlserver://hostname:1433;databaseName=local_test;user=sa;password=blablub;"; 
    Connection con = DriverManager.getConnection(connectionUrl); 
    con.setAutoCommit(false); 

    Stopwatch sw = Stopwatch.createStarted(); 

    PreparedStatement insertStatement = con.prepareStatement("INSERT INTO DatabaseObject(b_id, insert_time) VALUES (?, ?)"); 
    for (int i = 0; i < NUM_LOOPS; i++) { 
    insertStatement.setString(1, UUID.randomUUID().toString()); 
    insertStatement.setDate(2, Date.valueOf(LocalDate.now())); 
    insertStatement.addBatch(); 
    } 
    insertStatement.executeBatch(); 
    con.commit(); 
    con.close(); 

    sw.stop(); 
    System.out.println(String.format("Duration plain JDBC: %,dms", sw.elapsed(TimeUnit.MILLISECONDS))); 
    } 
} 

PersistableObjectClass.java :

import javax.persistence.Basic; 
... 
import javax.persistence.TemporalType; 

@Entity(name = "PersistableObjectClass") 
@MappedSuperclass() 
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 
public abstract class PersistableObjectClass { 

    @Basic() 
    @Temporal(TemporalType.TIMESTAMP) 
    private Date insert_time = null; 

    @Id() 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private int s_id = 0; 

... 
} 
+0

가주의 깊게 읽기 :

그래서,이처럼 배치 작업이 보일 것입니다 방법입니다 배치 세션 배치 – zloster

+0

힌트에 감사드립니다! 기억에 문제가 있니? 플러싱이 로딩 시간을 감소시키지 않았기 때문에. – KayleeTheMech

+1

JPA는 오버 헤드를 추가하기 때문에 약간의 차이가있을 것으로 예상되지만 숫자를 설명하기에는 너무 많은 변수가 있습니다. 당신은 정말로 당신이 사과를 비교하기 위해 사과를 만들고 있는지 확인하기 위해 생성 된 SQL을보기 위해 로그인을 사용 했습니까? JPA/EclipseLink에서 사용하는 설정은 무엇입니까? 배치 크기와 일치하는 사전 할당을 허용하는 대신 시퀀스 관리에 Identity를 사용하는 이유는 무엇입니까? – Chris

답변

2

바와 같이, this article 설명뿐만 아니라 당신이 batch updates를 사용해야하지만, 당신은 또한 보장 할 필요가 트랜잭션이 일정한 간격으로 커밋 된 경우 그렇지 않으면 장기 실행 트랜잭션으로 실행됩니다.이 트랜잭션은 2PL 또는 MVCC 데이터베이스 엔진 https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html# :

int entityCount = 50; 
int batchSize = 25; 

EntityManager entityManager = null; 
EntityTransaction transaction = null; 

try { 
    entityManager = entityManagerFactory() 
     .createEntityManager(); 

    transaction = entityManager.getTransaction(); 
    transaction.begin(); 

    for (int i = 0; i < entityCount; ++i) { 
     if (i > 0 && i % batchSize == 0) { 
      entityManager.flush(); 
      entityManager.clear(); 

      transaction.commit(); 
      transaction.begin(); 
     } 

     Post post = new Post( 
      String.format("Post %d", i + 1) 
     ); 
     entityManager.persist(post); 
    } 

    transaction.commit(); 
} catch (RuntimeException e) { 
    if (transaction != null && 
     transaction.isActive()) { 
     transaction.rollback(); 
    } 
    throw e; 
} finally { 
    if (entityManager != null) { 
     entityManager.close(); 
    } 
} 
관련 문제