我从csv文件导入大量数据(文件大小超过100MB)
我正在使用的代码如下所示:
def errorLignes = []
def index = 1
csvFile.toCsvReader(['charset':'UTF-8']).eachLine { tokens ->
if (index % 100 == 0) cleanUpGorm()
index++
def order = Orders.findByReferenceAndOrganization(tokens[0],organization)
if (!order) {
order = new Orders()
}
if (tokens[1]){
def user = User.findByReferenceAndOrganization(tokens[1],organization)
if (user){
order.user = user
}else{
errorLignes.add(tokens)
}
}
if (tokens[2]){
def customer = Customer.findByCustomCodeAndOrganization(tokens[2],organization)
if (customer){
order.customer = customer
}else{
errorLignes.add(tokens)
}
}
if (tokens[3]){
order.orderType = Integer.parseInt(tokens[3])
}
// etc.....................
order.save()
}
我正在使用cleanUpGorm方法在每100个条目后清理会话
def cleanUpGorm() {
println "clean up gorm"
def session = sessionFactory.currentSession
session.flush()
session.clear()
propertyInstanceMap.get().clear()
}
我还关闭了二级缓存
hibernate {
cache.use_second_level_cache = false
cache.use_query_cache = false
cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
}
项目的grails版本是2.0.4,而我使用mysql的数据库
对于每个条目,我正在进行3次调用
最后我正在保存订单实例
导入过程太慢,我想知道如何加快和优化此代码。
我发现可搜索的插件也让它变慢了。 所以,为了解决这个问题,我使用了命令:
searchableService.stopMirroring()
但它仍然不够快,我终于改变代码使用groovy sql而不是
答案 0 :(得分:1)
这发现此博客条目非常有用: http://naleid.com/blog/2009/10/01/batch-import-performance-with-grails-and-mysql/
您已经在清理GORM,但请尝试清理每100个条目:
def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP
propertyInstanceMap.get().clear()
创建数据库索引可能也有帮助,并使用default-storage-engine=innodb
代替MyISAM
。
答案 1 :(得分:1)
我还在编写许多服务,这些服务将完成大量数据集的加载(每个文件最多可达1700万行的多个文件)。我最初尝试了你使用的cleanUpGorm
方法,但发现虽然它确实改进了东西,但加载速度仍然很慢。这就是我做得更快的事情:
调查导致应用程序实际变慢的原因。我安装了Grails Melody插件,然后执行了run-app
,然后在/monitoring
打开了一个浏览器。然后,我可以看到哪些例程需要花时间执行,以及执行情况最差的查询实际上是什么。
许多Grails GORM方法都映射到SQL ... where ...
子句。您需要确保为每个要更快的查询的where子句中使用的每个项目都有一个索引,否则数据集越大,该方法将变得相当慢。这包括将索引放在注入每个域类的id
和version
列中。
确保为所有hasMany和belongsTo关系设置了索引。
如果性能仍然太慢,请使用Spring Batch。即使您以前从未使用它,也应该花时间设置CSV文件的批处理解析以解析为Grails域对象。我建议您使用grails-spring-batch
插件执行此操作,并使用use the examples here快速完成工作实施。它速度非常快,非常易于配置,您不必为清理会话而烦恼。
答案 2 :(得分:1)
我在插入记录时使用了批量插入,这比gorm清理方法快得多。下面的例子描述了如何实现它。
Date startTime = new Date()
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
(1..50000).each {counter ->
Person person = new Person()
person.firstName = "abc"
person.middleName = "abc"
person.lastName = "abc"
person.address = "abc"
person.favouriteGame = "abc"
person.favouriteActor = "abc"
session.save(person)
if(counter.mod(100)==0) {
session.flush();
session.clear();
}
if(counter.mod(10000)==0) {
Date endTime =new Date()
println "Record inserted Counter =>"+counter+" Time =>"+TimeCategory.minus(endTime,startTime)
}
}
tx.commit();
session.close();