Grails批读取优化



我需要使用自定义ElasticSearch实现定期从实时遗留数据库中重新索引我的所有域实例。

到目前为止,我发现的所有建议都是为了优化批处理写入操作。

许多表都有几十万甚至数百万条记录,domain.list().each { ... }的简单解决方案似乎是一次将整个数据集加载到内存中。

使用Hibernate ScrollableResults似乎是一个很好的解决方案,但它可以在RecordSet级别工作,并且不会重新创建实际的域对象。我可以使用id字段来read()实例,但这似乎效率很低。

Searchable插件似乎可以执行有效的reindex操作。

对于成功地批量读取域实例,还有哪些其他选项或优化?


更新

最近,我在Grails邮件列表上偶然发现了一个4年前的线程,@BurtBeckwith的回答表明,使用ScrollableResultSet会效率低下。他建议使用标准GORM方法对记录进行分页,并批量清除会话。

1)使用传统的Java for循环将节省一点开销。

2) 数据块可能会有所帮助。你可以使用max:和offset:来获得100或1000的块,这样你总是在处理一个较小的集合:http://grails.org/doc/latest/ref/Domain%20Classes/list.html但是,如果您正在修改该表中的对象,或者在工作流中间添加了新数据,则可能会出现问题。(我把它留给你测试:)

3) 使用SQL或HSQL获取所有id,然后使用Grails.load()可能也会有所帮助。http://grails.org/doc/latest/ref/Domain%20Classes/load.html

4) 我以前尝试过使用Grails/Hibernate实现一些大批量作业,但发现它确实不太好用。如果可能的话,我建议您使用SQL直接处理数据库。这将是迄今为止最快的。

您可以使用类似于下面的实用程序类手动批量加载中的记录

 class Paginator {
    private static final Logger log = Logger.getLogger("grails.app.Paginator")
    int batchSize
    int totalCount
    public void eachPage(Closure c) {
        SessionFactory sessionFactory = Holders.applicationContext.sessionFactory
        if(totalCount > 0) {
            (0..totalCount -1).step(batchSize) { int offset ->
                log.debug "Executing batch $offset to ${offset + batchSize}"
                try {
                    c.call(batchSize, offset)
                    sessionFactory.currentSession.clear()
                }catch(Exception e) {
                    log.error "Error encountered while executing batch [$offset - ${batchSize + offset}]"
                }
            }
        }
    }
}

然后

Paginator p = new Paginator(batchSize:500, totalCount: Domain.count())
p.eachPage {def max, def offset ->
    List rows = Domain.list(max:max, offset:offset)
    //do some thing with records
}

您可以将分页器与gorm或直接sql或任何东西一起使用。

最新更新