Grails批量插入/更新优化
我正在从csv文件导入大量数据(文件大小超过100MB) 我使用的代码如下所示:Grails批量插入/更新优化,grails,optimization,bulkinsert,Grails,Optimization,Bulkinsert,我正在从csv文件导入大量数据(文件大小超过100MB) 我使用的代码如下所示: def errorLignes = [] def index = 1 csvFile.toCsvReader(['charset':'UTF-8']).eachLine { tokens -> if (index % 100 == 0) cleanUpGorm() index++ def order = Orders.findByRef
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了这篇博客文章非常有用: 您已经在清理GORM,但请尝试每100个条目清理一次:
def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP
propertyInstanceMap.get().clear()
创建数据库索引也可能有帮助,可以使用
default storage engine=innodb
而不是MyISAM
我还正在编写一些服务,这些服务将完成超大数据集的加载(每个文件多达1700万行)。我最初尝试了您使用的cleanUpGorm
方法,但发现,虽然它确实改善了情况,但加载速度仍然很慢。以下是我为加快速度所做的:
应用程序
,然后在/monitoring
打开了一个浏览器。然后,我可以看到哪些例程需要时间来执行,以及性能最差的查询实际上是什么。。。其中…
子句。您需要确保在where子句中使用的每个项都有一个索引,用于您希望更快地进行的每个查询,否则,数据集越大,该方法将变得相当慢。这包括在注入每个域类的id
和version
列上放置索引grailspringbatch
插件来完成这项工作,并快速实现。它速度极快,可配置性很强,而且您不必费心清理会话我在插入记录时使用了批插入,这比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();
那么,你测量了什么是缓慢的部分?测量您的块,看看特定块是否有异常(可能缺少索引)。否则,请考虑忽略gorm并使用groovy sql。没有银弹。配置/测量和优化。对于这种情况,我建议您依靠自己的数据库机制执行大容量插入。搜索大容量插入+您的数据库(MySQL、Oracle、SQL Server等)。这是将数据导入数据库的最快方式。它的速度通常要快几个数量级。我们发现每一百行清洗一次gorm是不可靠的。它将坚如磐石地工作一周,然后没有任何影响。对数据库的批量更新对我们来说是最大的帮助