将性能javax.persistence事务提高到远程数据库

时间:2013-03-30 19:50:31

标签: mysql database performance jpa eclipselink

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

当我将persistence.xml更改为使用远程数据库(检查RDS和个人的异地数据库)时,持久化/提交一批实例的最短时间约为20秒,这也是因为每5秒(平均)需要一次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日志时看起来好像仍然自己发送了bind,甚至虽然可以启用批量写入。

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

3 个答案:

答案 0 :(得分:2)

更改排序以使用表格排序,允许预先分配序列号。你现在有什么强制每个插入到自己的语句中,以便可以在之后找到id - 这可以防止批处理。如果与批量大小相匹配,表和其他允许预分配的策略将提供更好的性能。 http://java-persistence-performance.blogspot.se/2011/06/how-to-improve-jpa-performance-by-1825.html

中的优化#6

答案 1 :(得分:1)

尝试启用JDBC batch writing。我不确定它会有什么不同,但值得尝试。

答案 2 :(得分:1)

对于MySQL中的批量写入,MySQL JDBC驱动程序不会批处理语句,除非您在连接URL中设置了以下属性,

?rewriteBatchedStatements=true

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