【问题标题】:Need help improving the performance of large datasets in grails需要帮助提高 Grails 中大型数据集的性能
【发布时间】:2011-04-13 09:46:24
【问题描述】:

此解决方案有效,但性能低于预期。返回 200K 行的查询需要几分钟时间,并且会在我的开发盒上占用 CPU。在查询分析器中运行相同的*查询会在

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 行结果。如果可以的话,我想尝试不使用光标。

不确定是否是问题,但只能提供帮助。在休眠中,可以将滚动设置为仅向前,但我无法为 grails 找到类似的设置。

原始休眠issue

解决方案:绕过休眠。从 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。

【问题讨论】:

标签: grails grails-orm large-data


【解决方案1】:

如果 GORM 不支持某些内容,直接下拉到 Hibernate 很简单:

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)
         }
      }
   }
}

您可以改为使用 session.createQuery(...) 对 HQL 查询执行相同的操作。

【讨论】:

    【解决方案2】:

    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()。如果你不这样做,会话将继续增长,直到你用完内存并且你的垃圾收集器开始发疯。这可能就是您的处理器被盯住的原因。

    祝你好运!

    【讨论】:

      【解决方案3】:

      另一种使用 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()
              }
          }
      }
      

      【讨论】:

        【解决方案4】:

        有几点值得注意:

        【讨论】:

          【解决方案5】:

          使用批量插入,它比gorm cleanup方法和无状态会话方法更快。下面的例子帮助你如何在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();
          

          【讨论】:

            猜你喜欢
            • 2020-09-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-01-29
            相关资源
            最近更新 更多