Нужна помощь в улучшении производительности больших наборов данных в Grails - PullRequest
2 голосов
/ 16 сентября 2010

Это решение работает, но производительность ниже ожидаемой.Запрос, возвращающий 200K строк, занимает несколько минут и привязывает ЦП к моему устройству разработки.Выполнение одного и того же * запроса в анализаторе запросов возвращает все результаты в течение <1 минуты. </p>

Class MyController { 

 def index = {...}
 ...
 def csv = {
   ...
   def rs = DomainClass.createCritera().scroll {}

   while(rs.next()){
    response.getOutputStream().print(rs.getString(1)\n)
   }
   ...
 }

DB = сервер SQL Server 2005 на выделенном поле, отдельном от моей машины разработчика.

У меня естьчерез SQL Server Profiler также заметил, что gorm / hibernate использует sp_cursorprepexec и sp_cursorfetch для чтения результатов 128 строк одновременно.Я хотел бы попытаться не использовать курсор, если это вариант.

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

оригинальный спящий режим выпуск .

Решение: Обойти спящий режим.От 10 минут до 15 секунд.

Class MyController { 
 def DataSource

 def index = {...}
 ...
 def csv = {
   ...
   def out = response.getOutoutStream()
   Sql sql = new Sql(dataSource)

   sql.eachRow("select c1, c2 from t1",{
     out.println( it.c1 + "," + it.c2 )
   })
   ...
 }

* same = вырезать и вставлять из SQL Server Profiler, но исключая перенос sp_cursorprepexec sproc.

Ответы [ 5 ]

4 голосов
/ 17 сентября 2010

Просто перейти в Hibernate напрямую, если что-то не поддерживается GORM:

import org.hibernate.ScrollMode

class MyController { 

   def index = {...}

   def csv = {
      DomainClass.withSession { session ->
         def rs = session.createCriteria(DomainClass).scroll(ScrollMode.FORWARD_ONLY)
         while (rs.next()) {
            response.outputStream.print rs.getString(1)
         }
      }
   }
}

Вы можете сделать то же самое для HQL-запроса, используя вместо этого session.createQuery(...).

3 голосов
/ 17 сентября 2010

Hibernate на самом деле не предназначен для пакетной загрузки, но есть некоторые вещи, которые вы можете попробовать (большинство из которых требует от вас отказаться от использования ScrollableResult и просто выполнять регулярные запросы с результатами объекта).

  1. Просто обойдите Hibernate / GORM и перейдите к SQL напрямую для (надеюсь) нескольких мест, где вам это нужно.Да, я знаю, но если хуже становится хуже ...
  2. Вызовите session.setReadOnly () или query.setReadOnly (), чтобы отключить снимки состояния Hibernate
  3. Попробуйте сеанс без сохранения состояния Hibernate.Если все, что вы делаете, это чтение, это может работать нормально.Сеанс без сохранения состояния имеет намного меньшую нагрузку, чем обычный сеанс Hibernate, но вы откажетесь от всего своего кэширования и отслеживания состояния объекта.Вам нужно будет сделать что-то подобное, чтобы использовать это:

    def Session statelessSession = sessionFactory.openStatelessSession()
    statelessSession.beginTransaction()
    
    // ...
    
    statelessSession.getTransaction().commit()
    statelessSession.close()
    
  4. Сбросить сеанс партиями по 25 или 50. По сути, так как выперебирая элементы, которые вы вернули, выполните session.flush ().Если вы этого не сделаете, сеанс будет расти до тех пор, пока у вас не закончится память и сборщик мусора не начнет сходить с ума.Это может быть причиной того, что ваш процессор привязан.

Удачи!

0 голосов
/ 29 апреля 2016

Используйте пакетную вставку, и это быстрее, чем метод очистки gorm и метод сеанса без сохранения состояния. Следующий пример поможет вам реализовать пакетную вставку в Grails.

    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 "Total record insert Counter =>"+counter+" Time =>"+TimeCategory.minus(endTime,startTime)
        }
    }

    tx.commit();
    session.close();
0 голосов
/ 27 июля 2015

Несколько вещей, на которые стоит обратить внимание:

0 голосов
/ 03 апреля 2012

Другой способ использовать критерии Grails и ScrollMode:

Criteria criteria = Domain.createCriteria().buildCriteria{
    eq('id', id)
}
ScrollableResults results = criteria.scroll(ScrollMode.FORWARD_ONLY)

int i = 0
while (results.next()){
    ...
    if (++i % 50 == 0){
        Domain.withSession { Session session ->
            session.flush()
            session.clear()
        }
    }
}
...