Оптимизация пакетного чтения Grails - PullRequest
0 голосов
/ 09 января 2012

Мне нужно регулярно переиндексировать все мои экземпляры домена из действующей устаревшей базы данных, используя пользовательскую реализацию ElasticSearch .

Все предложения, которые я нашел до сих пор, касались оптимизации пакетных операций записи .

Во многих таблицах есть сотни тысяч, если не миллионы записей ипростое решение domain.list().each { ... } позволяет сразу загрузить весь набор данных в память.

Использование Hibernate ScrollableResults кажется хорошим решением, но оно работает на уровне RecordSet и не воссоздает фактические доменные объекты.Я мог бы использовать поле id для read() экземпляра, но это кажется неэффективным.

Плагин Searchable , кажется, выполняет эффективную операцию reindex.

Какие еще варианты или оптимизации существуют для успешного чтения экземпляров домена в пакетном режиме?


ОБНОВЛЕНИЕ

Я недавно наткнулся на четырехлетнего ребенка.поток в списке рассылки Grails с ответом из @ BurtBeckwith , в котором говорится, что использование ScrollableResultSet было бы неэффективным.Он рекомендует пролистывать записи с использованием стандартных методов GORM и очищать сеанс пакетами.

Ответы [ 2 ]

1 голос
/ 09 января 2012

1) Использование традиционного Java for loop сэкономит вам немного времени.

2) Блок данных может помочь. Вы можете использовать max: и offset: чтобы получить куски 100 или 1000, так что вы всегда имеете дело с меньшим набором: http://grails.org/doc/latest/ref/Domain%20Classes/list.html Однако могут возникнуть проблемы с этим, если вы изменяете объекты в этой таблице или если новые данные добавляются в середине рабочего процесса. (Я оставлю это для вас, чтобы проверить:)

3) Использование SQL или HSQL для захвата всех идентификаторов, а затем использование Grails .load () также может помочь. http://grails.org/doc/latest/ref/Domain%20Classes/load.html

4) Я пытался реализовать несколько больших пакетных заданий, используя Grails / Hibernate, и обнаружил, что это просто не очень хорошо работает. Я бы посоветовал вам работать напрямую с базой данных, используя SQL, если это вообще возможно. Это, безусловно, будет самым быстрым.

0 голосов
/ 09 сентября 2015

Вы можете использовать служебный класс, аналогичный приведенному ниже, для записей ручной загрузки в пакетах

 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
}

Вы можете использовать paginator с gorm или прямым sql или чем-либо еще.

...