-1

在针对我的本地数据库开发应用程序时,事务速度没有问题,尽管每秒执行多个事务时 CPU 使用率始终保持在 30% 左右,并且在进行分析时,大部分时间都花在处理事务的 javax 方法中每笔交易平均需要 2.6 秒。因此,我使用 ArrayList 作为缓冲区,仅在缓冲区大小超过 300 个实例时才发送事务,这显着降低了 CPU 使用率。

当我将 persistence.xml 更改为使用远程数据库时(同时检查了 RDS 和个人的异地数据库),持久化/提交一批实例的最短时间约为 20 秒,这太高了,因为每 5 秒(平均)需要一次 300 个实例的事务。

我试图将 EntityManager 的刷新模式更改为,FlushModeType.COMMIT但它并没有明显改变性能。由于某些(对我而言)未知的原因,在发送之前增加缓冲区的大小会导致 javax.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]
... 

进步

By changing to @GeneratedValue(strategy = GenerationType.TABLE) and allocationSize=300 I've managed to reduce the number of requests by 50%, although it looks as if bind are still sent on their own when checking the EclipseLink log, even though batch writing is supposedly enabled.

[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 => [..., ..., ..., ..., ...]
4

3 回答 3

2

Change your sequencing to use table sequencing allowing sequence numbers to be preallocated. What you have now forces each insert into its own statement so that the id can be found right after - which prevents batching. Table and other strategies allowing preallocation will give better performance if matched up with the size of your batches. Optimization #6 in http://java-persistence-performance.blogspot.se/2011/06/how-to-improve-jpa-performance-by-1825.html

于 2013-04-01T01:13:11.160 回答
1

Try enabling JDBC batch writing. I'm not sure what difference it would make, but it may be worth trying.

于 2013-03-30T20:42:49.630 回答
1

For batch writing in MySQL the MySQL JDBC driver does not batch statement unless you have set the following property in your conneciton URL,

?rewriteBatchedStatements=true

i.e.

jdbc:mysql://localhost:3306/db1?rewriteBatchedStatements=true
于 2013-04-01T13:58:05.723 回答