ローカル データベースに対してアプリケーションを開発するとき、トランザクションの速度に問題はありませんでしたが、1 秒あたり複数のトランザクションを実行している場合、CPU 使用率は常に約 30% であり、プロファイリングの場合、トランザクションを処理する javax メソッドにほとんどの時間が費やされていました。トランザクションあたり平均 2.6 秒です。したがって、ArrayList をバッファーとして使用し、バッファーのサイズが 300 インスタンスを超えた場合にのみトランザクションを送信することで、CPU 使用率を大幅に低下させました。
代わりにリモート データベースを使用するように persistence.xml を変更している場合 (RDS と個人用のオフサイト データベースの両方をチェック)、インスタンスのバッチを永続化/コミットするための最小時間は約 20 秒であり、 5 秒に 1 回 (平均) 300 インスタンスのトランザクションが必要です。
EntityManager の flushmode を に変更しようとしましたFlushModeType.COMMIT
が、パフォーマンスが著しく変わることはありませんでした。送信前にバッファのサイズを大きくすると、(私にとっては) 不明な理由で javax.persistence ライブラリでスタック オーバーフローが発生します。
persistence.xml
<persistence-unit name="PU-data" transaction-type="RESOURCE_LOCAL">
<mapping-file>META-INF/orm.xml</mapping-file>
... // class, shared-cache-mode=none, validation-mode=none ...
<properties>
... // Authentication ...
<!-- Optimization attempts -->
<property name="eclipselink.jdbc.bind-parameters" value="true" />
<property name="eclipselink.jdbc.batch-writing" value="JDBC"/>
<property name="eclipselink.jdbc.batch-writing.size" value="300" />
<property name="eclipselink.jdbc.cache-statements" value="true" />
<property name="eclipselink.cache.shared.default" value="false" />
<property name="eclipselink.persistence-context.close-on-commit" value="true" />
<property name="eclipselink.persistence-context.flush-mode" value="commit" />
<property name="eclipselink.persistence-context.persist-on-commit" value="false" />
</properties>
</persistence-unit>
トランザクションを処理するファサード
MouseFacade.bufferSemaphore.acquireUninterruptibly(1);
if (MouseFacade.buffer.size() >= 300) {
EntityManager entityManager = EMF.getEntityManager();
try {
entityManager.getTransaction().begin();
for (Mouse mouse : MouseFacade.buffer) {
entityManager.persist(mouse);
}
entityManager.getTransaction().commit();
} finally {
if (entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
entityManager.close();
MouseFacade.buffer.clear();
}
}
MouseFacade.bufferSemaphore.release(1);
ORM マッピング
<entity-mappings version="2.1" xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<entity class="se.my.package.Mouse">
<table-generator name="ORD_SEQ" allocation-size="300"/>
</entity>
</entity-mappings>
アップデート
JPA パフォーマンスを1,825 % 向上させる方法( http://java-persistence-performance.blogspot.se/2011/06/how-to-improve-jpa-performance- by-1825.html ) ですが、バッチ書き込みと MySQL に関する重要なポイントを見逃しているのではないかと思うほどの違いはありません。関係に依存しないようにエンティティを書き直し、書き込みの問題だけに集中するために、アプリケーション全体の読み取り操作を 1 に最小化しました。
EclipseLink のログを見ると、バッチ書き込みがまったく使用されていないように見えますが、代わりにインスタンスごとに 2 つのログ全体が書き込まれており、ほぼ正しいと思われます (300 インスタンス * 2 接続 * 24 レイテンシ = 14.4 秒)。
[EL Fine]: sql: 2013-03-31 01:35:29.249--ClientSession(1213059092)--Connection(662811604)--Thread(Thread[pool-1-thread-1,5,main])--SELECT LAST_INSERT_ID()
[EL Fine]: sql: 2013-03-31 01:35:29.274--ClientSession(1213059092)--Connection(662811604)--Thread(Thread[pool-1-thread-1,5,main])--INSERT INTO mouse (event, posX, posY, created, uid) VALUES (?, ?, ?, ?, ?)
bind => [12, 241, 250, 1364690113727, 1]
[EL Fine]: sql: 2013-03-31 01:35:29.298--ClientSession(1213059092)--Connection(662811604)--Thread(Thread[pool-1-thread-1,5,main])--SELECT LAST_INSERT_ID()
[EL Fine]: sql: 2013-03-31 01:35:29.323--ClientSession(1213059092)--Connection(662811604)--Thread(Thread[pool-1-thread-1,5,main])--INSERT INTO mouse (event, posX, posY, created, uid) VALUES (?, ?, ?, ?, ?)
bind => [12, 233, 296, 1364690113443, 1]
...
進捗
に変更すること@GeneratedValue(strategy = GenerationType.TABLE)
でallocationSize=300
、リクエストの数を 50% 減らすことができましたが、バッチ書き込みが有効になっているはずですが、EclipseLink ログを確認すると、バインドがまだ独自に送信されているように見えます。
[EL Fine]: sql: 2013-03-31 01:35:29.323--ClientSession(1213059092)--Connection(662811604)--Thread(Thread[pool-1-thread-1,5,main])--INSERT INTO mouse (event, posX, posY, created, uid) VALUES (?, ?, ?, ?, ?)
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]