1

我正在使用一个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 次迭代大约 100 毫秒开始,但在大约 20,000 次迭代后逐渐上升到每 500 次迭代几秒。因此,该事务的性能极差。唯一需要花费时间的代码行是results.next(),它的执行时间会越来越长。

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

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

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

4

2 回答 2

0

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

于 2015-04-18T21:00:54.363 回答
0

首先,如果 fetch 是急切的,这意味着延迟加载是错误的,那么每当加载 Foo_Entity 时都会加载 Bar_Entity。因此,要么删除查询中的联接,要么使 fetch 变得懒惰。两者兼有是多余的。

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

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

于 2015-07-02T05:37:35.907 回答