2014-10-17 21 views
5

Tôi đang cố gắng tối ưu hóa việc triển khai JPA của tôi, bằng cách sử dụng EclipseLink. Tôi đã thêm hoạt động hàng loạt vào nó. Nhưng nó vẫn đang mất rất nhiều thời gian để làm 50 000 chèn. Phải mất hơn 10 lần thời gian cần thiết để thực hiện việc chèn chính xác bằng cách sử dụng SQL thô với JDBC.Chèn loạt EclipseLink rất rất chậm

Để đảm bảo hoạt động hàng loạt trong thực tế hoạt động, tôi đã sử dụng Wireshark để kiểm tra các gói của tôi và nó không sử dụng chèn hàng loạt.

Dưới đây là một trong những gói chèn:

enter image description here

Nó không được thực hiện:

INSERT INTO ENTITYCLASSTEST (LASTNAME, NAME) VALUES ('sfirosijfhgdoi 0', 'dsufius0'), ('sfirosijfhgdoi 0', 'dsufius0'), ('sfirosijfhgdoi 0', 'dsufius0'), ('sfirosijfhgdoi 0', 'dsufius0')... and so on 

tôi đã mong đợi nó để làm như trên nhưng nó được chèn một dòng cho mỗi gói và không nhiều dòng cho mỗi gói.

Dưới đây là là Entity Lớp tôi:

@Entity 
public class EntityClassTest implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Long id; 

    private String name; 
    private String lastname; 

    public EntityClassTest() { 
    } 

    public EntityClassTest(Long id, String name, String lastname) { 
     this.id = id; 
     this.name = name; 
     this.lastname = lastname; 
    } 

    public EntityClassTest(String name, String lastname) { 
     this.name = name; 
     this.lastname = lastname; 
    } 

    public Long getId() { 
     return id; 
    } 

    public String getName() { 
     return name; 
    } 

    public String getLastName() { 
     return lastname; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public void setLastName(String lastname) { 
     this.lastname = lastname; 
    } 

    @Override 
    public int hashCode() { 
     int hash = 0; 
     hash += (id != null ? id.hashCode() : 0); 
     return hash; 
    } 

    @Override 
    public boolean equals(Object object) { 
     // TODO: Warning - this method won't work in the case the id fields are not set 
     if (!(object instanceof EntityClassTest)) { 
      return false; 
     } 
     EntityClassTest other = (EntityClassTest) object; 
     if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) { 
      return false; 
     } 
     return true; 
    } 

    @Override 
    public String toString() { 
     return "database.EntityClassTest [id=" + id + " ]"; 
    } 

} 

Và đây là kiên trì của tôi phương pháp mà nhận được một List và vẫn tồn tại tất cả các đối tượng bên trong.

public void insertListToTable(final String persistenceUnit, final List list) throws SQLException { 
     final EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnit); 
     final EntityManager entityManager = entityManagerFactory.createEntityManager(); 
     final EntityTransaction transaction = entityManager.getTransaction(); 

     try {    
      final int listSize = list.size(); 
      transaction.begin(); 

      for (int i = 0; i<listSize; i++) { //Object object : list) { 
       final Object object = list.get(i); 
       entityManager.persist(object); 

       if (i % 500 == 0) { //500, same as the JDBC batch size defined in the persistence.xml 
        //flush a batch of inserts and release memory: 
        entityManager.flush(); 
        entityManager.clear(); 
       } 
      } 
      transaction.commit(); 
     } 
     catch(Exception e) { 
      if (transaction != null) { 
       transaction.rollback(); 
      } 
      throw new SQLException(e.getMessage()); 
     } 
     finally { 
      entityManager.close(); 
     } 
    } 

persistence.xml của tôi, nơi tôi đặt 500 là giá trị hàng loạt, tập tin là:

<?xml version="1.0" encoding="UTF-8"?> 
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> 
<persistence-unit name="ExternalServer" transaction-type="RESOURCE_LOCAL"> 
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> 
    <!-- List of Entity classes --> 
    <class>model.EntityClassTest</class> 
    <properties> 
     <property name="javax.persistence.jdbc.url" value="jdbc:mysql://myServer:3306/testdb?zeroDateTimeBehavior=convertToNull"/> 
     <property name="javax.persistence.jdbc.user" value="testdbuser"/> 
     <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> 
     <property name="javax.persistence.jdbc.password" value="myPassword"/> 
     <property name="javax.persistence.schema-generation.database.action" value="create"/> 

     <!-- Weaving --> 
     <property name="eclipselink.weaving" value="static"/> 
     <!-- SQL dialect/Database type --> 
     <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/> 
     <property name="eclipselink.target-database" value="MySQL"/> 
     <!-- Tell the JPA provider to, by default, create the table if it does not exist. --> 
     <property name="javax.persistence.schema-generation.database.action" value="create"/> 
     <!-- No logging (For development change the value to "FINE") --> 
     <property name="eclipselink.logging.level" value="OFF"/> 
     <!-- Enable batch writing --> 
     <property name="eclipselink.jdbc.batch-writing" value="JDBC"/> 
     <!-- Batch size --> 
     <property name="eclipselink.jdbc.batch-writing.size" value="500"/> 

    </properties> 
    </persistence-unit> 
</persistence> 

Vì vậy, câu hỏi của tôi là, tại sao nó không batch chèn? Tôi tin rằng tôi đã cấu hình EclipseLink để làm như vậy từ những gì tôi đã đọc xung quanh trên trang web EclipseLink và ở đây SO là tốt.

/////////////////////////// EDIT //////////////// //////////

theo đề nghị của câu trả lời của Chris, tôi đã thay đổi trong EntityClassTest của tôi giá trị này @GeneratedValue(strategy = GenerationType.IDENTITY)-@GeneratedValue(strategy = GenerationType.SEQUENCE) và tái chạy thử nghiệm và các gói được gửi như trước đây (như hình ảnh tôi đã đăng ở trên). Vì vậy, nó đã không sửa chữa vấn đề của tôi, tôi sợ.

//////////////////////////// EDIT 2 /////////////// /////////

Tôi đã thay đổi mức ghi nhật ký trong tệp persistence.xml thành FINEST như được hiển thị tiếp theo.

<property name="eclipselink.logging.level" value="FINEST"/> 

Và đây là nhật ký được tạo. Tôi đặt nó vào một con nhộng vì nó khá dài.

http://pastebin.com/rKihCKMW

Nó dường như được gọi Execute query InsertObjectQuery khá nhiều lần.

//////////////////////////// EDIT 3 /////////////// /////////

Đây là phiên bản cho mỗi thành phần tôi đang sử dụng.

+-------------------------+------------------------------+ 
| Variable_name   | Value      | 
+-------------------------+------------------------------+ 
| innodb_version   | 5.6.12      | 
| protocol_version  | 10       | 
| slave_type_conversions |        | 
| version     | 5.6.12-log     | 
| version_comment   | MySQL Community Server (GPL) | 
| version_compile_machine | x86_64      | 
| version_compile_os  | Win64      | 
+-------------------------+------------------------------+ 

Netbeans 8.0 

EclipseLink (JPA 2.1) 

mysql-connector-java-5.1.24.jar 

//////////////////////// EDIT 4 //////////// ////////////

Sau câu trả lời CuriousMind của tôi đã chỉnh sửa EntityClassTest id chú thích của tôi để:

@Id 
    @GeneratedValue(strategy = GenerationType.AUTO, generator="id-seq-gen") 
    @SequenceGenerator(name="id-seq-gen", sequenceName="ID_SEQ_GEN", allocationSize=500) 
    private Long id; 

Nhưng nó đã không giải quyết vấn đề của tôi, tôi vẫn còn nhận một gói đơn cho mỗi gói (như được mô tả bằng hình ảnh ở trên) và trên nhật ký EclipseLink Tôi nhận được:

[EL Fine]: sql: 2014-10-19 06:44:02.608--ClientSession(824177287)--Connection(1674390738)--Thread(Thread[main,5,main])--SELECT LAST_INSERT_ID() 
[EL Finest]: sequencing: 2014-10-19 06:44:02.608--UnitOfWork(1985011414)--Thread(Thread[main,5,main])--assign sequence to the object (1.251 -> database.EntityClassTest [id=null ]) 
[EL Finest]: query: 2014-10-19 06:44:02.608--UnitOfWork(1985011414)--Thread(Thread[main,5,main])--Execute query InsertObjectQuery(database.EntityClassTest [id=null ]) 
[EL Finest]: query: 2014-10-19 06:44:02.608--ClientSession(824177287)--Thread(Thread[main,5,main])--Execute query ValueReadQuery(name="ID_SEQ_GEN" sql="SELECT LAST_INSERT_ID()") 
[EL Fine]: sql: 2014-10-19 06:44:02.608--ClientSession(824177287)--Connection(1674390738)--Thread(Thread[main,5,main])--INSERT INTO ENTITYCLASSTEST (LASTNAME, NAME) VALUES (?, ?) 
    bind => [sfirosijfhgdoi 2068, dsufius1034] 
[EL Fine]: sql: 2014-10-19 06:44:02.608--ClientSession(824177287)--Connection(1674390738)--Thread(Thread[main,5,main])--SELECT LAST_INSERT_ID() 
[EL Finest]: sequencing: 2014-10-19 06:44:02.608--UnitOfWork(1985011414)--Thread(Thread[main,5,main])--assign sequence to the object (1.252 -> database.EntityClassTest [id=null ]) 
[EL Finest]: query: 2014-10-19 06:44:02.608--UnitOfWork(1985011414)--Thread(Thread[main,5,main])--Execute query InsertObjectQuery(database.EntityClassTest [id=null ]) 
[EL Finest]: query: 2014-10-19 06:44:02.608--ClientSession(824177287)--Thread(Thread[main,5,main])--Execute query ValueReadQuery(name="ID_SEQ_GEN" sql="SELECT LAST_INSERT_ID()") 
[EL Fine]: sql: 2014-10-19 06:44:02.608--ClientSession(824177287)--Connection(1674390738)--Thread(Thread[main,5,main])--INSERT INTO ENTITYCLASSTEST (LASTNAME, NAME) VALUES (?, ?) 
    bind => [sfirosijfhgdoi 2244, dsufius1122] 

Và vân vân ...

+0

Bạn có thể vui lòng đăng các phiên bản của từng phần mềm bạn đang sử dụng như, MySQL, Eclipse Link, trình điều khiển MySQL, v.v. – CuriousMind

+1

Bạn có cố gắng thêm rewriteBatchedStatements = true vào thuộc tính kết nối không? –

+0

@ MárcioSouzaJúnior bạn nói đúng. Tôi quên thêm 'rewriteBatchedStatements = true' vào kết nối trong tệp' persistence.xml' tôi có nó trong JDBC của mình và nhầm lẫn là tôi nghĩ rằng tôi đã có nó trong 'persistence.xml'. Điều đó giải quyết được một phần vấn đề của tôi. Với câu trả lời của Chris, nó đã giải quyết được vấn đề của tôi. – dazito

Trả lời

3

Bạn đang sử dụng GenerationType.IDENTITY cho trình tự, đòi hỏi lấy ID từ mỗi câu lệnh chèn từng cái một. Hãy thử lược đồ sắp xếp cho phép preallocation theo lô 500 và bạn sẽ thấy các cải tiến: http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Identity_sequencing

+0

Tôi đã thay đổi trong 'EntityClassTest' giá trị này' @GeneratedValue (strategy = GenerationType.IDENTITY) 'thành' @GeneratedValue (strategy = GenerationType.SEQUENCE) 'và chạy lại kiểm tra và các gói đang được gửi như trước (như hình ảnh tôi đăng trong câu hỏi của tôi). Vì vậy, nó đã không sửa chữa vấn đề của tôi, tôi sợ. – dazito

+0

Bạn cần có thể nhận được các chuỗi theo lô phù hợp với kích thước viết lô của bạn, nếu không JPA phải làm gián đoạn lô để nhận các giá trị chuỗi bổ sung. Tôi không tin rằng MySQL có trình tự, vì vậy nó là mặc định để nhận dạng; bạn cần phải sử dụng trình tự bảng thay thế. xem http://java-persistence-performance.blogspot.com/2011/06/how-to-improve-jpa-performance-by-1825.html?showComment=1379577956140#c4472664570410361957 – Chris

0

Có vẻ thế hệ thứ tự đã gây ra sự cố, bạn tham khảo post này. Nó cung cấp cách tiếp cận của thế hệ chuỗi preallocated.

0

Đã một năm rồi, có lẽ đã quá muộn để trả lời. Trong trường hợp của tôi, tôi thấy rằng flush() gây ra vấn đề. Tôi gọi flush() sau khi persist() cho mỗi bản ghi. Điều này ngăn chặn hàng loạt văn bản để thực hiện một tối ưu hóa và kết quả trong hiệu suất chèn kém. Sau khi xóa flush(), mọi thứ diễn ra tốt đẹp.

0

này có thể được bởi vì của chuỗi/indentity (cần phải sử dụng preallocation), nhưng tôi cũng cho mysql nghĩ rằng bạn cần một tài sản chuỗi kết nối để cho phép chèn số lượng lớn:

rewriteBatchedStatements = true

jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true