简体   繁体   English

滚动时使用Session.save()时,ScrollableResultSet.next()逐渐变慢

[英]ScrollableResultSet.next() gradually slows down when using Session.save() whilst scrolling

I am using a ScrollableResults object to scroll through about 500,000 to 1,000,000 rows from a table. 我正在使用ScrollableResults对象从表中滚动浏览大约500,000至1,000,000行。 Whilst scrolling I create a different entity using the resulting entity from each iteration and use session.save() to persist this object. 在滚动的同时,我使用每次迭代产生的实体创建一个不同的实体,并使用session.save()持久化此对象。 Below is example code, where the real code is more complex but essentially doing the same thing. 下面是示例代码,其中的实际代码更复杂,但实际上执行相同的操作。

Session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
ScrollableResults results = session.createQuery("from Foo_Table f join f.bars b")
    .scroll(ScrollMode.FORWARD_ONLY);
int i = 0;
while(results.next())
{
    Foo foo = (Foo) results.get(0);
    Bar bar = new Baz(foo);
    bar.setFoo(foo);

    session.save(bar)

    if(i % 50 == 0)
    {
        session.flush();
        session.clear();
    }
}

tx.commit();
session.close();

The important entities: 重要实体:

@Entity
@Table(name = "FOO_TABLE")
public class Foo_Entity implements Serializable {
    @Id    
    @Column(name = "Foo_ID", nullable=false)
    private String id;

    @OneToMany(fetch = FetchType.EAGER, //FetchType.LAZY fixes the slow down 
               mappedBy = "fooParent", cascade = CascadeType.ALL)
    private Set<Bar> bar_entities = new HashSet<>(0);
}

@Entity
@Table(name = "BAR_TABLE")
public class Bar_Entity implements Serializable {
    @Id
    @GeneratedValue
    @Column(name="Id")
    private Long id;

    @ManyToOne
    @JoinColumn(name="foo_pk")
    private Foo fooParent;

    // setFoo, getFoo...

}

When I time this transaction, the running time starts at about 100ms per 500 iterations but gradually rises to a few seconds per 500 iterations after about 20,000 iterations. 当我为该事务计时时,运行时间开始于每500次迭代大约100毫秒,但在大约20,000次迭代之后逐渐增加到每500次迭代几秒。 As a result the transaction has extremely poor performance. 结果,该事务的性能极差。 The only line of code which is taking any time is the results.next() , which gradually takes longer and longer to execute. 唯一需要花费时间的代码行是results.next() ,它逐渐花费越来越长的时间来执行。

The issue is resolved if I change the fetch type for Bar entities in Foo from eager to lazy. 如果我将Foo中Bar实体的获取类型从“渴望”更改为“懒惰”,则此问题已解决。 I don't understand why using an eager fetch type for a set that is not yet filled causes problem with scrolling through entities that contain the relationship. 我不明白为什么对尚未填充的集合使用渴望的获取类型会导致滚动浏览包含关系的实体时出现问题。 The set is indeed filled during scrolling on session.flush(), but in my scenario the set is typically filled with only one to two elements, which is why I would prefer to have this fetch type as eager. 确实在滚动session.flush()时填充了该集合,但是在我的场景中,该集合通常仅填充一到两个元素,这就是为什么我更希望将这种获取类型设置为渴望的原因。

Does anyone know why this slow down happens for this particular scenario? 有谁知道为什么在这种情况下会出现这种减速?

Note that this question was first posted before I realised that changing the fetch type solved the problem, so the question has now shifted from "How can I fix this" to "why is this a problem?" 请注意,此问题是在我意识到更改获取类型可以解决该问题之前首先发布的,因此该问题现在已从“我如何解决此问题”转移到“这是为什么这个问题?”。

BAR_TABLE.foo_pk列上的索引丢失会因渴望获取而减慢速度,因为将执行全表扫描以加载与每个FOO实体关联的BAR实体,

First, If fetch is eager which means lazy loading is false then Bar_Entity's are loaded whenever Foo_Entity's are loaded. 首先,如果急于获取,这意味着延迟加载为false,则每当加载Foo_Entity时都会加载Bar_Entity。 So either remove join in query or make fetch to lazy. 因此,要么删除查询中的联接,要么使获取变得懒惰。 Having both is redundant. 两者都是多余的。

Second, Regarding slow down. 第二,关于减速。 Since you are opening a stateful session. 由于您正在打开有状态会话。 every object is cached in memory due to hibernate first level cache. 由于休眠的一级缓存,每个对象都缓存在内存中。 In this scenario Slow down has nothing to do with lazy or eager or join. 在这种情况下,慢下来与懒惰,渴望或加入无关。 Slow down is due to number of objects being holded in cache(Memory) by hibernate. 变慢的原因是休眠状态下保存在缓存(内存)中的对象数量。 Try using stateless Session. 尝试使用无状态会话。 Then slow down should go away. 然后减速应该消失。 Please refer to below URL 请参考以下URL

https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/batch.html https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/batch.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM