2

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

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 找到类似的设置。

原来的休眠问题

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

4

5 回答 5

4

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

您可以对 HQL 查询执行相同的操作session.createQuery(...)

于 2010-09-16T21:37:46.950 回答
3

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

祝你好运!

于 2010-09-17T01:44:05.667 回答
0

使用 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()
        }
    }
}
于 2012-04-03T15:44:52.767 回答
0

有几点值得注意:

于 2015-07-27T20:12:47.273 回答
0

使用批量插入,它比 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();
于 2016-04-29T10:00:44.443 回答