当前位置: 首页 > 知识库问答 >
问题:

Spring Boot JPARepository存储性能()

程祺
2023-03-14

我的spring boot应用程序在插入数据时性能非常慢。

我正在从一个数据库中提取大量数据,并将数据插入另一个数据库。

以下是我的实体。

@Entity
@Table(name = "element")
public class VXMLElementHistorical {

@Id
@Column(name = "elementid")   
private long elementid;

@Column(name = "elementname")
private String elementname; 

Getter/Setter methods...    

我已经配置了一个JPA存储库

public interface ElementRepository extends JpaRepository<Element, Long> {

}

并使用我的对象调用Save()方法

@Transactional 
public void processData(List<sElement> hostElements) 
throws DataAccessException { 

List<Element> elements = new ArrayList<Element>();    

for (int i = 0; i < hostElements.size(); i++) {
        Element element = new Element();
        element.setElementid(hostElements.get(i).getElementid());
        element.setElementname(hostElements.get(i).getElementname());
        elements.add(element);
    }

   try{
   elementRepository.save(elements);{
   //catch etc...

}

目前的情况是,对于每个项目,执行插入操作需要6到12秒的时间。我打开了hibernate跟踪日志记录和统计功能,当我调用save函数时,hibernate执行两个查询,一个选择和一个插入。select查询占用了99%的总时间。

我直接在数据库上运行了select查询,结果以纳秒为单位返回。这让我相信这不是索引问题,但我不是DBA。

我已经在我的开发环境中创建了一个负载测试,在负载大小相似的情况下,整个过程的时间没有prod环境中的时间长。

有什么建议吗?

共有3个答案

寿子轩
2023-03-14

由于加载实体似乎是一个瓶颈,而且您真的只想进行插入,即您知道数据库中不存在实体,因此您可能不应该使用Spring Data JPA的标准save方法。

原因是它执行合并,触发Hibernate加载数据库中可能已经存在的实体。

相反,向存储库中添加一个自html" target="_blank">定义方法,该方法在实体管理器上执行持久化。由于要预先设置Id,请确保您有一个version属性,以便Hibernate可以确定这确实是一个新实体。

这将使选择消失。

其他答案中给出的其他建议值得作为第二步考虑:

  • 启用批处理。
  • 试验中间冲洗和清除会话。
  • 一次保存一个实例而不将它们收集到集合中,因为调用合并持久化实际上不会触发对数据库的写入,而只有刷新会(这是一个简化,但它应该适用于此上下文)
颜啸
2023-03-14

正如@M. Deina在评论中所说,您可以通过在如下所示的一定数量的插入后调用flush()clear()来改进。

int i = 0;
for(Element element: elements) {
    dao.save(element);
    if(++i % 20 == 0) {
        dao.flushAndClear();
    }

}
盖向荣
2023-03-14

保存单个元素,而不是创建元素列表并保存这些元素。每隔一段时间,然后进行刷新清除,以防止脏检查成为瓶颈。

@PersistenceContext
private EntityManager entityManager;

@Transactional 
public void processData(List<sElement> hostElements) 
throws DataAccessException {     

for (int i = 0; i < hostElements.size(); i++) {
        Element element = new Element();
        element.setElementid(hostElements.get(i).getElementid());
        element.setElementname(hostElements.get(i).getElementname());
        elementRepository.save(element)
        if ( (i % 50) == 0) {
            entityManager.flush();
            entityManager.clear();
        }
}
entityManager.flush(); // flush the last records.

你想清除每个x元素(这里是50,但你可能想找到自己的最佳数字。

现在,当您使用Spring Boot时,您可能还想添加一些附加属性。比如配置批处理大小。

spring.jpa.properties.hibernate.jdbc.batch_size=50 

如果您的JDBC驱动程序支持,这将把50条单insert语句转换成1条大批量insert语句。即50个插页到1个插页。

另见https://vladmihalcea.com/how-to-batch-insert-and-update-statements-with-hibernate/

 类似资料:
  • 我必须对Azure表存储进行查询,其中我有以下设置:RowKey、PartitionKey、ThirdColumn RowKey是唯一的,Partitionkey与ThirdColumn相关联,这意味着所有值为“Y”的第三列都将具有分区键“X”。 我必须使用ThirdColumn值获取分区键为X的所有实体。这将不是Performance,因为Y既不是PartitionKey也不是RowKey。 问

  • 我有一个用例,需要以Json格式将调查结果从web应用程序上传到azure blob存储。根据调查问题判断,这些json对象将很小,甚至不会接近1MB。我一直在阅读C#中的azure blob客户端并进行实验。我实现了一个工作单元和存储库设计模式,这意味着每个CRUD操作都会导致与azure存储的连接。我是否应该考虑并行操作或批量调用以降低成本,提高性能和吞吐量?有很多关于并行操作的文章,但他们试

  • 问题内容: 在MySQL中,性能和存储(空间)明智地归零是什么? 例如: TINYINT:1字节TINYINT w / NULL 1字节+以某种方式存储NULL? 问题答案: 这取决于您使用的存储引擎。 在MyISAM格式中,每个行标题都包含一个位域,每个列的每个位都具有一位以对NULL状态进行编码。NULL列仍会占用空间,因此NULL不会减少存储量。参见https://dev.mysql.com

  • 本文向大家介绍阐述ArrayList、Vector、LinkedList的存储性能和特性相关面试题,主要包含被问及阐述ArrayList、Vector、LinkedList的存储性能和特性时的应答技巧和注意事项,需要的朋友参考一下 考察点:ArrayList ArrayList 和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,

  • 我们在应用程序中使用ehcache。请看以下配置: 既然我们已经配置为eternal="true ",那么它会永远创建缓存吗?。磁盘空间有可能用完吗? 对磁盘存储的性能会有什么影响?。肯定比内存缓存慢,但是影响有多大。 如果磁盘中存储了更多缓存,是否会导致执行多个文件操作的IO问题? 请建议生产级应用的最佳实践。假设我们有一个3 GB的堆内存和25000个并发用户访问应用程序。但是,我们的应用程序

  • 问题内容: 关于Spring JPA存储库事务性的1个快速问题。我有未标记为事务性的服务,并调用了Spring JPA存储库方法 它被定义为 问题是它失败,并且“ 没有EntityManager,当前线程没有可用的实际事务- 无法可靠地处理’remove’调用;嵌套异常是javax.persistence.TransactionRequiredException “异常。 好的,我可以通过将服务