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 プロファイラーからカット アンド ペーストしますが、ラップする 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 が必要な (できれば) 少数の場所で直接 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 のバッチでセッションをフラッシュします。そうしないと、メモリが不足し、ガベージ コレクターが狂い始めるまで、セッションは成長し続けます。これが、プロセッサが固定されている理由である可能性があります。

幸運を!

于 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

バッチ挿入を使用すると、ゴーム クリーンアップ メソッドやステートレス セッション メソッドよりも高速です。以下の例は、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 に答える