Grails批量插入/更新优化

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

我正在从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了

这篇博客文章非常有用:

您已经在清理GORM,但请尝试每100个条目清理一次:

def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP
propertyInstanceMap.get().clear()

创建数据库索引也可能有帮助,可以使用
default storage engine=innodb
而不是
MyISAM

我还正在编写一些服务,这些服务将完成超大数据集的加载(每个文件多达1700万行)。我最初尝试了您使用的
cleanUpGorm
方法,但发现,虽然它确实改善了情况,但加载速度仍然很慢。以下是我为加快速度所做的:

  • 调查到底是什么导致应用程序运行缓慢。我安装了Grails Melody插件,然后运行了一个
    应用程序
    ,然后在
    /monitoring
    打开了一个浏览器。然后,我可以看到哪些例程需要时间来执行,以及性能最差的查询实际上是什么

  • 许多Grails GORM方法映射到SQL
    。。。其中…
    子句。您需要确保在where子句中使用的每个项都有一个索引,用于您希望更快地进行的每个查询,否则,数据集越大,该方法将变得相当慢。这包括在注入每个域类的
    id
    version
    列上放置索引

  • 确保为所有hasMany和belongsTo关系设置了索引

  • 如果性能仍然太慢,请使用Spring Batch。即使您以前从未使用过它,设置CSV文件的批处理解析以解析为Grails域对象也不会花费任何时间。我建议您使用
    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是不可靠的。它将坚如磐石地工作一周,然后没有任何影响。对数据库的批量更新对我们来说是最大的帮助