JPA/Eclipselink poor performance batch update entity on ManyToOne relationship changes
I have problem with batch writing in eclipselink when i update an entity properties which link to other entity.
I have a Cardholder entity with @ManyToOne relationship with Card Entity.
@Entity
@Table(name = "...")
@NamedQueries({...})
public class Cardholder implements Serializable {
...
@JoinColumn(name = "card_number", referencedColumnName = "...")
@ManyToOne(fetch=FetchType.LAZY)
private Card card;
}
and a Card with @OneToMany relationship with cardholder
@Entity
@Table(name = "cms_card")
@NamedQueries({...})
public class Card implements Serializable {
@OneToMany(mappedBy = "card")
private List<Cardholder> cardholderList;
}
I already have List of child (persisted cardholders). Now i want to add some card to them, so : // cardholderList is a managed entity 开发者_StackOverflow中文版list.
for (Cardholder cardholder : cardholderList) {
Card newCard = new Card();
...
cardholder.setCard(newCard);
List<Cardholder> cardCardholders = new ArrayList<Cardholder>();
cardCardholders.add(cardholder);
newCard.setCardholderList(cardCardholders);
cardsToBePersisted.add(newCard);
++i;
}
I configured my Persistence.xml to use batch-writing, but performance is horribly slow for +-15000 list update. Now, when i check into generated SQL, i found that Eclipselink is creating one batch for one query, its like :
FINER: Begin batch statements
FINE: INSERT INTO cms_card (card_number, status, chip_serial_number, dwh_status, valid_until, card_holder_id, file_perso_history_id, feedback_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
FINE: bind => [9030002005890011, ACTIVE, null, false, 2015-12-10, null, 241, null]
FINER: End Batch Statements
FINER: Begin batch statements
FINE: UPDATE cms_cardholder SET card_number = ? WHERE (id = ?)
FINE: bind => [9030002005890011, 176075]
FINER: End Batch Statements
FINER: Begin batch statements
FINE: INSERT INTO cms_card (card_number, status, chip_serial_number, dwh_status, valid_until, card_holder_id, file_perso_history_id, feedback_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
FINE: bind => [9030002005889908, ACTIVE, null, false, 2015-12-10, null, 241, null]
FINER: End Batch Statements
I think this is because i set a new parent property (card) to existing children.
I also try to play with reversing the parent - child relationship (cardholder->card instead of card->cardholder). Batch insert is correct after i reverse the relationship in entity and database, but still Eclipselink would query the database (SELECT * from card where cardholder.id = ?), so for 15000 record i got 15000 select statement. Better than above, but still very very slow.
Is there any mistake i made in setting up batch-writing? Thank you very much.
What are all of the relationships in the Card and Cardholder?
You seem to have a cycle between the two classes, so EclipseLink must issue the update to resolve the cycle.
You have a card_holder_id in your Card and a card_number in your CardHolder? Why do you have a foriegn key in both tables to the other? If you fix your cycle, then the inserts can be grouped and allow optimal batching.
Not sure what you are doing to get the select? These are new objects are they note? Or are you updating as well?
Im not really sure about the cause of your problem, but i would suggest doing this :
If i have a oneToMany and manyToOne situation, and it involves lots of collection data, i'll avoid using the collection to add detail[s], since it could trigger populating the collection when it's not necessary, which could be the source of performance problem.
A simple example that will help illustrating what i meant : Consider 2 Entities of Team and Player, A Team has a list of Player (one to many) A Player has a Team (many to one)
Whenever i want to add a new player, i would do :
Team team = getTeamFromDbUsingEntityManager(teamId); Player player = new Player(); ... player.setTeam(team); entityManager.persist(player);
Notice that it doesnt do team.addPlayer(player); which means, you're not 'touching' the collection.
精彩评论