同事, 对于以下情况,我将提供很多建议。
我们的项目基于Spring Data JPA,因此我的存储库实现基于SimpleJpaRepository。
要讨论的方法在标有@Transactional的服务中。
据我了解,Spring创建了实体管理器,刷新数据并在不介入流程的情况下提交事务。
该项目读取并解析两次外部json。 第一次运行-给出json以填充表格。 第二次运行-大小相同的json,这里有一些新值,并提供了更新表的信息。
表在用于更新的搜索字段上具有UNIQUE索引。 数据对象是基本的,没有@OneToMany关系。
问题:第二次运行(获取更新)时,速度急剧下降。 比方说,每条新处理的1000条记录的处理速度都比上一条慢。 结果更新运行时间比创建运行时间长约10倍
对于创建运行,我使用了简单的存储库方法#save,它在#persist和#merge之间进行选择。 显然,在我的案例中,它选择了#persist。在所有可能性下,Spring都会刷新数据并提交事务。 我打开了“ generate_statistics”选项,并按预期进行了1次刷新和创建的实体数
我如何加快更新速度:
首先,对于更新运行,我将要处理的数据切片为集合(实际上是在每个切片处理端清除的数据),并先调用#saveAll然后调用#flush(实际上是em#flush) 这种方法基于这些讨论 How to improve performance of Updating data using JPA和 HIbernate commit() and flush()
A,时间花费几乎是相同的, JDBC操作的数量是相同的 冲洗次数符合预期(例如,“包装”大小为1000时冲洗29次,“包装”大小为10时冲洗2900次)。 奇怪的是,这次的实体数量与要更新的表中的记录数量不同
日志看起来像
76545093741 nanoseconds spent executing 2860 flushes (flushing a total of 40912292 entities and 0 collections);
756096912142 nanoseconds spent executing 28592 partial-flushes (flushing a total of 408736936 entities and 408736936 collections)
40912292实体? 408736936实体和集合? 但为什么? 我还想知道这些部分冲洗是什么-引起什么?为什么他们的人数浮动?
我想知道为什么手动定期冲洗没有帮助。
第二,在上一次尝试中,我使用了带有IDENTITY策略自动生成的主键的数据对象。
这次我决定尝试批处理。 我将PK生成策略更改为SEQUENCE,并添加了一堆Spring属性以进行批处理:
jpa:
properties:
hibernate:
jdbc:
batch_size: 50
batch_versioned_data: true
order_inserts: true
order_updates: true
在这种情况下,我收到了什么日志:
250614501 nanoseconds spent preparing 28594 JDBC statements;
8759177291 nanoseconds spent executing 28592 JDBC statements;
3398281 nanoseconds spent executing 2 JDBC batches;
0 nanoseconds spent performing 0 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
7925542816 nanoseconds spent executing 286 flushes (flushing a total of 4104092 entities and 0 collections);
794086157441 nanoseconds spent executing 28592 partial-flushes (flushing a total of 408736936 entities and 408736936 collections)
所以只有2批...几乎没有速度
显然smth是错误的,可能配置错误。 我可以以某种方式解决它吗? 有什么方法可以提高更新速度?
在事务完成后的创建运行中,我认为实体已脱离并需要合并(它们在此处声明:Does JPA's commit() method make entity detached?) 我什至重启了码头。 我的更新代码所做的唯一一件事就是在更新运行期间设置了一个新值。 无需调用存储库方法saveAndFlash(即entitymanager.merge),就可以将新值神奇地传输到数据库:) las,虽然处理速度没有提高...
答案 0 :(得分:0)
由于没有人提出任何解决方案,所以我告诉我最终有什么帮助
我将以下内容注入了服务类:
@PersistenceContext
private EntityManager entityManager;
并称为
entityManager.clear();
每1000条记录后