2008-12-23 74 views
0

我正在使用Java和Hibernate的JPA实现构建数据库Web应用程序。应用程序跟踪对象。它还需要从传统源批量导入对象。批量导入大型数据集时的数据库性能建议

例如,假设我们正在跟踪的人。该数据库具有名为个人和地址的表。有相应的JPA实体和DAO类。

在JPA层的顶部是负责各种操作的服务层。一项操作是从外部遗留源(例如电话簿中的人员)导入潜在的大量数据。对于每个人,都必须检查它是否已经存在于数据库中。然后必须根据需要创建或更新该人员。每个人都有一个地址,因此必须进行适当的交叉引用和地址创建。

我的问题是,这种操作可以为大型数据集缓慢。我目前的算法是:

for (Person person: allPersons) 
{ 
    check if person exists in database 
    check if address exists in database 
    create or update person and address as necessary 
} 

您会建议如何改善性能?

把我的头,我能想到的顶部:

  1. 更改导入逻辑检索和存储数据使用的查询数据库。例如,不是检查for循环中是否存在person,而是在一个查询中将所有person key提交给数据库,每个进程检索内存中的person。
  2. 在DAO类中添加我自己的缓存。
  3. 使用外部缓存解决方案(如memcached)。

我能#1通过重组以减少查询始终走。缺点是我的服务层现在非常了解DAO层。它的实现现在由较低的数据库层决定。还有其他问题,如使用太多的内存。这种从数据库中获取内存然后在内存中进行处理似乎非常有用,并且不符合JPA等现成的解决方案。我很好奇别人在这种情况下会做什么。

编辑:缓存将不利于为每个人所内环路查询是不同的。

回答

1

我找到了两种解决方案。一个是一次处理一个块。每个块关闭后重新启动会话。我曾尝试在会话中使用清除清除方法,但有时候它的功能正如您所期望的那样。开始和停止批次之间的交易似乎是最好的。

如果性能是一个主要关注点,那么您只需要在JDBC中分解并执行它。 Hibernate增加了批量处理大量数据集的开销,其中内存和性能非常重要。

+1

其中一个原因是冲洗不总是释放内存的是,hibernate将存储对事务中保存的所有对象的引用,以便它可以在事务结束时调用对象上的提交挂钩(如果有的话)。 – davidsheldon 2009-01-04 10:04:52

0

你的做法是将导致对数据库中太多的个人查询;看起来像4n + 1。如果可能的话,我会写一个查询(可能是原始SQL),一次检查是否存在person + address。

您可能想使用StatelessSession而不是标准的Hibernate Session。由于它没有第一级缓存,因此应该保持较低的内存要求。

http://www.hibernate.org/hib_docs/reference/en/html/batch-statelesssession.html

如果不为你工作,那么你会想在休眠看看批处理选项:

http://www.hibernate.org/hib_docs/reference/en/html/batch.html