2016-02-26 1 views
1

J'ai travaillé sur une solution BulkSMS pour un de mes clients, et j'ai décidé d'utiliser JPA (Eclipselink) comme ORM et la base de données sous-jacente est PostgreSQL 9.5.1.Eclipselink et l'écriture par lots Postgresql

Mon problème est que chaque fois que j'envoie une requête avec 65 000 enregistrements à persister, il faut environ 27 secondes pour terminer l'opération. J'ai décidé d'implémenter le regroupement de séquences, la pré-allocation de séquence = 1000 et l'écriture par lots, mais cela n'a réussi qu'à supprimer 15 secondes de l'opération. Après avoir étudié les journaux de la base de données, j'ai remarqué que les mêmes requêtes sont appelées avant et après l'application de l'optimisation.

Voici mon optimisé persistance.xml:

<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="com.kw.ktt.sms.server" transaction-type="JTA"> 
    <jta-data-source>SMSDB</jta-data-source> 
    <non-jta-data-source>sequence</non-jta-data-source> 
    <class>com.kw.ktt.sms.server.core.TestClass</class> 
    <class>com.kw.ktt.sms.server.jpa.Customer</class> 
    <class>com.kw.ktt.sms.server.jpa.SMSAccount</class> 
    <class>com.kw.ktt.sms.server.jpa.SMSTransaction</class> 
    <class>com.kw.ktt.sms.server.jpa.ContactGroup</class> 
    <class>com.kw.ktt.sms.server.jpa.PhoneNumber</class> 
    <properties> 
     <property name="eclipselink.application-location" value="/Users/mousaalsulaimi/Desktop"/> 
     <property name="eclipselink.ddl-generation.output-mode" value="database"/> 
     <property name="eclipselink.logging.connection" value="true"/> 
     <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/> 
     <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/> 
     <property name="eclipselink.jdbc.batch-writing" value="JDBC" /> 
     <property name="eclipselink.jdbc.batch-writing.size" value="1000"/> 
     <property name="eclipselink.jdbc.sequence-connection-pool" value="true" /> 
     <property name="eclipselink.connection-pool.sequence.nonJtaDataSource" value="sequence"/> 
     <property name="eclipselink.connection-pool.sequence.intial" value="1000" /> 
    </properties> 
</persistence-unit> 

Comme mentionné ci-dessus, je suis sur un pool de connexion JTA pour la persistance (appelée SMSDB) et une connexion non JTA pour le séquençage (appelé séquence) chacun avec un utilisateur DB différent afin de suivre facilement la connexion du journal DB.

Journaux pour la connexion non optimisée are here - ceci est un échantillon de 10 enregistrements seulement.

Les journaux pour la connexion optimisée are here - il s'agit d'un échantillon de 10 enregistrements seulement.

Quelqu'un peut-il m'expliquer ce que je fais de mal et pourquoi les deux paramètres de persistance produisent les mêmes requêtes même s'il y a une amélioration réelle de 15 secondes. Une autre chose, j'ai défini la pré-allocation de la séquence à 1000 dans le code source de l'entité et, à en juger par le séquençage des journaux de base de données, fonctionne comme prévu et récupère la valeur d'incrément correcte. Ce que je suis préoccupé par l'écriture est du lot et je crains qu'il ne soit pas configuré correctement dans le persistence.xml

Mise à jour

Je permet l'enregistrement en lien éclipse comme conseillé par Chris, voici les journaux EclipseLink produites lors de l'utilisation du persistence.xml

2016-02-27T23:59:28.307+0300|Fine: SELECT CUSTOMERID, CIVILIDNUMBER, CREATEDATE, CREATEDBY, EMAIL, FULLNAME, ISACTIVE, ISADMIN, MALE, PASSWORD, PERSONAL, PHONENUMBER, STATUS, USERNAME, ACCOUNT_SMSACCOUNTID FROM CUSTOMER WHERE (CUSTOMERID = ?) 
    bind => [1 parameter bound] 
2016-02-27T23:59:28.310+0300|Fine: SELECT SMSACCOUNTID, OOOREDOOO_BALANCE, VIVA_BALANCE, ZAIN_BALANCE FROM SMSACCOUNT WHERE (SMSACCOUNTID = ?) 
    bind => [1 parameter bound] 
2016-02-27T23:59:28.312+0300|Fine: select nextval('SEQ_GEN_SEQUENCE') 
2016-02-27T23:59:28.327+0300|Fine: select nextval('number_seq') 
2016-02-27T23:59:28.331+0300|Info: this is the id 1 
2016-02-27T23:59:28.332+0300|Fine: INSERT INTO SMSACCOUNT (SMSACCOUNTID, OOOREDOOO_BALANCE, VIVA_BALANCE, ZAIN_BALANCE) VALUES (?, ?, ?, ?) 
    bind => [4 parameters bound] 
2016-02-27T23:59:28.335+0300|Fine: INSERT INTO CUSTOMER (CUSTOMERID, CIVILIDNUMBER, CREATEDATE, CREATEDBY, EMAIL, FULLNAME, ISACTIVE, ISADMIN, MALE, PASSWORD, PERSONAL, PHONENUMBER, STATUS, USERNAME, ACCOUNT_SMSACCOUNTID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
    bind => [15 parameters bound] 
2016-02-27T23:59:28.337+0300|Fine: INSERT INTO CONTACTGROUP (GROUPID, CREATEBY, CREATEDATE, GROUPDESCRIPTION, GROUPNAME) VALUES (?, ?, ?, ?, ?) 
    bind => [5 parameters bound] 
2016-02-27T23:59:28.339+0300|Fine: INSERT INTO PHONENUMBER (NUMBERID, OPERATOR, PHONENUMBER) VALUES (?, ?, ?) 
2016-02-27T23:59:28.339+0300|Fine: bind => [3 parameters bound] 
2016-02-27T23:59:28.339+0300|Fine: bind => [3 parameters bound] 
2016-02-27T23:59:28.339+0300|Fine: bind => [3 parameters bound] 
2016-02-27T23:59:28.339+0300|Fine: bind => [3 parameters bound] 
2016-02-27T23:59:28.339+0300|Fine: bind => [3 parameters bound] 
2016-02-27T23:59:28.339+0300|Fine: bind => [3 parameters bound] 
2016-02-27T23:59:28.339+0300|Fine: bind => [3 parameters bound] 
2016-02-27T23:59:28.340+0300|Fine: bind => [3 parameters bound] 
2016-02-27T23:59:28.340+0300|Fine: bind => [3 parameters bound] 
2016-02-27T23:59:28.340+0300|Fine: bind => [3 parameters bound] 
2016-02-27T23:59:28.342+0300|Fine: UPDATE CONTACTGROUP SET customerID = ? WHERE (GROUPID = ?) 
    bind => [2 parameters bound] 
2016-02-27T23:59:28.343+0300|Fine: UPDATE PHONENUMBER SET groupId = ? WHERE (NUMBERID = ?) 
2016-02-27T23:59:28.344+0300|Fine: bind => [2 parameters bound] 
2016-02-27T23:59:28.344+0300|Fine: bind => [2 parameters bound] 
2016-02-27T23:59:28.344+0300|Fine: bind => [2 parameters bound] 
2016-02-27T23:59:28.344+0300|Fine: bind => [2 parameters bound] 
2016-02-27T23:59:28.344+0300|Fine: bind => [2 parameters bound] 
2016-02-27T23:59:28.344+0300|Fine: bind => [2 parameters bound] 
2016-02-27T23:59:28.344+0300|Fine: bind => [2 parameters bound] 
2016-02-27T23:59:28.344+0300|Fine: bind => [2 parameters bound] 
2016-02-27T23:59:28.344+0300|Fine: bind => [2 parameters bound] 
2016-02-27T23:59:28.344+0300|Fine: bind => [2 parameters bound] 

et en dessous des registres de liaison éclipse produits optimisée pour l'utilisation de la persistence.xml originale

2016-02-28T08:56:25.440+0300|Fine: SELECT CUSTOMERID, CIVILIDNUMBER, CREATEDATE, CREATEDBY, EMAIL, FULLNAME, ISACTIVE, ISADMIN, MALE, PASSWORD, PERSONAL, PHONENUMBER, STATUS, USERNAME, ACCOUNT_SMSACCOUNTID FROM CUSTOMER WHERE (CUSTOMERID = ?) 
    bind => [1 parameter bound] 
2016-02-28T08:56:25.443+0300|Fine: SELECT SMSACCOUNTID, OOOREDOOO_BALANCE, VIVA_BALANCE, ZAIN_BALANCE FROM SMSACCOUNT WHERE (SMSACCOUNTID = ?) 
    bind => [1 parameter bound] 
2016-02-28T08:56:25.445+0300|Fine: select nextval('SEQ_GEN_SEQUENCE') 
2016-02-28T08:56:25.447+0300|Fine: select nextval('number_seq') 
2016-02-28T08:56:25.449+0300|Info: this is the id 1 
2016-02-28T08:56:25.450+0300|Fine: INSERT INTO SMSACCOUNT (SMSACCOUNTID, OOOREDOOO_BALANCE, VIVA_BALANCE, ZAIN_BALANCE) VALUES (?, ?, ?, ?) 
    bind => [4 parameters bound] 
2016-02-28T08:56:25.451+0300|Fine: INSERT INTO CUSTOMER (CUSTOMERID, CIVILIDNUMBER, CREATEDATE, CREATEDBY, EMAIL, FULLNAME, ISACTIVE, ISADMIN, MALE, PASSWORD, PERSONAL, PHONENUMBER, STATUS, USERNAME, ACCOUNT_SMSACCOUNTID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
    bind => [15 parameters bound] 
2016-02-28T08:56:25.452+0300|Fine: INSERT INTO CONTACTGROUP (GROUPID, CREATEBY, CREATEDATE, GROUPDESCRIPTION, GROUPNAME) VALUES (?, ?, ?, ?, ?) 
    bind => [5 parameters bound] 
2016-02-28T08:56:25.452+0300|Fine: INSERT INTO PHONENUMBER (NUMBERID, OPERATOR, PHONENUMBER) VALUES (?, ?, ?) 
    bind => [3 parameters bound] 
2016-02-28T08:56:25.453+0300|Fine: INSERT INTO PHONENUMBER (NUMBERID, OPERATOR, PHONENUMBER) VALUES (?, ?, ?) 
    bind => [3 parameters bound] 
2016-02-28T08:56:25.453+0300|Fine: INSERT INTO PHONENUMBER (NUMBERID, OPERATOR, PHONENUMBER) VALUES (?, ?, ?) 
    bind => [3 parameters bound] 
2016-02-28T08:56:25.454+0300|Fine: INSERT INTO PHONENUMBER (NUMBERID, OPERATOR, PHONENUMBER) VALUES (?, ?, ?) 
    bind => [3 parameters bound] 
2016-02-28T08:56:25.454+0300|Fine: INSERT INTO PHONENUMBER (NUMBERID, OPERATOR, PHONENUMBER) VALUES (?, ?, ?) 
    bind => [3 parameters bound] 
2016-02-28T08:56:25.454+0300|Fine: INSERT INTO PHONENUMBER (NUMBERID, OPERATOR, PHONENUMBER) VALUES (?, ?, ?) 
    bind => [3 parameters bound] 
2016-02-28T08:56:25.455+0300|Fine: INSERT INTO PHONENUMBER (NUMBERID, OPERATOR, PHONENUMBER) VALUES (?, ?, ?) 
    bind => [3 parameters bound] 
2016-02-28T08:56:25.455+0300|Fine: INSERT INTO PHONENUMBER (NUMBERID, OPERATOR, PHONENUMBER) VALUES (?, ?, ?) 
    bind => [3 parameters bound] 
2016-02-28T08:56:25.455+0300|Fine: INSERT INTO PHONENUMBER (NUMBERID, OPERATOR, PHONENUMBER) VALUES (?, ?, ?) 
    bind => [3 parameters bound] 
2016-02-28T08:56:25.456+0300|Fine: INSERT INTO PHONENUMBER (NUMBERID, OPERATOR, PHONENUMBER) VALUES (?, ?, ?) 
    bind => [3 parameters bound] 
2016-02-28T08:56:25.456+0300|Fine: UPDATE CONTACTGROUP SET customerID = ? WHERE (GROUPID = ?) 
    bind => [2 parameters bound] 
2016-02-28T08:56:25.457+0300|Fine: UPDATE PHONENUMBER SET groupId = ? WHERE (NUMBERID = ?) 
    bind => [2 parameters bound] 
2016-02-28T08:56:25.457+0300|Fine: UPDATE PHONENUMBER SET groupId = ? WHERE (NUMBERID = ?) 
    bind => [2 parameters bound] 
2016-02-28T08:56:25.458+0300|Fine: UPDATE PHONENUMBER SET groupId = ? WHERE (NUMBERID = ?) 
    bind => [2 parameters bound] 
2016-02-28T08:56:25.458+0300|Fine: UPDATE PHONENUMBER SET groupId = ? WHERE (NUMBERID = ?) 
    bind => [2 parameters bound] 
2016-02-28T08:56:25.459+0300|Fine: UPDATE PHONENUMBER SET groupId = ? WHERE (NUMBERID = ?) 
    bind => [2 parameters bound] 
2016-02-28T08:56:25.459+0300|Fine: UPDATE PHONENUMBER SET groupId = ? WHERE (NUMBERID = ?) 
    bind => [2 parameters bound] 
2016-02-28T08:56:25.460+0300|Fine: UPDATE PHONENUMBER SET groupId = ? WHERE (NUMBERID = ?) 
    bind => [2 parameters bound] 
2016-02-28T08:56:25.460+0300|Fine: UPDATE PHONENUMBER SET groupId = ? WHERE (NUMBERID = ?) 
    bind => [2 parameters bound] 
2016-02-28T08:56:25.460+0300|Fine: UPDATE PHONENUMBER SET groupId = ? WHERE (NUMBERID = ?) 
    bind => [2 parameters bound] 
2016-02-28T08:56:25.461+0300|Fine: UPDATE PHONENUMBER SET groupId = ? WHERE (NUMBERID = ?) 
    bind => [2 parameters bound] 

Il existe évidemment une grande différence entre les requêtes produites lors de l'utilisation du fichier persistence.xml optimisé et le fichier persistence.xml d'origine.

Merci

+0

On dirait que la mise à jour de ContactGroup force l'exécution de l'instruction batch Phonenumber plus tôt que je ne le pensais. Vous pouvez examiner le mappage sur ceci pour déterminer pourquoi EclipseLink pense qu'il doit exécuter l'instruction ContactGroup avant de pouvoir continuer avec Phonenumbers. – Chris

Répondre

0

Allumez l'enregistrement de SQL EclipseLink et vous devriez voir une différence dans la façon dont les déclarations sont préparées et traitées dans JDBC, qui devrait montrer pourquoi il y a 15 secondes de différence. Je ne suis pas familier avec la propriété eclipselink.connection-pool.sequence.intial - Ce que vous devriez probablement utiliser est la configuration allocationSize dans votre générateur de séquence lui-même pour permettre l'obtention de 1000 séquences à la fois.S'il n'est pas défini, l'écriture par lots réduit le nombre d'instructions d'insertion, mais vous verrez toujours un grand nombre d'instructions pour obtenir des numéros de séquence, mais sur des connexions différentes - le séquencement utilise son propre pool de connexions.

+0

Je n'ai peut-être pas mentionné cela mais j'ai déjà défini la taille d'allocation à 1000, cela est défini dans le code source de l'Entité. Je ne sais pas que le séquençage est le problème puisque les journaux attachés montrent que le lien eclipse demande correctement les valeurs de séquence, par exemple pour 65000 enregistrements eclipse link appelle le sequence.nextVal 60 fois seulement, ce qui signifie que la préallocation fonctionne correctement. En ce qui concerne eclipselink.connection-pool.sequence .intial, je pense que cela est ignoré par eclipslink puisque j'utilise un pool de connexion externe (glassfish) –

+0

Mon souci est que l'écriture par lots ne fonctionne pas ou ne soit pas correctement configurée dans la persistance .xml, de toute façon je vais activer la journalisation jdbc comme vous l'avez indiqué comme vérifier les résultats, je n'étais pas au courant de cette fonctionnalité. Merci beaucoup Chris. –

+0

Merci beaucoup Chris les logs eclipselink ont ​​beaucoup aidé, mais je m'attendais à ce que l'optimisation se fasse au niveau de la base de données, pas au niveau de l'ORM, les logs de la base de données semblent identiques. –