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

时间:2015-04-17 15:57:15

标签: java hibernate h2 scrollableresults

我正在使用ScrollableResults对象从表格中滚动大约500,000到1,000,000行。滚动时,我使用每次迭代中生成的实体创建一个不同的实体,并使用session.save()来持久保存此对象。下面是示例代码,其中实际代码更复杂但基本上做同样的事情。

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();

重要实体:

@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...

}

当我计算此交易时,运行时间从每500次迭代约100ms开始,但在大约20,000次迭代后逐渐上升到每500次迭代几秒钟。结果,交易的表现极差。任何时间的唯一代码行是results.next(),执行的时间越来越长。

如果我将Foo中Bar实体的获取类型从急切变为懒惰,则问题得以解决。我不明白为什么对尚未填充的集合使用eager fetch类型会导致滚动浏览包含该关系的实体的问题。在session.flush()上滚动期间确实填充了该集合,但在我的场景中,该集合通常只填充了一到两个元素,这就是为什么我更希望将此获取类型作为渴望。

有谁知道为什么这种特殊情况会发生这种减速?

请注意,在我意识到更改获取类型解决了问题之前,首先发布了这个问题,所以问题现在已经从“我该如何解决这个问题”转变为“为什么这是一个问题?”

2 个答案:

答案 0 :(得分:0)

BAR_TABLE.foo_pk列上缺少索引会因为执行全表扫描而加速与每个FOO实体关联的BAR实体,从而减慢了速度。

答案 1 :(得分:0)

首先,如果fetch是eager,这意味着延迟加载为false,那么只要加载了Foo_Entity,就会加载Bar_Entity。因此,要么删除查询中的连接,要么将其提取为延迟。两者都是多余的。

第二,关于减速。由于您正在开启有状态会话。由于休眠的第一级缓存,每个对象都缓存在内存中。在这种情况下,慢下来与懒惰或渴望或加入无关。减速是由于休眠时缓存(内存)中的对象数量。尝试使用无状态会话。慢下来应该消失。请参阅以下网址

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