Grails批量插入/更新优化

时间:2015-03-05 10:09:27

标签: 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.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而不是

3 个答案:

答案 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方法,但发现虽然它确实改进了东西,但加载速度仍然很慢。这就是我做得更快的事情:

  1. 调查导致应用程序实际变慢的原因。我安装了Grails Melody插件,然后执行了run-app,然后在/monitoring打开了一个浏览器。然后,我可以看到哪些例程需要花时间执行,以及执行情况最差的查询实际上是什么。

  2. 许多Grails GORM方法都映射到SQL ... where ...子句。您需要确保为每个要更快的查询的where子句中使用的每个项目都有一个索引,否则数据集越大,该方法将变得相当慢。这包括将索引放在注入每个域类的idversion列中。

  3. 确保为所有hasMany和belongsTo关系设置了索引。

  4. 如果性能仍然太慢,请使用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();